python批量、動態爬取百度圖片的原圖、縮略圖

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方法,可以實現在線程中批量下載圖片,使用多個線程可以加速下載,效果如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章