note.nkmk.me

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はまだ廃止されていないが、将来的に廃止される可能性がある。

例外が発生しても止まらないように、try, exceptでエラーを捕捉している。このときurllib.errorimportするのを忘れないように注意。

エラーがある場合はメッセージが表示される。

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}とすればよい。文字列strformatメソッドについては、以下も参照。

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ページによって構成は異なるが、基本的には

  • classidなどを指定して、ダウンロードしたい<img>タグのオブジェクトのリストを取得
    • soup.find(class_='headline').find_all('img')の部分
  • <img>タグのsrc要素から画像のURLを取得
    • img.get('src')

という流れになる。

Beautiful Soupについては以下の記事も参照。

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して使う。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事