PythonでWeb上の複数の画像を一括ダウンロード・保存

URLを指定して画像をダウンロード・保存

コード例 はじめに、URLと保存先のパスを指定して画像をダウンロード・保存する関数とその使い方のコード例を示す。 保存先のディレクトリを指定してURLのファイル名で画像を保存する場合はコメントアウトしている部分を参照。

import urllib.error
import urllib.request

def download_image(url, dst_path):
    try:
        data = urllib.request.urlopen(url).read()
        with open(dst_path, mode="wb") as f:
            f.write(data)
    except urllib.error.URLError as e:
        print(e)

url = 'https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png'
dst_path = 'data/src/lena_square.png'
# dst_dir = 'data/src'
# dst_path = os.path.join(dst_dir, os.path.basename(url))
download_image(url, dst_path)

urllib.request.urlopenでURLを開く

urllib.request.urlopenでURLを開く。なお、Python 2.6以前のurllib.urlopenは廃止されました。urllib.request.urlretrieveはまだ廃止されていないが、将来的に廃止される可能性があります。

21.6. urllib.request — URL を開くための拡張可能なライブラリ — Python 3.6.3 ドキュメント

例外が発生しても止まらないように、try, exceptでエラーを捕捉しています。このときurllib.errorをimportするのを忘れないように気をつけてください。 エラーがある場合はメッセージが表示されます。

error_url = 'https://upload.wikimedia.org/wikipedia/en/2/24/Lenna_xxx.png'
download_image(error_url, dst_path)
# HTTP Error 404: Not Found

標準ライブラリのurllibではなくサードパーティライブラリのRequestsを使ってurlを開いてデータを取得することもできます。Requestsのほうがシンプルに書けます。

バイナリモードでファイルに書き込み

mode='wb'でバイナリとして書き込む。wが書き込み、bがバイナリの意味。 open()によるファイルの読み書きについては

Webページの画像のURLを抽出

連番になっている場合

ダウンロードしたい画像のURLが単純な連番になっている場合は簡単。連番に限らず何らかの規則性があれば、後述のBeautiful Soupなどでスクレイピングをするより、規則に従ってURLのリストを作ってしまったほうが楽。

url_list = []
for i in range(5):
    url = 'http://example.com/basedir/base_{:03}.jpg'.format(i)
    url_list.append(url)

上の例では{:03}で3桁の0埋め連番としています。0埋めの必要が無い場合は{}、3桁ではなく例えば5桁の場合は{:05}とすればOKです。文字列strのformatメソッドについては、以下も参照。

Pythonのformatでゼロ埋めや16進数などを出力

Beautiful Soupで抽出

Webページの画像URLを一括で抽出するにはBeautiful Soupを使います。

from bs4 import BeautifulSoup

url = 'https://news.yahoo.co.jp/photo/'
ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) '\
     'AppleWebKit/537.36 (KHTML, like Gecko) '\
     'Chrome/55.0.2883.95 Safari/537.36 '

req = urllib.request.Request(url, headers={'User-Agent': ua})
html = urllib.request.urlopen(req)

soup = BeautifulSoup(html, "html.parser")

img_list = soup.find(class_='headline').find_all('img')
url_list = []
for img in img_list:
    url_list.append(img.get('src'))

例ではYahoo!ニュースの写真トップの画像のURLを抽出しています。 Webページによって構成は異なるが、基本的には

classやidなどを指定して、ダウンロードしたいタグのオブジェクトのリストを取得 soup.find(class_='headline').find_all('img')の部分 タグのsrc要素から画像のURLを取得 img.get('src')という流れになります。 Beautiful Soupについては以下の記事も参照。

Python, Beautiful Soupでスクレイピング、Yahooのヘッドライン抽出

URLのリストから複数画像を一括ダウンロード・保存

URLのリストがあれば、forループで回して、最初に示したURLを指定して画像をダウンロード・保存する関数を呼び出すだけです。(仮のURLリストのため、ここでは関数download_image()はコメントアウトしている)

download_dir = 'temp/dir'
sleep_time_sec = 1

for url in url_list:
    filename = os.path.basename(url)
    dst_path = os.path.join(download_dir, filename)
    time.sleep(sleep_time_sec)
    print(url, dst_path)
    # download_image(url, dst_path)

この例では、URLから画像ファイルの名前を取得して、その名前で任意のディレクトリに保存しています。osモジュールをimportして使っています。 また、サーバーに負担をかけないように、画像を1枚ダウンロードするごとにtime.sleep()で待機時間をつくっています。単位は秒なので、上の例では1秒ずつスリープ。timeモジュールをimportして使います。

Last Updated: 6/26/2019, 10:34:03 PM