最近的部門RPA項目中,小爬為了提升爬蟲性能,使用了Python中的多進程(multiprocessing)技術,里面需要用到進程鎖Lock,用到進程池Pool,同時利用map方法一次構造多個process。Multiprocessing的使用確實能顯著提升爬蟲速度,不過程序交由用戶使用時,缺乏一個好的GUI窗口來顯示爬蟲進度。之前的文章中使用了Chrome瀏覽器來渲染js腳本生成了進度條。但是鑒於Chrome在運行時十分吃內存資源,用Chrome只是生成一個進度條難免有些“大材小用”,所以,小爬決定使用Tkinter庫來制作進度條,進而擺脫對chrome瀏覽器的依賴。
要制作進度條,就得有計數器存儲爬蟲的總數,當前的爬取數甚至是當前的耗費時間等作為存儲變量。考慮到各個進程之間無法直接通信,這個當前量和總量如何得到,就只能借助multiprocessing中的Queue類了。根據官方文檔,multiprocessing中的Queue 類幾乎完美克隆了Queue.Queue中的功能,但是它是專為多進程間的通信單獨設計的。

透過一個簡單的例子看下Queue是如何運用的:
from multiprocessing import Process, Queue def f(q): q.put([42, None, 'hello']) if __name__ == '__main__': q = Queue() p = Process(target=f, args=(q,)) p.start() print q.get() # prints "[42, None, 'hello']" p.join()
從上面的例子可以看到,此處的Queue示例出的q對象非常靈活,使用Ipython的代碼提示功能可以輕松知道q對象含以下方法,供用戶調用:

比如:
1、它主要是通過q.put()來入列,該方法支持存入單個變量,也支持通過列表一次入列多個不同類型的元素,異常靈活多變。
2、q.qsize()可以得到當前隊列的元素總數。
3、q.empty()可以判斷當前隊列中是否還有值,返回一個布爾型的結果。如:
In [36]: q.empty()
Out[36]: True
4、通過q.get()方法來出隊列。
這樣我們就可以靈活使用隊列來在各進程間通信和制作進度條了。
我們在爬蟲中,往往會遇到一個這樣的情況,目錄頁和詳情頁的信息需要結合到一個item中存儲起來,它就可以巧妙借助Queue來實現。

上面的例子中,我一次存入了url,bpmDefName,dataId,afFormNumber 等多個字段信息。
后面我們再從queue中取出一個結果,則該結果是包含 url,bpmDefName,dataId,afFormNumber 多個信息的元組。進而得到元組的每個元素與詳情頁的相關字段拼接到一起,形成一行信息。代碼示例如下:

最后通過Q.qsize()方法判斷隊列中的元素是否已完全取出,來實時計算爬蟲進度和決定后續動作,非常方便!

有了multiprocessing模塊的Queue類和它提供的諸多方法,制作進度條和關聯多個item信息,便不再是難題!
更詳細的multiprocessing模塊的Queue類介紹,可以參見python官方的文檔說明:
https://docs.python.org/3/library/multiprocessing.html#multiprocessing.Queue
