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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章