涉及知识点:
参考博客:
https://www.cnblogs.com/chen0307/articles/9706977.html
https://blog.csdn.net/emaste_r/article/details/78105713
https://www.cnblogs.com/nul1/p/9172068.html
https://blog.csdn.net/qq_33876553/article/details/79730246
import requests, time
from lxml import etree
from multiprocessing import Queue, Process
from threading import Thread
from urllib.parse import unquote
# 待解决问题
# 文件下载不完整的问题(目前通过比较文件大小判断是否下载完整,可以支持断点续传吗?)
# 写日志记录源文件大小和下载后的文件大小
# closing的作用?
class Code_spider(object):
def __init__(self):
self.url = 'http://****/****/****/'
self.headers = {'User-Agent': 'Mozilla/5.0'}
self.folder = 'C:\\Users\\77962\\Desktop\\****/****/****/'
# 创建消息队列,存放下载链接
self.q = Queue()
def work(self):
self.get_link()
# 开启多线程,5线程用时677s,10线程用时148s
L = []
for i in range(10):
th = Thread(target=self.down_load, args=(i+1,))
# th = Process(target=spider.down_load, args=(i+1,))
th.start()
L.append(th)
for th in L:
th.join()
# 获取页面上的下载链接
def get_link(self):
res = requests.get(self.url,headers=self.headers,auth=('****','****'))
res.encoding = 'utf-8'
html = res.text
parseHtml = etree.HTML(html)
r_list = parseHtml.xpath('//a/@href')[1:]
for link in r_list:
self.q.put(link)
print("本次将下载",self.q.qsize(),"个文件")
# 多线程循环执行的下载函数
def down_load(self,n):
while True:
try:
# 中文不能出现在链接地址中,因此会进行url编码,此处使用unquote进行解码
filename = unquote(self.q.get(block=True,timeout=2))
except:
print('取不到链接了,%s号线程结束工作'%n)
break
link = self.url + filename
# closing:可用于创建上下文管理器(保持下载连接?)
# 设置stream=true时,并不会立即下载(但已获取响应头)
# 会在使用iter_content或iter_lines遍历内容或访问内容属性时才开始下载。
# 需要注意一点:文件没有下载之前,它也需要保持连接。
with closing(requests.get(link,headers=self.headers,stream=True,auth=('tarenacode','code_2014'))) as response:
chunk_size = 2048 # 设置单次请求大小
total_size = int(response.headers['content-length']) # 下载内容的总大小
data_count = 0 # 已下载大小
percent = 0 # 记录下载百分比
with open(self.folder+filename,'wb') as fw:
# 循环下载并写入磁盘
for data in response.iter_content(chunk_size=chunk_size):
last_percent = percent
fw.write(data)
data_count += len(data)
percent = int((data_count/total_size)*100)
# 下载总进度有更新则打印
if percent > last_percent:
print("线程%s正在下载:%s:已完成%s%%(%s/%s)"%(n,filename,percent,data_count,total_size))
# 判断文件是否下载完整
if total_size == data_count:
print("下载完成,文件名:",filename," 总大小",total_size," 下载完成大小",data_count)
else:
self.q.put(link)
if __name__ == '__main__':
start_time = time.time()
spider = Code_spider()
spider.work()
end_time = time.time()
print("爬取总时间:",end_time-start_time)
消息队列
消息队列 : 存储模型,线性的,先进先出原则
原理 : 在内存中建立队列模型,进程通过队列对象将消息存入队列,或从队列取出消息,完成进程间通信
from multiprocessing import Queue
q = Queue(maxsize)
功能: 创建队列对象
参数: 表示队列中最多存放消息个数
返回值: 队列对象
q.put(data,[block,timeout])
功能:向队列存入消息
参数:data 要存入的内容
block 默认队列满时会阻塞,设置为False则为非阻塞
timeout 超时时间
q.get([block,timeout])
功能: 从队列取出消息
参数: block 默认队列为空会阻塞,设置为False则非阻塞
timeout 超时时间
返回值:取出的内容
q.full() 判断队列是否为满
q.empty() 判断队列是否为空
q.qsize() 获取队列中消息个数
q.close() 关闭队列
url编解码
from urllib.parse import unquote, quote
filename1 = "day07%e4%bb%a3%e7%a0%81-1811-springboot-easymall.zip"
filename2 = "1811-springboot-seckill.zip"
# 解码
name1 = unquote(filename1)
name2 = unquote(filename2)
print(name1,"---",name2)
# 编码
url = "Spark内核模块知识点梳理.xlsx"
url1 = quote(url, "utf-8")
print(url1)