摘要:繼續看上一段循環的代碼,是遍歷,將已經掛了的線程去除掉,那么在這個中線程什么情況下會死掉就是類中的方法中的這段代碼如果為空會循環,此時對應的線程會死掉。此時主函數的循環將死掉的線程去除,在線程數不足個的情況下,接下來的循環繼續制造新的線程。
上一篇文章: 從0開始寫一個多線程爬蟲(1)
我們用繼承Thread類的方式來改造多線程爬蟲,其實主要就是把上一篇文章的代碼寫到線程類的run方法中,代碼如下:
import re import requests from threading import Thread class BtdxMovie(Thread): # 初始化時傳入3個list,含義見上文,并為當前線程取個名字 def __init__(self, total_url_list, used_url_list, movie_url_list, thread_name="MyThread"): super(BtdxMovie, self).__init__() self.all_url = total_url_list self.used_url = used_url_list self.movie_url = movie_url_list self.name = thread_name def run(self): while 1: # 從all_url中獲取第一條url,如果all_url為空則break,這會導致線程死掉(is_alive()為False) try: url = self.all_url.pop(0) except IndexError: break # 如果url是電影詳情頁,則將其加入到movie_url中 if re.match("https://www.btdx8.com/torrent/.*?html", url): if url not in self.movie_url: self.movie_url.append(url) try: html = requests.get(url).text new_url = re.findall("href="(https://.*?)"", html) for u in new_url: # 只要同一個域名下的url if not re.match("https://.*?btdx8.com", u): continue # "#"在url中是代表網頁位置的,這里處理一下,避免url重復 if "#" in u: u = u.split("#")[0] if u in self.used_url or u in self.all_url: continue self.all_url.append(u) except: pass self.used_url.append(url) # 每次循環打印當前線程id和各個list的長度 curr_thread = "[{}]".format(self.name) info = "ALL: {}, USED: {}, MOV: {}".format(len(self.all_url), len(self.used_url), len(self.movie_url)) print(curr_thread + ": " + info)
此時線程類就已經寫好了,接下來要做的就是生成多個實例,并開啟線程,繼續追加如下代碼:
# 網站首頁 base_url = r"https://www.btdx8.com/" # 爬取到的新url會繼續加入到這個list里 total_url_list = [base_url] # 存放已經爬取過的url used_url_list = [] # 存放是電影詳情頁的url movie_url_list = [] # 存入線程對象的list thread_list = [] thread_id = 0 while total_url_list or thread_list: for t in thread_list: if not t.is_alive(): thread_list.remove(t) while len(thread_list) < 5 and total_url_list: thread_id += 1 thread_name = "Thread-{}".format(str(thread_id).zfill(2)) t = BtdxMovie(total_url_list, used_url_list, movie_url_list, thread_name) t.start() thread_list.append(t)
此時運行腳本,就可以以多線程的方式抓取url了,運行之后print的信息如下:
[Thread-04]: ALL: 2482, USED: 84, MOV: 55 [Thread-01]: ALL: 2511, USED: 85, MOV: 56 [Thread-02]: ALL: 2518, USED: 86, MOV: 57 [Thread-05]: ALL: 2555, USED: 87, MOV: 58 [Thread-03]: ALL: 2587, USED: 88, MOV: 59 [Thread-01]: ALL: 2595, USED: 89, MOV: 60 [Thread-04]: ALL: 2614, USED: 90, MOV: 61 [Thread-05]: ALL: 2644, USED: 91, MOV: 62 [Thread-03]: ALL: 2686, USED: 92, MOV: 63
我們來解釋一下while循環里的代碼,先看內嵌的while循環,是當total_url_list不為空,并且thread_list長度小于5的時候執行,利用thread_id獲得thread_name,實例化一個線程實例t,并用t.start()開啟線程,然后將其加入到thread_list中,因此很容易可以理解這段代碼,就是確保當前運行的線程數為5,并且給每個新線程一個從1開始自增長的id。
繼續看上一段for循環的代碼,是遍歷thread_list,將已經掛了的線程去除掉,那么在這個case中線程什么情況下會死掉?就是BtdxMovie類中的run方法中的這段代碼:
try: url = self.all_url.pop(0) except IndexError: break
如果all_url為空會break循環,此時對應的線程會死掉。這里可能很容易誤以為所有的url都已經爬取完了導致線程退出,實際上,目前的代碼沒有對爬取的url深度做控制,可能永遠都不會爬完,當all_url為空時候,很大可能是all_url里的url被線程取走了,但還沒來得及把爬取到新的url加入到all_url中,所以很容易理解這種情況會在程序剛開始運行的時候發生,因為一開始all_url中只有一個url,被第一個線程取走,在第一個線程還沒返回結果的時候,后續的線程去取url都會導致循環break,然后線程死掉。此時主函數的for循環將死掉的線程去除,在線程數不足5個的情況下,接下來的while循環繼續制造新的線程。
那么外層的while循環的條件也很容易就明白了,不能在total_url_list為空的時候退出,要在total_url_list和thread_list都為空的時候才能退出。如果就是在total_url_list為空的時候退出會發生什么?程序會在第一個url被取走導致total_url_list為空的時候退出循環并結束嗎?嚴格來說是的,我們可以在程序的末尾加入一個print語句,就可以驗證修改while條件之后,while循環就退出了,但這個時候是主線程結束了,新增的線程并沒有結束,此時還有一個線程在不斷的運行和爬取url,這個線程就是獲取了第一個url的線程,線程可以設置成隨主線程一起停止,也可以讓主線程掛起等待其余線程運行完成,默認情況下是我們這種,主線程運行完成并停止,而其余線程繼續運行。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/42294.html
摘要:最近發現有個電影下載網站叫做比特大雄,下了幾部電影之后,打算寫個爬蟲把網站的電影信息都爬取下來。結果我就發現,速度太慢了因為決定將其改成多線程爬蟲,歡迎繼續閱讀后續的此系列文章。 最近發現有個電影下載網站叫做比特大雄,下了幾部電影之后,打算寫個爬蟲把網站的電影信息都爬取下來。 一開始思路是這樣的,從首頁開始,解析首頁的所有鏈接,如果這個鏈接是電影詳情頁的鏈接,就將其html解析成想要...
摘要:一般用進程池維護,的設為數量。多線程爬蟲多線程版本可以在單進程下進行異步采集,但線程間的切換開銷也會隨著線程數的增大而增大。異步協程爬蟲引入了異步協程語法。 Welcome to the D-age 對于網絡上的公開數據,理論上只要由服務端發送到前端都可以由爬蟲獲取到。但是Data-age時代的到來,數據是新的黃金,毫不夸張的說,數據是未來的一切?;诮y計學數學模型的各種人工智能的出現...
摘要:所以與多線程相比,線程的數量越多,協程性能的優勢越明顯。值得一提的是,在此過程中,只有一個線程在執行,因此這與多線程的概念是不一樣的。 真正有知識的人的成長過程,就像麥穗的成長過程:麥穗空的時候,麥子長得很快,麥穗驕傲地高高昂起,但是,麥穗成熟飽滿時,它們開始謙虛,垂下麥芒。 ——蒙田《蒙田隨筆全集》 上篇論述了關于python多線程是否是雞肋的問題,得到了一些網友的認可,當然也有...
摘要:以下這些項目,你拿來學習學習練練手。當你每個步驟都能做到很優秀的時候,你應該考慮如何組合這四個步驟,使你的爬蟲達到效率最高,也就是所謂的爬蟲策略問題,爬蟲策略學習不是一朝一夕的事情,建議多看看一些比較優秀的爬蟲的設計方案,比如說。 (一)如何學習Python 學習Python大致可以分為以下幾個階段: 1.剛上手的時候肯定是先過一遍Python最基本的知識,比如說:變量、數據結構、語法...
閱讀 3584·2021-11-04 16:06
閱讀 3578·2021-09-09 11:56
閱讀 846·2021-09-01 11:39
閱讀 896·2019-08-29 15:28
閱讀 2293·2019-08-29 15:18
閱讀 829·2019-08-29 13:26
閱讀 3333·2019-08-29 13:22
閱讀 1046·2019-08-29 12:18