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()

你可能感兴趣的:(数据采集)