Ref1:https://blog.csdn.net/qq_32166627/article/details/60882964
Ref2:https://blog.csdn.net/sinat_35045195/article/details/79205578
Ref3:https://www.jianshu.com/p/a31745fef1d8
思路:
1)獲取 關鍵詞 對應的百度圖片頁面信息
2)從頁面信息中獲取url
3)根據url下載圖片
4)多線程加速
代碼:
# -*- coding: utf-8 -*-
# @Time : 2020/1/24 18:47
# @Author : Zhao HL
# @File : pic_download.py
import re, os,sys,time,threading
import requests, urllib,socket
socket.setdefaulttimeout(2)# 最長響應時間2秒
save_path = r'E:\_Python\99_interest\web_spider\web_get\test'
key_words = ['貓','狗']
get_nums = [10]
def get_imgs(key_words, save_path=save_path, get_nums=get_nums):
if len(key_words) != len(get_nums):
get_nums = get_nums * len(key_words)
clear_dir(save_path)
print('clear',save_path)
t = time.time()
for kw, n in zip(key_words, get_nums):
img_folder = os.path.join(save_path, kw)
if not os.path.exists(img_folder):
os.makedirs(img_folder)
print(kw,':')
datas = get_Datas(kw,n)
# get_thumbImg(datas,img_folder)# 爬取縮略圖
get_thumbImg_thread(datas,img_folder)# 多線程爬取縮略圖
# get_srcImg(datas, img_folder)# 爬取原始圖
print('total time',time.time()-t)
#region get methods
def get_Datas(keyword, n=100):
'''
根據關鍵詞和指定圖片下載數量,獲取百度圖片對應的json信息
:param keyword: 搜索關鍵詞
:param n: 下載數量,實際數量爲大於等於n的30的整數倍
:return:
'''
url = 'https://image.baidu.com/search/index'
params = []
for i in range(0, n, 30):
params.append({
'tn': 'resultjson_com',
'ipn': 'rj',
'ct': 201326592,
'is': '',
'fp': 'result',
'queryWord': keyword,
'cl': 2,
'lm': -1,
'ie': 'utf-8',
'oe': 'utf-8',
'adpicid': '',
'st': -1,
'z': '',
'ic': 0,
'word': keyword,
's': '',
'se': '',
'tab': '',
'width': '',
'height': '',
'face': 0,
'istype': 2,
'qc': '',
'nc': 1,
'fr': '',
'pn': i,
'rn': 30,
'gsm': '1e',
'1526377465547': ''
})
urls = []
for i in params:
group_datas = requests.get(url, params=i).json().get('data')
for data in group_datas:
if data != {}:
urls.append(data)
return urls
def get_thumbImg(datas, save_path):
'''
根據json列表,解析並下載圖片
:param datas:
:param save_path:
:return:
'''
for index,data in enumerate(datas):
try:
thumbURL = data.get('thumbURL')
dst_path = os.path.join(save_path,'thb_%d.jpg'%index)
urllib.request.urlretrieve(thumbURL, dst_path)
except:
pass
process_show(index+1,len(datas))
print()
def get_thumbImg_thread(datas, save_path):
'''
根據json列表,創建多個線程
:param datas:
:param save_path:
:return:
'''
num_sum = len(datas)
thd1 = get_thread(datas[:num_sum//2],save_path,1)
thd2 = get_thread(datas[num_sum // 2:], save_path,2,add_num=num_sum//2)
thd1.start()
thd2.start()
print()
def get_srcImg(datas, save_path):
'''
根據json列表,解析並下載圖片,有兩個URL地址,推薦第一個
:param datas:
:param save_path:
:return:
'''
for index,data in enumerate(datas):
#region method1
try:
objURL = baidimage_uncomplie(data.get('objURL'))
dst_path = os.path.join(save_path,'src_%d.jpg'% index)
urllib.request.urlretrieve(objURL, dst_path)
except:
pass
# endregion
#region method2
# try:
# objURL = data.get('replaceUrl')[1].get('ObjURL')
# dst_path = os.path.join(save_path, 'src_%d.jpg' % index)
# urllib.request.urlretrieve(objURL, dst_path)
# except:
# pass
#endregion
process_show(index+1,len(datas))
print()
#endregion
# region utils
class get_thread(threading.Thread):
'''
多線程下載
'''
def __init__(self,datas,save_path,num=0,add_num=0):
super(get_thread, self).__init__()
self.datas = datas
self.save_path = save_path
self.num = num
self.add_num = add_num
def run(self):
print('thread %d start:'%self.num)
for index, data in enumerate(self.datas):
try:
thumbURL = data.get('thumbURL')
dst_path = os.path.join(self.save_path, 'thb_%d.jpg' % (index+self.add_num))
urllib.request.urlretrieve(thumbURL, dst_path)
except:
pass
print('thread %d get %d/%d'%(self.num,index+1,len(self.datas)))
print('thread %d end:' % self.num)
def baidimage_uncomplie(url):
'''
百度圖片objURL解析
:param url:
:return:
'''
res = ''
c = ['_z2C$q', '_z&e3B', 'AzdH3F']
d= {'w':'a', 'k':'b', 'v':'c', '1':'d', 'j':'e', 'u':'f', '2':'g', 'i':'h', 't':'i', '3':'j', 'h':'k', 's':'l', '4':'m', 'g':'n', '5':'o', 'r':'p', 'q':'q', '6':'r', 'f':'s', 'p':'t', '7':'u', 'e':'v', 'o':'w', '8':'1', 'd':'2', 'n':'3', '9':'4', 'c':'5', 'm':'6', '0':'7', 'b':'8', 'l':'9', 'a':'0', '_z2C$q':':', '_z&e3B':'.', 'AzdH3F':'/'}
if(url==None or 'http' in url):
return url
else:
j= url
for m in c:
j=j.replace(m,d[m])
for char in j:
if re.match('^[a-w\d]+$',char):
char = d[char]
res= res+char
return res
def process_show(num, nums, pre_fix='', suf_fix=''):
'''
進度條顯示
:param num:
:param nums:
:param pre_fix:
:param suf_fix:
:return:
'''
rate = num / nums
ratenum = round(rate, 3) * 100
bar = '\r%s %g/%g [%s%s]%.1f%% %s' % \
(pre_fix, num, nums, '#' * (int(ratenum) // 5), '_' * (20 - (int(ratenum) // 5)), ratenum, suf_fix)
sys.stdout.write(bar)
sys.stdout.flush()
def clear_dir(root_path):
files_list = os.listdir(root_path)
for f in files_list:
file_path = os.path.join(root_path+f)
if os.path.isfile(file_path):
os.remove(file_path)
elif os.path.isdir(file_path):
clear_dir(file_path)
print('clear',root_path)
#endregion
if __name__ == '__main__':
pass
get_imgs(key_words)
過程說明
1)參考Ref1,在chrome中可以獲取到傳輸的json數據
2)人工從json數據中提取有效信息
json中有各種信息,需要的是url連接,但是url連接也有多種,根據key推測需要的是這幾個url
- 通過複製url在瀏覽器中打開,發現滴啊有img.tn.bdimg的地址一般爲縮略圖,使用thumbURL即可下載
- 在replaceURL中的1中的前2個objURL一般爲原始圖像URL。fromURL則表示原始圖像所在的網頁,無用。
- 進一步,發現在data中的objURL與fromURL有一定關係,但是不明確,推測爲加密後的URL,通過Ref2中的方法,可以將該URL轉爲可訪問URL,後續實驗表明該URL別上述URL更穩定,下載更快
3)下載代碼完善
由於objURL所在的服務器可能無法訪問,因此會出現超時現象,參考Ref3,使用socket.setdefaulttimeout(2)設置最長響應時間,使用try except結構跳過超時圖片
使用Thread自定義線程類,改寫run方法,可以實現在線程中批量下載圖片,使用多個線程可以加速下載,效果如下: