您好,登錄后才能下訂單哦!
本文小編為大家詳細介紹“Python如何多線程并發下載圖片”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Python如何多線程并發下載圖片”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
這就是我們最終要構建的效果。
讓我們安裝每個人最喜歡的 requests 庫。
pip install requests
現在,我們將看到一些用于下載單個 URL 并嘗試自動查找圖像名稱以及如何使用重試的基本代碼。
import requests res = requests.get(img_url, stream=True) count = 1 while res.status_code != 200 and count <= 5: res = requests.get(img_url, stream=True) print(f'Retry: {count} {img_url}') count += 1
在這里,我們重試下載圖像五次,以防失敗。現在,讓我們嘗試自動找到圖像的名稱并保存它。
import more required library import io from PIL import Image # lets try to find the image name image_name = str(img_url[(img_url.rfind('/')) + 1:]) if '?' in image_name: image_name = image_name[:image_name.find('?')]
假設我們要下載的 URL 是:
instagram.fktm7-1.fna.fbcdn.net/vp...
好吧,這是一團糟。讓我們分解一下代碼對 URL 的作用。我們首先使用 rfind
找到最后一個正斜杠(/
),然后選擇之后的所有內容。這是結果:
65872070_1200425330158967_6201268309743367902_n.jpg?_nc_ht=instagram.fktm7–1.fna.fbcdn.net&_nc_cat=111
現在我們的第二部分找到一個 ?
,然后只取它前面的任何東西。
這是我們最終的圖像名稱:
65872070_1200425330158967_6201268309743367902_n.jpg
這個結果非常好,適用于大多數用例。
現在我們已經下載了圖像名稱和圖像,我們將保存它。
i = Image.open(io.BytesIO(res.content)) i.save(image_name)
如果你在想,「我到底應該怎么使用上面的代碼?」那么你的想法是正確的。這是一個漂亮的函數,我們在上面所做的一切都被扁平處理了。在這里,我們還測試了下載的類型是否為圖像,以防找不到圖像名稱。
def image_downloader(img_url: str): """ Input: param: img_url str (Image url) Tries to download the image url and use name provided in headers. Else it randomly picks a name """ print(f'Downloading: {img_url}') res = requests.get(img_url, stream=True) count = 1 while res.status_code != 200 and count <= 5: res = requests.get(img_url, stream=True) print(f'Retry: {count} {img_url}') count += 1 # checking the type for image if 'image' not in res.headers.get("content-type", ''): print('ERROR: URL doesnot appear to be an image') return False # Trying to red image name from response headers try: image_name = str(img_url[(img_url.rfind('/')) + 1:]) if '?' in image_name: image_name = image_name[:image_name.find('?')] except: image_name = str(random.randint(11111, 99999))+'.jpg' i = Image.open(io.BytesIO(res.content)) download_location = 'cats' i.save(download_location + '/'+image_name) return f'Download complete: {img_url}'
現在,你可能會問:「這個人所說的多處理在哪里?」。
這很簡單。我們將簡單地定義我們的池并將我們的函數和圖像 URL 傳遞給它。
results = ThreadPool(process).imap_unordered(image_downloader, images_url) for r in results: print(r)
讓我們把它放在一個函數中:
def run_downloader(process:int, images_url:list): """ Inputs: process: (int) number of process to run images_url:(list) list of images url """ print(f'MESSAGE: Running {process} process') results = ThreadPool(process).imap_unordered(image_downloader, images_url) for r in results: print(r)
再一次,你可能會說,「這一切都很好,但我想立即開始下載我的 1000 張圖像列表。我不想復制和粘貼所有這些代碼并試圖弄清楚如何合并所有內容。」
這是一個完整的腳本。它執行以下操作:
以圖像列表文本文件和進程號作為輸入
按照您想要的速度下載它們
打印下載文件的總時間
還有一些不錯的函數可以幫助我們讀取文件名并處理錯誤和其他東西
# -*- coding: utf-8 -*- import io import random import shutil import sys from multiprocessing.pool import ThreadPool import pathlib import requests from PIL import Image import time start = time.time() def get_download_location(): try: url_input = sys.argv[1] except IndexError: print('ERROR: Please provide the txt file\n$python image_downloader.py cats.txt') name = url_input.split('.')[0] pathlib.Path(name).mkdir(parents=True, exist_ok=True) return name def get_urls(): """ 通過讀取終端中作為參數提供的 txt 文件返回 url 列表 """ try: url_input = sys.argv[1] except IndexError: print('ERROR: Please provide the txt file\n Example \n\n$python image_downloader.py dogs.txt \n\n') sys.exit() with open(url_input, 'r') as f: images_url = f.read().splitlines() print('{} Images detected'.format(len(images_url))) return images_url def image_downloader(img_url: str): """ 輸入選項: 參數: img_url str (Image url) 嘗試下載圖像 url 并使用標題中提供的名稱。否則它會隨機選擇一個名字 """ print(f'Downloading: {img_url}') res = requests.get(img_url, stream=True) count = 1 while res.status_code != 200 and count <= 5: res = requests.get(img_url, stream=True) print(f'Retry: {count} {img_url}') count += 1 # checking the type for image if 'image' not in res.headers.get("content-type", ''): print('ERROR: URL doesnot appear to be an image') return False # Trying to red image name from response headers try: image_name = str(img_url[(img_url.rfind('/')) + 1:]) if '?' in image_name: image_name = image_name[:image_name.find('?')] except: image_name = str(random.randint(11111, 99999))+'.jpg' i = Image.open(io.BytesIO(res.content)) download_location = get_download_location() i.save(download_location + '/'+image_name) return f'Download complete: {img_url}' def run_downloader(process:int, images_url:list): """ 輸入項: process: (int) number of process to run images_url:(list) list of images url """ print(f'MESSAGE: Running {process} process') results = ThreadPool(process).imap_unordered(image_downloader, images_url) for r in results: print(r) try: num_process = int(sys.argv[2]) except: num_process = 10 images_url = get_urls() run_downloader(num_process, images_url) end = time.time() print('Time taken to download {}'.format(len(get_urls()))) print(end - start)
將其保存到 Python 文件中,然后運行它。
python3 image_downloader.py cats.txt
這是 GitHub 存儲庫的鏈接。
python3 image_downloader.py <filename_with_urls_seperated_by_newline.txt> <num_of_process>
這將讀取文本文件中的所有 URL,并將它們下載到名稱與文件名相同的文件夾中。
num_of_process
是可選的(默認情況下,它使用 10 個進程)。
python3 image_downloader.py cats.txt
讀到這里,這篇“Python如何多線程并發下載圖片”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。