python多線程爬蟲項目() 爬取目標:鬥圖啦(起始url:http://www.doutula.com/photo/list/?page=1) 爬取內容:鬥圖啦全網圖片 使用工具:requests庫實現發送請求、獲取響應。 xpath實現數據解析、提取和清洗 threading模塊實現多線程爬蟲 ...
python多線程爬蟲項目()
爬取目標:鬥圖啦(起始url:http://www.doutula.com/photo/list/?page=1)
爬取內容:鬥圖啦全網圖片
使用工具:requests庫實現發送請求、獲取響應。
xpath實現數據解析、提取和清洗
threading模塊實現多線程爬蟲
爬取結果:
思路:由於該爬蟲存在網路密集IO和磁碟密集IO,存在大量等待時間,遂採用多線程方式爬取。
設計:本文采用多為結構化代碼的面向對象封裝設計思路,使用生產消費者模型,完成多線程的調度、爬取。
直接放代碼(詳細說明在註釋里,歡迎同行相互交流、學習~):
1 import os 2 import threading 3 import re 4 from queue import Queue 5 import requests 6 from urllib import request 7 from lxml import etree 8 9 # 定義一個全局變數,存儲請求頭headers數據 10 headers = { 11 "User-Agent": "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)" 12 } 13 14 class Producter(threading.Thread): 15 """ 16 生產者模型:負責從起始url隊列中提取url,進行解析,將得到的圖片地址放入img圖片隊列中 17 """ 18 def __init__(self, page_queue, img_queue, *args, **kwargs): 19 # 改寫父類threading.Thread的__init__方法,添加預設值 20 super(Producter, self).__init__(*args, **kwargs) 21 # 添加對象屬性 22 self.page_queue = page_queue 23 self.img_queue = img_queue 24 25 def run(self): 26 """ 27 實現消費者模型的主要業務邏輯 28 """ 29 while True: 30 # 當請求隊列為空,生產者停止生產 31 if self.page_queue.empty(): 32 break 33 # 獲取起始url隊列的對象,進行頁面解析 34 url = self.page_queue.get() 35 self.parse_url(url) 36 37 def parse_url(self, url): 38 """ 39 實現解析指定頁面的功能 40 :param url: 傳入待處理的頁面url 41 """ 42 response = requests.get(url=url, headers=headers) 43 html = etree.HTML(response.text) 44 # 使用lxml庫里HTML解析器進行數據解析,利用xpath語法解析得到指定數據,返回一個element對象列表 45 url_gifs = html.xpath("//div[@class='page-content text-center']//img[@class!='gif']") 46 for url_gif in url_gifs: 47 # element.get(屬性名)可以獲取屬性值 48 url_name = url_gif.get("alt") 49 # 正則表達式替換非法字元 50 url_name = re.sub(r"[\!!\.\??]", "", url_name).strip() 51 url_link = url_gif.get("data-original") 52 # os模塊中os.path.splitext()可以獲取url的尾碼名 53 url_suffix = os.path.splitext(url_link)[1] 54 filename = url_name + url_suffix 55 # 隊列的put()裡面傳的是元組或者列表 56 self.img_queue.put((url_link, filename)) 57 58 class Consumer(threading.Thread): 59 """ 60 消費者模型的主要業務邏輯 61 """ 62 63 def __init__(self, page_queue, img_queue, *args, **kwargs): 64 super(Consumer, self).__init__(*args, **kwargs) 65 self.page_queue = page_queue 66 self.img_queue = img_queue 67 68 def run(self): 69 """ 70 實現讀取圖片url內容的功能 71 """ 72 while True: 73 if self.page_queue.empty() and self.img_queue.empty(): 74 break 75 url, filename = self.img_queue.get() 76 # urllib庫裡面的request模塊可以讀取圖片url內容 77 request.urlretrieve(url, "GIF/" + filename) 78 # 控制台輸出提示信息 79 print(filename + "-------下載完成!") 80 81 def main(): 82 # 創建page隊列,存放請求的起始url;創建img隊列,存放圖片data的url 83 page_queue = Queue(100) # 設置隊列的最大存儲數量 84 img_queue = Queue(1000) # 設置隊列的最大存儲數量 85 for i in range(100): 86 start_url_format = "http://www.doutula.com/photo/list/?page={}".format(i) 87 # print(start_url_format) #調試代碼用 88 page_queue.put(start_url_format) #將獲取的起始url放入隊列中 89 # 生成多線程對象(多個生產者、消費者)。實現發送請求,獲取響應,解析頁面,獲取數據 90 for i in range(10): 91 t = Producter(page_queue, img_queue) 92 t.start() 93 for i in range(10): 94 t = Consumer(page_queue, img_queue) 95 t.start() 96 97 if __name__ == '__main__': 98 main()