Python《多執行緒併發爬蟲》

星海千尋發表於2020-12-12

今天再去爬取另外一個網站 http://pic.netbian.com/
先來看看這個網站的幾張圖片,我們試圖單獨爬取看看。
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

我們單獨爬取一下試一試
在這裡插入圖片描述

本地檢視,證明圖片是可以爬取成功的。
程式碼如下:

import requests   #匯入模組

def run4():
    headers = {'referer': 'http://pic.netbian.com/',
           'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0'}
    with open("D:/estimages/ali.jpg", "wb") as f :
        f.write(requests.get("http://pic.netbian.com/uploads/allimg/201207/233228-16073551488aeb.jpg", headers=headers).content)
        f.close

    with open("D:/estimages/ali1.jpg", "wb") as f :
        f.write(requests.get("http://pic.netbian.com/uploads/allimg/200618/005100-1592412660d6f4.jpg", headers=headers).content)
        f.close

    with open("D:/estimages/ali2.jpg", "wb") as f :
        f.write(requests.get("http://pic.netbian.com/uploads/allimg/190518/174718-1558172838db13.jpg", headers=headers).content)
        f.close

if __name__ == "__main__":   #主程式入口
    run4()    #呼叫上面的run方法

開始開始。。。
接下來我們得分析下這個網站的結構,http://pic.netbian.com/ 是根url,存在多個標籤,也是個分層的展示結構。
在這裡插入圖片描述

而且是固定這些標籤,數量是固定的,因此我們還是先爬取標籤按種類。
隨意選首頁即可把所有的標籤都爬取下來。
而且標籤的 href 值是下一層的地址,text文字是標籤的文字內容。

點選一個標籤進去,發現是一大堆屬於該標籤的圖片,還有分頁。
比如我點選的是【4K美女】,位址列顯示的是http://pic.netbian.com/4kmeinv/
此時每張圖片的HTML位置如下:在class=”slist”的div塊中。
在這裡插入圖片描述

因此我們需要把這個div下所有img都需要爬取出來。

另外分頁欄如下:
在這裡插入圖片描述

經過觀察可見每個分頁欄的命名也是很有規律的啊,因此我們可以推測出 http://pic.netbian.com/4kmeinv/ 是等於http://pic.netbian.com/4kmeinv/index.html ,在瀏覽器中這樣輸入,果然是對的,其他的頁面都是按照 index_+數字編號的方式。
在這裡插入圖片描述

後面我會把完整程式碼貼上,需要把save_all_images函式的呼叫註釋掉,且讓執行緒順序執行的展示結果(也就是在t.start() 後面增加了t.Join(),這樣就能順序執行了),我做了額外處理,就是頁面實在太多了,越是做了截斷(每個標籤最多爬取10個頁面)。

這裡我還是選擇找【下一頁】的href值來選擇下一個頁面。
在這裡插入圖片描述

它處在class=”page”的div中,找到這個【下一頁】,得到其href值,就得到了下一個頁面的地址。

這樣一來,我們的策略就是:
1:先得到所有的標籤
2:根據標籤建立一個執行緒單獨處理該標籤下所有圖片
3:每一個標籤下,按照分頁,一旦訪問一個頁面,就爬取該頁面所有圖片。

具體程式碼如下:

#-*- coding:utf-8 -*-
import os
import requests
from bs4 import BeautifulSoup
import threading
import time

rootrurl = 'http://pic.netbian.com/'
save_dir = 'D:/estimages/'
no_more_pages = 'END'
max_pages = 8

image_cache = set()
index = len(image_cache)

# step 1: 得到所有標籤tags
html = BeautifulSoup(requests.get(rootrurl).text.encode('iso-8859-1').decode('gbk'), features="html.parser")
tag_list = {}
for link in html.find('div', {'class': 'classify clearfix'}).find_all('a'):
    tag_list[link.string] = link.get('href')

print("the number of unique tag is : %d" % len(tag_list))
print(tag_list)

# step 2: 根據每個標籤分別爬取,每個標籤點進去都是一個分頁
# 因此需要做好分頁,鑑於圖片太多了,我們需要做個多執行緒來操作


class myThread (threading.Thread):   #繼承父類threading.Thread
    def __init__(self, threadID, key ,value):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.key = key
        self.value = value

    def run(self):                   #把要執行的程式碼寫到run函式裡面 執行緒在建立後會直接執行run函式
        time.sleep(1)
        print("Thread %d is running..." % self.threadID)
        self.serachSubPages(self.key, self.value)
        print("Thread %d is over..." % self.threadID)

    def serachSubPages(self, key ,value):

        # 建立這個標籤的子目錄,圖片太多了,按照標籤建立子目錄,方便儲存和整理
        tag_name = key
        if not os.path.exists(save_dir + tag_name):
            os.mkdir(save_dir + tag_name)
        print("current tag is : " + tag_name)

        url = rootrurl + value + 'index.html'
        pages = 0;
        while 1:
            print("next page: " + url)
            html = BeautifulSoup(requests.get(url).text.encode('iso-8859-1').decode('gbk'), features="html.parser")
            self.save_all_images(html, save_dir + tag_name)

            if pages >= max_pages:  #每個標籤最多搜尋的頁面數
                break;
            pages = pages + 1

            url = self.findNextPage(html)
            if url == no_more_pages:
                break
            url = rootrurl + url



    def save_all_images(self, html, saveDir):
        global index
        imgs = html.find('div', {'class': 'slist'}).find_all('img')
        print('total imgs is %d:' % len(imgs))
        for img in imgs:

            # 有一些圖片的href是src, 有一些圖片的href是original,因此都是要考慮的。
            href = img.get('src')
            print(href)

            # 判斷是否重複下載
            if href not in image_cache:
                with open(
                        '{}/{}'.format(saveDir, href.split("/")[-1]), 'wb') as jpg:  # 請求圖片並寫進去到本地檔案
                    jpg.write(requests.get(rootrurl + href).content)

                image_cache.add(href)
                print("正在抓取第%s條資料" % index)
                index += 1

    def findNextPage(self, html):
        nextBtn = html.find('div', {'class': 'page'}).find_all('a')  # 找到next按鈕,獲得下一個連線網頁的位置
        for link in nextBtn:
            if link.string == '下一頁':
                return link.get('href')[1:]

        return no_more_pages


if __name__ == '__main__':
    i = 0
    thread_list = []
    for key ,value in tag_list.items():
        thread1 = myThread(i, key ,value[1:])  # 建立多個執行緒去分別爬取各個標籤頁的資料
        thread_list.append(thread1)
        i=i+1

    for t in thread_list:
        # t.setDaemon(True)  # 設定為守護執行緒,不會因主執行緒結束而中斷
        t.start()

效果如下:
在這裡插入圖片描述
在這裡插入圖片描述
請新增圖片描述

請新增圖片描述

相關文章