python + selenium多进程分摊爬虫任务基础

python + selenium多进程分摊爬虫任务基础

1. 背景

  • 现在有这样一个需求:爬取淘宝商品信息,具体的流程是,在搜索栏输入关键字,然后爬取搜索结果列表中的商品信息。
  • 分析这个需求会发现具有如下特点:
    • 第一,淘宝请求url具有一定的反爬措施,构造起来困难 ——> 应对这种问题的方案就是采用selenium浏览器渲染技术去爬取。
    • 第二,实践发现,目前淘宝对这个爬取频率并没有做很大的限制。也就是说,可以在selenium的基础上,加上多进程并发的方式,并行爬取数据,加快爬取速度。
    • 第三,为什么不用多线程,而选择多进程?由于python GIL的存在,在CPU密集型的程序当中,使用多线程并不能有效利用多核CPU的优势,因为一个解析器在同一时刻只会有一个线程在执行。所以,python的多进程(multiprocessing)模块可以充分利用硬件的多处理器来进行工作。目前支持UNIX和Windows系统。而且multiprocessing提供了本地和远程的并发性。

2. 环境

  • python 3.6.1
  • 系统:win7
  • IDE:pycharm
  • selenium 3.7.0

3. 多进程任务分摊

  • 基本思路:
    • 第一,开多个进程,并行运行多个chrome浏览器。
    • 第二,将所有的关键字放入同一个queue中,其他进程从中获取关键字,进行搜索数据。

import configure
import multiprocessing
import time

# 由mark标记是哪个进程执行的动作
def getkeyWordFunc(queue, lock, mark):
    while not queue.empty():
        # def get(self, block=True, timeout=None):
        keyWord = queue.get()

        # 加锁,是为了防止散乱的打印。 保护一些临界状态
        # 多个进程运行的状态下,如果同一时刻都调用到print,那么显示的打印结果将会混乱
        lock.acquire()
        print(f"keyWord = {keyWord}, markProcess = {mark}")
        lock.release()
        time.sleep(1)

if __name__ == '__main__':
    lock = multiprocessing.Lock()       # 进程锁
    queue = multiprocessing.Queue(150)  # 队列,用于存放所有的初始关键字

    for keyWord, keyWordValue in configure.keySearchWords.items():
        print(f"keyWord = {keyWord}")
        # 如果queue定的太小,剩下的放不进去,程序就会block住,等待队列有空余空间
        # def put(self, obj, block=True, timeout=None):
        queue.put(keyWord)
    print(f"queueBefore = {queue}")

    getKeyProcessLst = []
    # 生成两个进程,并启动
    for i in range(2):
        # 携带的args 必须是python原有的数据类型,不能是自定义的。否则会出现下面的error(见后面)
        process = multiprocessing.Process(target = getkeyWordFunc, args = (queue, lock, i))
        process.start()
        getKeyProcessLst.append(process)

    # 守护线程
    # join 等待线程终止,如果不使用join方法对每个线程做等待终止,那么线程在运行过程中,可能会去执行最后的打印
    # 如果没有join,父进程就不会阻塞,启动子进程之后,父进程就直接执行最后的打印了
    for p in getKeyProcessLst:
        p.join()

    print(f"queueAfter = {queue}")
    queue.close()
    print(f"all queue used.")
  • 运行结果:可以看到关键字被分摊到两个进程中去了
queueBefore = <multiprocessing.queues.Queue object at 0x0000000002277F60>
keyWord = 头巾, markProcess = 0
keyWord = 上衣, markProcess = 1
keyWord = 铁碗, markProcess = 0
keyWord = 玩具, markProcess = 1
keyWord = 苹果, markProcess = 0
keyWord = 床单, markProcess = 1
keyWord = 石榴, markProcess = 0
queueAfter = <multiprocessing.queues.Queue object at 0x0000000002277F60>
all queue used.
  • args参数不正确造成的error
queueBefore = <multiprocessing.queues.Queue object at 0x000000000385CCF8>
Traceback (most recent call last):
  File "E:/PyCharmCode/taobaoProductSelenium/taobaoSeleniumMulti.py", line 399, in <module>
    process.start()
  File "E:\Miniconda\lib\multiprocessing\process.py", line 105, in start
    self._popen = self._Popen(self)
  File "E:\Miniconda\lib\multiprocessing\context.py", line 223, in _Popen
    return _default_context.get_context().Process._Popen(process_obj)
  File "E:\Miniconda\lib\multiprocessing\context.py", line 322, in _Popen
    return Popen(process_obj)
  File "E:\Miniconda\lib\multiprocessing\popen_spawn_win32.py", line 65, in __init__
    reduction.dump(process_obj, to_child)
  File "E:\Miniconda\lib\multiprocessing\reduction.py", line 60, in dump
    ForkingPickler(file, protocol).dump(obj)
TypeError: can't pickle _thread.lock objects
发布了73 篇原创文章 · 获赞 244 · 访问量 69万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章