:點擊上方[Python爬蟲數據分析挖掘]→右上角[...]→[設爲星標⭐]html
多線程爬取表情包
有一個網站,叫作「鬥圖啦」,網址是:https://www.doutula.com/
。這裏麪包含了許許多多的有意思的鬥圖圖片,還蠻好玩的。有時候爲了鬥圖要跑到這個上面來找表情,實在有點費勁。因而就產生了一個邪惡的想法,能夠寫個爬蟲,把全部的表情都給爬下來。這個網站對於爬蟲來說算是比較友好了,他不會限制你的headers
,不會限制你的訪問頻率(固然,做爲一個有素質的爬蟲工程師,爬完趕忙撤,不要把人家服務器搞垮了),不會限制你的IP地址,所以技術難度不算過高。可是有一個問題,由於這裏要爬的是圖片,而不是文本信息,因此採用傳統的爬蟲是能夠完成咱們的需求,可是由於是下載圖片因此速度比較慢,可能要爬一兩個小時都說不許。所以這裏咱們準備採用多線程爬蟲,一下能夠把爬蟲的效率提升好幾倍。python
文章目錄
一、爬取準備程序員
二、完整代碼web
三、圖片輔助分析ruby
四、運行結果服務器
一、爬取準備
爬取目標微信
https://www.doutula.com/article/list/
批量爬取網絡
舒適提示:爬取過程當中保持網絡通暢,否則會爬取失敗!
這裏多線程咱們使用的是Python
自帶的threading
模塊。而且咱們使用了一種叫作生產者和消費者的模式,生產者專門用來從每一個頁面中獲取表情的下載連接存儲到一個全局列表中。而消費者專門從這個全局列表中提取表情連接進行下載。而且須要注意的是,在多線程中使用全局變量要用鎖來保證數據的一致性。
ps:感興趣的小夥伴能夠試試線程池多線程
使用線程池app
線程池或進程池是用於在程序中優化和簡化線程/進程的使用。經過池,你能夠提交任務給executor。池由兩部分組成,一部分是內部的隊列,存放着待執行的任務;另外一部分是一系列的進程或線程,用於執行這些任務。池的概念主要目的是爲了重用:讓線程或進程在生命週期內能夠屢次使用。它減小了建立建立線程和進程的開銷,提升了程序性能。重用不是必須的規則,但它是程序員在應用中使用池的主要緣由。
二、完整代碼
import requestsfrom threading import Threadfrom queue import Queuefrom lxml import etreeimport timeimport osimport random
# 請求頭headers = { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36"}path = "./圖片"
#數據採集class CrawlInfo(Thread): def __init__(self ,url_queue ,html_queue): Thread.__init__(self)
self.url_queue = url_queue self.html_queue = html_queue
def run(self): # 不存在就建立 if not os.path.exists(path): # mkdir是建立文件夾 os.mkdir(path)
while self.url_queue.empty() == False: url = self.url_queue.get() response = requests.get(url,headers=headers) #請求成功狀態碼爲200則進行put if response.status_code == 200: self.html_queue.put(response.text)
# 數據解析、保存class ParseCrawl(Thread): def __init__(self, html_queue): Thread.__init__(self) self.html_queue = html_queue
def run(self): #隊列不爲空則繼續遍歷 while self.html_queue.empty() == False: data = etree.HTML(self.html_queue.get()) #查看圖1,根據class定位獲取其下的全部a標籤 a_list = data.xpath("//div[@class='col-sm-9 center-wrap']/a") #遍歷a標籤 for a_singer in a_list: #查看圖2,從新寫xpath根據class定位 #text():獲取文本值 name = a_singer.xpath(".//div[@class='random_title']/text()")[0] #替換掉name中的\u200b\u200b\u200b字符串 name = str(name).replace("\u200b\u200b\u200b","") #拼接新的路徑 new_path = path + "/" + name #新路徑不存在就建立 if not os.path.exists(new_path): os.mkdir(new_path)
#獲取圖片url,查看圖3 #根據class值定位到全部img的父標籤,在根據img的class拿到全部img的data-original屬性即圖片url,這裏不拿src屬性是由於爬取時拿到的是圖片還未加載完畢的url img_url_list = a_singer.xpath(".//div[@class='random_article']//img[@class='lazy image_dtb img-responsive']/@data-original") #遍歷img_url_list for img in img_url_list: #因爲圖片有jpg、png、gif格式,這裏咱們根據'.'分割獲取圖片格式後綴 suffix = "." + str(img).split(".")[-1] #發起請求,content爲二進制 re = requests.get(img,headers=headers).content
#圖片命名爲隨機數str(random.randint(1,500)) with open(new_path + "/" + str(random.randint(1,500)) + str(suffix), "wb") as f: #保存圖片 f.write(re)
#開始if __name__ == '__main__': start = time.time()
url_queue = Queue() html_queue = Queue()
base_url = "https://www.doutula.com/article/list/?page={}" #咱們這隻爬取13頁 for i in range(1,14): print("正在爬取第{}頁".format(i)) new_url = base_url.format(i) url_queue.put(new_url)
crawl_list = [] for i in range(3): Crawl = CrawlInfo(url_queue, html_queue) crawl_list.append(Crawl) Crawl.start()
for crawl in crawl_list: crawl.join()
parse_list = [] for i in range(3): parse = ParseCrawl(html_queue) parse_list.append(parse) parse.start()
for parse in parse_list: parse.join()
end = time.time() print("爬取時間:{}".format(end- start))
以上這份代碼。能夠完整的運行了。採用多線程,在一張圖片下載的時候,就徹底能夠去請求其餘圖片,而不用繼續等待了。所以效率比較高。
三、圖片輔助分析
圖1
圖2
圖3
四、運行結果
寫在最後:
本教程採用多線程來完成表情的爬取,可讓爬取效率高出不少倍。Python
的多線程雖然有GIL
全局解釋器鎖,但在網絡IO
處理這一塊表現仍是很好的,不用在一個地方一直等待。以上這個例子就很好的說明了多線程的好處。
【各類爬蟲源碼獲取方式】
- END -
歡迎關注公衆號:Python爬蟲數據分析挖掘,方便及時閱讀最新文章
記錄學習python的點點滴滴;
回覆【開源源碼】免費獲取更多開源項目源碼;
本文分享自微信公衆號 - Python爬蟲數據分析挖掘(zyzx3344)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。