python3 提高爬虫采集速度 方案三:多进程 + 队列
多进程使用注意点
1.多进程说明 进程:一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。
2.使用多进程后的通信 多进程中使用普通的队列模块无法实现进程间的通讯,因为进程是系统分配资源的基本单元. 对应的需要使用multiprocessing提供的JoinableQueue模块,其使用过程和在线程中使用的queue方法相同
案列使用说明
queue = Queue() # 普通队列无法实现多进程间通信
多进程中要使用multiprocessing.JoinableQueue
from multiprocessing import Process import multiprocessing queue = multiprocessing.JoinableQueue()
def add_to_queue(): for i in range(0, 10): print(“向队列中添加: {}”.format(i)) queue.put(i)
def get_queue(): for i in range(0, 10): print(‘从队列中获取: {}’.format(queue.get())) queue.task_done()
p = Process(target=add_to_queue) p.daemon = True p.start()
p = Process(target=get_queue) p.daemon = True p.start()
让任务能够开始执行
time.sleep(0.01) queue.join() 3. 实现多进程的糗事百科爬虫 把多线程版修改多进程版:
把原来的threading.Thread修改为multiprocessing.Process 把queue.Queue修改为multiprocessing.JoinableQueue
代码
import requests
from lxml import etree
import json
from multiprocessing import JoinableQueue
from multiprocessing import Process
import time
def run_forever(func):
def wrapper(obj):
while True:
func(obj)
return wrapper
class JiubaiSpider(object):
def __init__(self):
self.headers = {
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36
}
self.url_pattern = https://www.Jiushaike.com/8hr/page/{}/
# url 队列
self.url_queue = JoinableQueue()
# 响应队列
self.page_queue = JoinableQueue()
# 数据队列
self.data_queue = JoinableQueue()
def add_url_to_queue(self):
# 把URL添加url队列中
for i in range(1, 14):
self.url_queue.put(self.url_pattern.format(i))
@run_forever
def add_page_to_queue(self):
发送请求获取数据
url = self.url_queue.get()
pass
self.url_queue.task_done()
@run_forever
def add_dz_to_queue(self):
根据页面内容使用lxml解析数据, 获取段子列表
page = self.page_queue.get()
pass
self.page_queue.task_done()
def get_first_element(self, list):
获取列表中第一个元素,如果是空列表就返回None
return list[0] if len(list) != 0 else None
@run_forever
def save_dz_list(self):
把段子信息保存到文件中
dz_list = self.data_queue.get()
pass
self.data_queue.task_done()
def run_use_more_task(self, func, count=1):
把func放到进程中执行, count:开启多少进程执行
for i in range(0, count):
t = Process(target=func)
t.daemon = True
t.start()
def run(self):
# 开启线程执行上面的几个方法
self.run_use_more_task(self.add_url_to_queue)
self.run_use_more_task(self.add_page_to_queue, 3)
self.run_use_more_task(self.add_dz_to_queue, 2)
self.run_use_more_task(self.save_dz_list, 2)
# 让主线线程等待0.001s让有时间想队列中添加数据
time.sleep(0.001)
# 使用队列join方法,等待队列任务都完成了才结束
self.url_queue.join()
self.page_queue.join()
self.data_queue.join()
if __name__ == __main__:
qbs = JiubaiSpider()
qbs.run()
