Python多線程爬蟲快速批量下載下傳圖檔
1、完成這個需要導入的子產品
urllib,random,queue(隊列),threading,time,os,json
第三方子產品的安裝
鍵盤win+R,輸入cmd,來到指令視窗
對于urllib子產品,安裝代碼pip install urllib3
2、怎樣多線程爬取圖檔
首先,我們需要來到這個網址
https://www.quanjing.com/
然後輸入關鍵字,來到另外一個界面,如 我輸入 風景
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5CNxQGNwIzYlNTMzgzYkljNzgjY5kTM4QTY5UDNjhTZ38CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
檢視一下源代碼,可以發現,這些圖檔的下載下傳連結應該不是直接寫在網址内的,我們點選滑鼠右鍵,點選檢查,點選Network,點選XHR,按F5重新整理,可以發現XHR下面有這些圖檔的下載下傳連結。
這樣我們就隻需要這個網址就可以得到這一頁是以圖檔的下載下傳連結了。
https://www.quanjing.com/Handler/SearchUrl.ashx?t=8102&callback=searchresult&q=%E9%A3%8E%E6%99%AF&stype=1&pagesize=100&pagenum=1&imageType=2&imageColor=&brand=&imageSType=&fr=1&sortFlag=1&imageUType=&btype=&authid=&_=1584067448531
通過多個這樣的網址進行分析可以發現,‘t=’後面的參數應該是一個四位的随機數,‘q=’後面的參數應該是自己輸入圖檔的類型,也就是 風景,隻不過這裡對于它進行編碼罷了,‘pagnum=’後面的參數是第幾頁的意思,網址中**‘pagesize=100’**标明每頁應該一百張圖檔,而總的頁碼數在這上有
最後面的那個參數值應該是一個時間戳,通過處理得到的。
這樣我們就可以得到爬取多頁的圖檔了。不過,進行爬取的時候,可以發現,就算得到了這個網址,也得不到這些資料,這個時候,我們可以來到這個網址的請求頭那裡,通過多次實驗可以發現隻需在請求頭中加上:Referer:即可
這裡為了讓伺服器認為我們是浏覽器通路的,我們可以在請求頭上添加:User-Agent
代碼如下:
def get_time(): # 時間戳處理 str_time = str(time.time()) str_time = str_time[:str_time.find('.')] + str_time[str_time.find('.') + 1:str_time.find('.') + 4] time.sleep(1.25) # 沒得到一個時間戳,休眠1.25秒 return str_time
def get_url(): keyword = input('請輸入你想下載下傳的圖檔類型:') key_word = parse.urlencode({'q': keyword}) num=int(input('請輸入你想下載下傳的圖檔數量:'))//100 headers = { "Referer": "https://www.quanjing.com/search.aspx?%s" % (key_word), "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3741.400 QQBrowser/10.5.3863.400"} url='https://www.quanjing.com/Handler/SearchUrl.ashx?t=%s&callback=searchresult&%s&stype=1&pagesize=100&pagenum=%s&imageType=2&imageColor=&brand=&imageSType=&fr=1&sortFlag=1&imageUType=&btype=&authid=&_=%s' list_url=[] for i in range(1,num+1): str_1 = str(random.random()) random_1 = str_1[str_1.find('.') + 1:str_1.find('.') + 5] time_1=get_time() url_1=url%(random_1,key_word,i,time_1) list_url.append(url_1) return list_url,headers,keyword
通過這樣我們就可以得到圖檔的下載下傳連結了,後面隻需多線程下載下傳即可。不過,在多線程下載下傳過程,發現下載下傳的圖檔的數量遠遠低于自己輸入的圖檔數量,其實這是因為圖檔同名的原因,我們可以在圖檔名稱前面添加一個随機随機數即可;
運作:
也許輸入完成之後,會達不到自己輸入的圖檔數量程式就自動結束了,建議多試幾次。
完成之後,我們可以檢視一下目前檔案夾下面會多了一個檔案夾,所下載下傳的圖檔就在裡面
為了知道我們下載下傳的圖檔的數量,我們可以這樣:
運作結果:
這樣就發現這裡有400張圖檔。
3、完整代碼如下
import urllib.parse as parse
from urllib import request import random from queue import Queue import threading import time import json import os def get_time(): # 時間戳處理 str_time = str(time.time()) str_time = str_time[:str_time.find('.')] + str_time[str_time.find('.') + 1:str_time.find('.') + 4] time.sleep(1.25) # 沒得到一個時間戳,休眠1.25秒 return str_time def get_url(): keyword = input('請輸入你想下載下傳的圖檔類型:') key_word = parse.urlencode({'q': keyword}) num=int(input('請輸入你想下載下傳的圖檔數量:'))//100 headers = { "Referer": "https://www.quanjing.com/search.aspx?%s" % (key_word), "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3741.400 QQBrowser/10.5.3863.400"} url='https://www.quanjing.com/Handler/SearchUrl.ashx?t=%s&callback=searchresult&%s&stype=1&pagesize=100&pagenum=%s&imageType=2&imageColor=&brand=&imageSType=&fr=1&sortFlag=1&imageUType=&btype=&authid=&_=%s' list_url=[] for i in range(1,num+1): str_1 = str(random.random()) random_1 = str_1[str_1.find('.') + 1:str_1.find('.') + 5] time_1=get_time() url_1=url%(random_1,key_word,i,time_1) list_url.append(url_1) return list_url,headers,keyword tuple_1=get_url() list_url,headers,keyword=tuple_1[0],tuple_1[1],tuple_1[2] queue_url = Queue(len(list_url)*100+5) queue_img = Queue(len(list_url)*100+5) try: # 防止因為沒有該圖檔類型而報錯 num=1 for i in range(len(list_url)): request_1=request.Request(url=list_url[i],headers=headers) content=request.urlopen(request_1) str_1 = content.read().decode('utf-8') # 得到的資料字元串類型 str_1 = str_1[str_1.find('(') + 1:str_1.rfind(')')] dict_1 = json.loads(str_1) images_list = dict_1['imglist'] for j in range(len(images_list)): print('【{}】-{}'.format(num, images_list[j]['caption'])) queue_url.put(images_list[j]['imgurl']) queue_img.put(images_list[j]['caption']) num+=1 def Downlad(queue_url: Queue, queue_img: Queue): path_1 = './' + keyword try: os.mkdir(path_1) except: pass finally: while True: if queue_url.empty(): break image_name = queue_img.get() request.urlretrieve(url=queue_url.get(), filename=path_1 + '/【{}】-{}.png'.format(random.random()*1000,image_name)) # 下載下傳圖檔 # 為了防止出現圖檔名相同的情況,對于圖檔命名添加一個随機數 print('線程{}正在下載下傳【{}】'.format(threading.current_thread().getName(), image_name)) time.sleep(0.25) # 每下載下傳一張圖檔,休眠0.25秒 threading_list = [] print('開始下載下傳!') time.sleep(5) for i in range(len(list_url)*5): # 根據使用者的輸入建立相應多的線程 threading_1 = threading.Thread(target=Downlad, args=(queue_url, queue_img,)) threading_1.start() threading_list.append(threading_1) for i in threading_list: i.join() print('------------------------下載下傳完畢!目前線程為', threading.current_thread().getName()) except Exception as e: print(e,'沒有搜到該圖檔或者今日通路次數過多!')