最令人頭疼的Python問題:Python多執行緒在爬蟲中的應用
作為測試工程師經常需要解決測試資料來源的問題,解決思路無非是三種:
1、直接從生產環境複製真實資料
2、從網際網路上爬取資料
3、自己用指令碼或者工具造資料。
前段時間,為了獲取更多的測試資料,筆者就做了一個從網際網路上爬取資料的爬蟲程式,雖然功能上基本滿足專案的需求,但是爬取的效率還是不太高。
作為一個精益求精的測試工程師,決定研究一下多執行緒在爬蟲領域的應用,以提高爬蟲的效率。
一、為什麼需要多執行緒
凡事知其然也要知其所以然。在瞭解多執行緒的相關知識之前,我們先來看看為什麼需要多執行緒。打個比方吧,你要搬家了,單執行緒就類似於請了一個搬家工人,他一個人負責打包、搬運、開車、卸貨等一系列操作流程,這個工作效率可想而知是很慢的;而多執行緒就相當於請了四個搬家工人,甲打包完交給已搬運到車上,然後丙開車送往目的地,最後由丁來卸貨。
由此可見多執行緒的好處就是高效、可以充分利用資源,壞處就是各個執行緒之間要相互協調,否則容易亂套(類似於一個和尚挑水喝、兩個和尚抬水喝、三個和尚沒水喝的窘境)。所以為了提高爬蟲效率,我們在使用多執行緒時要格外注意多執行緒的管理問題。
二、多執行緒的基本知識
程式:由程式,資料集,程式控制塊三部分組成,它是程式在資料集上的一次執行過程。如果同一段程式在某個資料集上執行了兩次,那就是開啟了兩個程式。程式是資源管理的基本單位。在作業系統中,每個程式有一個地址空間,而且預設就有一個控制程式。
執行緒:是程式的一個實體,是 CPU 排程和分派的基本單位,也是最小的執行單位。它的出現降低了上下文切換的消耗,提高了系統的併發性,並克服了一個程式只能幹一件事的缺陷。執行緒由程式來管理,多個執行緒共享父程式的資源空間。
程式和執行緒的關係:
一個執行緒只能屬於一個程式,而一個程式可以有多個執行緒,但至少有一個執行緒。
資源分配給程式,同一程式的所有執行緒共享該程式的所有資源。
CPU 分給執行緒,即真正在 CPU 上執行的是執行緒。
執行緒的工作方式:
如下圖所示,序列指執行緒一個個地在 CPU 上執行;並行是在多個 CPU 上執行多個
執行緒;而併發是一種“偽並行”,一個 CPU 同一時刻只能執行一個任務,把 CPU 的時間
分片,一個執行緒只佔用一個很短的時間片,然後各個執行緒輪流,由於時間片很短所以在
使用者看來所有執行緒都是“同時”的。併發也是大多數單 CPU 多執行緒的實際執行方式。
程式的工作狀態:
一個程式有三種狀態:執行、阻塞、就緒。三種狀態之間的轉換關係如下圖所示:執行態的程式可能由於等待輸入而主動進入阻塞狀態,也可能由於排程程式選擇其他程式而被動進入就緒狀態(一般是分給它的 CPU 時間到了);阻塞狀態的程式由於等到了有效的輸入而進入就緒狀態;就緒狀態的程式因為排程程式再次選擇了它而再次進入執行狀態。
三、多執行緒通訊例項
還是回到爬蟲的問題上來,我們知道爬取部落格文章的時候都是先爬取列表頁,然後根據列表頁的爬取結果再來爬取文章詳情內容。而且列表頁的爬取速度肯定要比詳情頁的爬取速度快。
這樣的話,我們可以設計執行緒 A 負責爬取文章列表頁,執行緒 B、執行緒 C、執行緒 D 負責爬取文章詳情。A 將列表 URL 結果放到一個類似全域性變數的結構裡,執行緒 B、C、D從這個結構裡取結果。
在 PYTHON 中,有兩個支援多執行緒的模組:threading 模組--負責執行緒的建立、開啟等操作;queque 模組--負責維護那個類似於全域性變數的結構。
這裡還要補充一點:也許有同學會問直接用一個全域性變數不就可以了麼?幹嘛非要用 queue?
因為全域性變數並不是執行緒安全的,比如說全域性變數裡(列表型別)只有一個 url 了,執行緒 B 判斷了一下全域性變數非空,在還沒有取出該 url 之前,cpu 把時間片給了執行緒 C,執行緒 C 將最後一個url 取走了,這時 cpu 時間片又輪到了 B,B 就會因為在一個空的列表裡取資料而報錯。
而 queue 模組實現了多生產者、多消費者佇列,在放值取值時是執行緒安全的。
廢話不多說了,直接上程式碼給大夥看看:
import threading # 匯入 threading 模組
from queue import Queue #匯入 queue 模組
import time #匯入 time 模組
# 爬取文章詳情頁
def get_detail_html(detail_url_list, id):
while True:
url = detail_url_list.get() #Queue 佇列的 get 方法用於從佇列中提取元素
time.sleep(2) # 延時 2s,模擬網路請求和爬取文章詳情的過程
print("thread {id}: get {url} detail finished".format(id=id,url=url)) #列印執行緒 id 和被爬取了文章內容的 url
# 爬取文章列表頁
def get_detail_url(queue):
for i in range(10000):
time.sleep(1) # 延時 1s,模擬比爬取文章詳情要快
queue.put("{id}".format(id=i))#Queue 佇列的 put 方法用於向 Queue 佇列中放置元素,由於 Queue 是先進先出佇列,所以先被 Put 的 URL 也就會被先 get 出來。
print("get detail url {id} end".format(id=i))#列印出得到了哪些文章的 url
#主函式
if __name__ == "__main__":
detail_url_queue = Queue(maxsize=1000) #用 Queue 構造一個大小為 1000 的執行緒安全的先進先出佇列
# 先創造四個執行緒
thread = threading.Thread(target=get_detail_url, args=(detail_url_queue,)) #A 執行緒負責抓取列表
url
html_thread= []
for i in range(3):
thread2 = threading.Thread(target=get_detail_html, args=(detail_url_queue,i))
html_thread.append(thread2)#B C D 執行緒抓取文章詳情
start_time = time.time()
# 啟動四個執行緒
thread.start()
for i in range(3):
html_thread[i].start()
# 等待所有執行緒結束,thread.join()函式代表子執行緒完成之前,其父程式一直處於阻塞狀態。
thread.join()
for i in range(3):
html_thread[i].join()
print("last time: {} s".format(time.time()-start_time))#等 ABCD 四個執行緒都結束後,在主程式中計算總爬取時間。
執行結果:
後記:
從執行結果可以看出各個執行緒之間井然有序地工作著,沒有出現任何報錯和告警的情況。可見使用 Queue 佇列實現多執行緒間的通訊比直接使用全域性變數要安全很多。而且使用多執行緒比不使用多執行緒的話,爬取時間上也要少很多,在提高了爬蟲效率的同時也兼顧了執行緒的安全,可以說在爬取測試資料的過程中是非常實用的一種方式。
希望小夥伴們能夠 GET 到哦!
加我VX:ww-51testing 回覆關鍵詞“測試”領取限量軟體測試學習資料哦~~
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31407649/viewspace-2662778/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python《多執行緒併發爬蟲》Python執行緒爬蟲
- python多執行緒爬蟲與單執行緒爬蟲效率效率對比Python執行緒爬蟲
- python中多執行緒和多程序的應用Python執行緒
- python爬蟲入門八:多程式/多執行緒Python爬蟲執行緒
- Python爬蟲入門【9】:圖蟲網多執行緒爬取Python爬蟲執行緒
- python多執行緒非同步爬蟲-Python非同步爬蟲試驗[Celery,gevent,requests]Python執行緒非同步爬蟲
- python爬蟲之多執行緒、多程式+程式碼示例Python爬蟲執行緒
- PyQt應用程式中的多執行緒:使用Qt還是Python執行緒?QT執行緒Python
- Python爬蟲入門【10】:電子書多執行緒爬取Python爬蟲執行緒
- Python中的多工:多執行緒Python執行緒
- Python爬蟲之路-chrome在爬蟲中的使用Python爬蟲Chrome
- Python爬蟲之路-selenium在爬蟲中的使用Python爬蟲
- python中多執行緒消費者生產者問題Python執行緒
- Python | 多執行緒死鎖問題的巧妙解決方法Python執行緒
- python面試題之python下多執行緒的限制Python面試題執行緒
- python中的socket+threading多執行緒Pythonthread執行緒
- python 代理在爬蟲中的作用Python爬蟲
- python多執行緒中:如何關閉執行緒?Python執行緒
- python網路爬蟲應用_python網路爬蟲應用實戰Python爬蟲
- 簡易多執行緒爬蟲框架執行緒爬蟲框架
- 多執行緒爬蟲實現(上)執行緒爬蟲
- Python的多程式和多執行緒Python執行緒
- python多執行緒爬去糗事百科Python執行緒
- 教程中 令人頭疼的 前端流安裝前端
- Spring中多執行緒的使用及問題Spring執行緒
- Python爬蟲入門教程 13-100 鬥圖啦表情包多執行緒爬取Python爬蟲執行緒
- Python爬蟲入門教程 11-100 行行網電子書多執行緒爬取Python爬蟲執行緒
- Python爬蟲亂碼問題Python爬蟲
- [譯] Python 的多執行緒與多程式Python執行緒
- python多程式取代多執行緒的探究Python執行緒
- Python 多執行緒多程式Python執行緒
- python中的執行緒池Python執行緒
- python爬蟲常見的那點問題!Python爬蟲
- 如何爬取 python 進行多執行緒跑資料的內容Python執行緒
- Python執行緒專題10:queue、多執行緒按順序執行Python執行緒
- 資料提取方法-多程式多執行緒爬蟲執行緒爬蟲
- Java多執行緒中執行緒安全與鎖問題Java執行緒
- python豆瓣多執行緒爬蟲加IP代理(免費的一般是不穩定)Python執行緒爬蟲