爬取後同時下載多張圖片
這篇文章會使用 Python 的 Requests 和 Beautiful Soup 函式庫,搭配 concurrent.futures 內建函式庫,實作一個可以同時且自動下載圖片的網路爬蟲。
本篇使用的 Python 版本為 3.7.12,所有範例可使用 Google Colab 實作,不用安裝任何軟體 ( 參考:使用 Google Colab )
使用「自動下載 PTT 正妹圖片」範例程式
在「自動下載 PTT 正妹圖片」文章中,已經介紹過如何自動下載圖片,這篇教學將從這個範例延伸,將原本「一張一張依序下載」的圖片,改成「同時」下載,就能大幅減少下載時間,將下方的程式複製貼上到 Colab、Jupyter 或自己的編輯器中。
import requests
from bs4 import BeautifulSoup
web = requests.get('https://www.ptt.cc/bbs/Beauty/M.1638380033.A.7C7.html', cookies={'over18':'1'})
soup = BeautifulSoup(web.text, "html.parser")
imgs = soup.find_all('img')
name = 0
for i in imgs:
print(i['src'])
jpg = requests.get(i['src'])
f = open(f'content/drive/MyDrive/Colab Notebooks/download/test_{name}.jpg', 'wb')
f.write(jpg.content)
f.close()
name = name + 1
使用 concurrent.futures
使用 concurrent.futures 內建函式庫,將原本的程式,從「同步」改為「非同步」執行,由於在使用「多執行緒」時如果搭配全域變數,會發生記憶體位置重疊的失敗狀況,為了避免這種狀況,在取得圖片網址時,先一併將名稱編號設定好,最後再將編號提供給執行緒處理即可。
import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor # 加入 concurrent.futures 內建函式庫
web = requests.get('https://www.ptt.cc/bbs/Beauty/M.1638380033.A.7C7.html', cookies={'over18':'1'})
soup = BeautifulSoup(web.text, "html.parser")
imgs = soup.find_all('img')
name = 0
img_urls = [] # 根據爬取的資料,建立一個圖片名稱與網址的空串列
for i in imgs: # 修改 for 迴圈內容
img_urls.append([i['src'], name]) # 將圖片網址與編號加入串列中
name = name + 1 # 編號增加 1
def download(url): # 編輯下載函式
print(url) # 印出網址
jpg = requests.get(url[0]) # 使用 requests.get 取得圖片資訊
f = open(f'download/test_{url[1]}.jpg', 'wb') # 將圖片開啟為二進位格式 ( 請自行修改存取路徑 )
f.write(jpg.content) # 存取圖片
f.close()
executor = ThreadPoolExecutor() # 建立非同步的多執行緒的啟動器
with ThreadPoolExecutor() as executor:
executor.map(download, img_urls) # 同時下載圖片
程式執行後,就會看見圖片「幾乎同時」下載到電腦裡。
如果使用 Colab 就會下載到雲端硬碟指定的資料夾裡。
小結
如果要用爬蟲下載大量圖片,使用「非同步」( 多執行緒平行處理 ) 的方式是相當方便的做法,不僅不用一張張的等待,更能發揮閒置 CPU 最大的效益 ( 同一時間裡可以做很多事情 )。
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~