首頁 > 軟體

利用Python多執行緒實現圖片下載器

2022-03-25 19:00:46

導語

之前有很多小夥伴說想學習一下多執行緒圖片下載器,雖然好像已經過去很久了,不過還是上來安排一波吧。至於題目為什麼說是構建一個小型資料集,因為公眾號之後的文章應該還會用到它來構建一些簡單的影象分類資料集,換句話說,後續一段時間,公眾號會主要寫一些深度學習機器學習相關的文章,下期文章揭曉具體內容。

廢話不多說,讓我們愉快地開始近期最後一篇爬蟲文章~

開發工具

Python版本:3.7.8

相關模組:

requests模組;

alive-progress模組;

pyfreeproxy模組;

user_agent模組;

beautifulsoup4模組;

lxml模組;

以及一些python自帶的模組。

環境搭建

安裝Python並新增到環境變數,pip安裝需要的相關模組即可。

原理簡介

我看了下,發現大家基本都是從百度,必應和谷歌來根據給定的關鍵字下載相關的圖片資料的,所以我們也選用這三個資料來源。具體而言,百度的圖片搜尋介面如下:

'https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&lm=7&fp=result&ie=utf-8&oe=utf-8&st=-1&word={}&queryWord={}&face=0&pn={}&rn={}'

為了可以多執行緒地進行圖片搜尋,我們先根據想要下載的圖片數量來構造所有請求頁的連結如下:

search_urls, pagesize = [], 30
for pn in range(math.ceil(search_limits * 1.2 / pagesize)):
    search_url = base_url.format(quote(keyword), quote(keyword), pn * pagesize, pagesize)
    search_urls.append(search_url)

然後再多執行緒請求所有構造好的搜尋連結:

# 多執行緒請求獲取所有圖片連結
def searchapi(self, search_urls, image_urls, bar):
    while len(search_urls) > 0:
        search_url = search_urls.pop(0)
        response = self.get(search_url)
        if response is None: 
            bar()
            continue
        response.encoding = 'utf-8'
        response_json = json.loads(response.text.replace(r"'", ""), encoding='utf-8', strict=False)
        for item in response_json['data']:
            if 'objURL' in item.keys():
                image_urls.add(self.parseurl(item['objURL']))
            elif 'replaceUrl' in item.keys() and len(item['replaceUrl']) == 2:
                image_urls.add(item['replaceUrl'][1]['ObjURL'])
        bar()
task_pool, image_urls = [], set()
with alive_bar(min(len(search_urls), search_limits)) as bar:
    for idx in range(num_threadings):
        task = threading.Thread(
            target=searchapi,
            args=(self, search_urls, image_urls, bar)
        )
        task_pool.append(task)
        task.start()
    for task in task_pool: task.join()

執行緒結束的條件為我們構造的所有請求頁連結search_urls全部被用完。這裡我們用的最基本的python的threading庫,感覺python應該還有很多更加好用的多執行緒庫,感興趣的小夥伴可以自己查查資料,不必拘泥於我寫的內容。threading庫的話呼叫方便,只需要target指定目標函數,args指定目標函數輸入的引數,然後start一下就行,所以我圖省事就直接用它了。

類似地,我們也可以根據得到的image_urls寫個多執行緒的圖片下載器:

'''下載'''
def download(self, keyword, search_limits=1000, num_threadings=5, savedir='outputs'):
    touchdir(savedir)
    # 獲得image_urls
    self.logging(f'Start to search images from {self.source_name}')
    image_urls = self.search(keyword, search_limits, num_threadings)
    # 多執行緒下載圖片
    self.logging(f'Start to download images from {self.source_name}')
    def downloadapi(self, savepaths, image_urls, bar):
        assert len(savepaths) == len(image_urls)
        while len(image_urls) > 0:
            savepath, image_url = savepaths.pop(0), image_urls.pop(0)
            response = self.get(image_url)
            if response is None: 
                bar()
                continue
            with open(savepath, 'wb') as fp: fp.write(response.content)
            filetype = imghdr.what(savepath)
            if filetype in ['jpg', 'jpeg', 'png', 'bmp', 'gif']:
                savepath_correct = f'{savepath}.{filetype}'
                shutil.move(savepath, savepath_correct)
            else:
                os.remove(savepath)
            bar()
    task_pool, savepaths = [], []
    for idx in range(len(image_urls)):
        savename = f'image_{str(idx).zfill(8)}'
        savepaths.append(os.path.join(savedir, savename))
    with alive_bar(len(image_urls)) as bar:
        for idx in range(num_threadings):
            task = threading.Thread(
                target=downloadapi,
                args=(self, savepaths, image_urls, bar)
            )
            task_pool.append(task)
            task.start()
        for task in task_pool: task.join()

然後必應的圖片搜尋介面如下:

# 構建所有urls
base_url = 'https://cn.bing.com/images/async?q={}&first={}&count={}&cw=1536&ch=240&relp={}&tsc=ImageBasicHover&datsrc=I&layout=RowBased&mmasync=1&dgState=x*1063_y*768_h*186_c*5_i*71_r*10&IG=D6A4AD486F3A49F1BE164BC50750D641&SFX=3&iid=images.5555'
search_urls, pagesize = [], 35
for pn in range(math.ceil(search_limits * 1.2 / pagesize)):
    search_url = base_url.format(quote(keyword), pn * pagesize, pagesize, pagesize)
    search_urls.append(search_url)

谷歌的圖片搜尋介面如下:

# 構建所有urls
base_url = 'https://www.google.com/search?'
search_urls, pagesize = [], 20
for pn in range(math.ceil(search_limits * 1.2 / pagesize)):
    params = {
        'q': keyword,
        'ijn': pn,
        'start': pn * pagesize,
        'tbs': '',
        'tbm': 'isch',
    }
    search_urls.append(base_url + urlencode(params))

具體的多執行緒搜尋和下載圖片的寫法和百度的類似,大功告成啦。

效果展示

你只需要pip安裝一下,就可以直接在終端執行了。安裝命令如下:

pip install pyimagedl

使用方式如下:

Usage: imagedl [OPTIONS]

Options:
  --version                  Show the version and exit.
  -k, --keyword TEXT         想要搜尋下載的圖片關鍵字, 若不指定, 則進入imagedl終端版
  -s, --savedir TEXT         下載的圖片的儲存路徑
  -t, --target TEXT          指定圖片搜尋下載的平臺, 例如"baidu"
  -l, --limits INTEGER       下載的圖片數量
  -n, --nthreadings INTEGER  使用的執行緒數量
  --help                     Show this message and exit.

例如,在終端輸入:

imagedl -k 狗狗 -s dogs -t baidu -l 1000

到此這篇關於利用Python多執行緒實現圖片下載器的文章就介紹到這了,更多相關Python圖片下載內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com