このブログではPythonを使ったスクレイピングを、初心者向けにサンプルコード付きで解説しています。以下に紹介する記事では、①から⑨のステップでスクレイピングの方法を学び、実践に役立てられるよう体系的にまとめています。
【①〜⑨まとめ】PythonでWebスクレイピングを実践する方法【サンプルコード付き】
このブログではPythonスクレイピングを初心者向けに解説していきます。順番に各記事で解説しており入門者向けです。サンプルコード付きで解説するので実践的…
スクレイピングする際、テキストデータだけではなく画像データを取得したい場合もあるかと思います。
この記事では画像を一括取得し、ローカルに自動ダウンロードする方法を紹介しています。
以下で解説する関数を利用することで、ローカルに画像をまとめてダウンロードすることができます。
サンプルコード全文
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
import requests from bs4 import BeautifulSoup from urllib.parse import urljoin import os # サイト名を指定、これがフォルダ名になる folder_name = "test_folder" # フォルダのパスを指定 location_path = "/path/to/your/directory" # 画像が相対パスの場合に設定する(不要な場合はNoneを設定) base_url = 'https://scraping-for-beginner.herokuapp.com/' # 画像ダウンロード関数 def download_image(img_urls, contents_title, base_url= base_url, min_image_size_kb=1): min_image_size_bytes = min_image_size_kb * 1024 # キロバイトからバイトに変換 # フォルダのパスを作成 folder_path = os.path.join(location_path, folder_name, contents_title) # フォルダが存在しない場合は作成する os.makedirs(folder_path, exist_ok=True) for i, img_url in enumerate(img_urls, 1): # フォルダのパスを作成 # 連番を1から始めるためにiを使用、拡張子も取得 img_name = f"image_{i}{os.path.splitext(img_url)[1]}" img_path = os.path.join(folder_path, img_name) # URLが相対パスの場合、フルURLに変換 if base_url and not img_url.startswith(('http://', 'https://')): img_url = urljoin(base_url, img_url) # URLがhttpまたはhttpsで始まるかどうかをチェック if img_url.startswith(('http://', 'https://')): try: image_response = requests.get(img_url, stream=True) image_response.raise_for_status() # ステータスコードが200以外の場合に例外を発生させる image_data = image_response.content # 画像のバイトデータを取得 # 画像のバイトデータのサイズが閾値より大きいかどうかを確認 if len(image_data) >= min_image_size_bytes: with open(img_path, 'wb') as file: for chunk in image_response.iter_content(1024): file.write(chunk) #print(f"Successfully downloaded image: {img_url}") else: print(f"Skipped image download due to small size: {img_url}") except requests.RequestException as e: print(f"Failed to download image: {img_url}, error: {e}") else: print(f"Skipped non-http URL: {img_url}") link = 'https://scraping-for-beginner.herokuapp.com/ranking/?page=1' def get_contents_from_link(link): webpage_response = requests.get(link) webpage_content = webpage_response.content webpage_soup = BeautifulSoup(webpage_content, "html.parser") # img要素から画像のURLを取得 img_urls = [] img_urls_set = set() # 重複除外するため contents_title = webpage_soup.select_one("title").text.strip() # 除外したい要素を特定 target_elements = webpage_soup.select('#mybox img') img_tags = webpage_soup.select('img') for target_element in target_elements: if target_element in img_tags: img_tags.remove(target_element) for img in img_tags: img_src = img.get('src') if img_src: img_urls_set.add(img_src) img_urls = list(img_urls_set) download_image(img_urls, contents_title) get_contents_from_link(link) |
以下でコードを解説していきます。
必要なライブラリのインポート
1 2 3 4 |
import requests from bs4 import BeautifulSoup from urllib.parse import urljoin import os |
urljoin: 相対URLを絶対URLに変換するための関数。
os: ファイルやディレクトリの操作を行うためのライブラリ。
基本設定
ダウンロード先のフォルダ名やパス、画像のベースURLを設定します。
1 2 3 |
folder_name = "test_folder" location_path = "/path/to/your/directory" base_url = 'https://scraping-for-beginner.herokuapp.com/' |
フォルダ名やパスには任意のものを設定してください。
base_url ですが、スクレイピング時に取得するimg srcが相対パスであれば、このbase_urlを設定します。
絶対パスの場合、base_urlにはNoneを設定します。
画像ダウンロード関数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# 画像ダウンロード関数 def download_image(img_urls, contents_title, base_url= base_url, min_image_size_kb=1): min_image_size_bytes = min_image_size_kb * 1024 # キロバイトからバイトに変換 # フォルダのパスを作成 folder_path = os.path.join(location_path, folder_name, contents_title) # フォルダが存在しない場合は作成する os.makedirs(folder_path, exist_ok=True) for i, img_url in enumerate(img_urls, 1): # フォルダのパスを作成 # 連番を1から始めるためにiを使用、拡張子も取得 img_name = f"image_{i}{os.path.splitext(img_url)[1]}" img_path = os.path.join(folder_path, img_name) # URLが相対パスの場合、フルURLに変換 if base_url and not img_url.startswith(('http://', 'https://')): img_url = urljoin(base_url, img_url) # URLがhttpまたはhttpsで始まるかどうかをチェック if img_url.startswith(('http://', 'https://')): try: image_response = requests.get(img_url, stream=True) image_response.raise_for_status() # ステータスコードが200以外の場合に例外を発生させる image_data = image_response.content # 画像のバイトデータを取得 # 画像のバイトデータのサイズが閾値より大きいかどうかを確認 if len(image_data) >= min_image_size_bytes: with open(img_path, 'wb') as file: for chunk in image_response.iter_content(1024): file.write(chunk) #print(f"Successfully downloaded image: {img_url}") else: print(f"Skipped image download due to small size: {img_url}") except requests.RequestException as e: print(f"Failed to download image: {img_url}, error: {e}") else: print(f"Skipped non-http URL: {img_url}") |
・フォルダ作成: 指定されたフォルダが存在しない場合は作成します。画像の名前には、image_1,image_2のように連番を振ります。
・画像のダウンロード: 画像のURLがHTTPまたはHTTPSで始まる場合、リクエストを送信し画像データを取得します。サイズが閾値以上の場合にのみ保存します。
ここではmin_image_size_bytesを使い、不要な画像のダウンロードを防いでいます。ウェブサイトにはアイコンなど小さい画像が複数あり、それらは不要だったりします。ここでは1キロバイト以下の画像は除外するようにしています。必要に応じて調整してください。
ウェブページからのコンテンツ取得
get_contents_from_link関数は、指定したURLからコンテンツを取得し、画像のURLを抽出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
link = 'https://scraping-for-beginner.herokuapp.com/ranking/?page=1' def get_contents_from_link(link): webpage_response = requests.get(link) webpage_content = webpage_response.content webpage_soup = BeautifulSoup(webpage_content, "html.parser") # img要素から画像のURLを取得 img_urls = [] img_urls_set = set() # 重複除外するため contents_title = webpage_soup.select_one("title").text.strip() # 除外したい要素を特定 target_elements = webpage_soup.select('#mybox img') img_tags = webpage_soup.select('img') for target_element in target_elements: if target_element in img_tags: img_tags.remove(target_element) for img in img_tags: img_src = img.get('src') if img_src: img_urls_set.add(img_src) img_urls = list(img_urls_set) download_image(img_urls, contents_title) |
・ウェブページの取得: 指定したリンクからHTMLコンテンツを取得します。
・画像URLの抽出: <img>要素から画像URLを収集し、重複を排除します。
ここでは.removeを使って、不要な画像を除去しています。もし不要な画像がクラス名で特定できる場合、target_elementsに指定することで削除できます。
なおここでは、取得した画像が格納されるフォルダ名には以下のようにtitle要素を指定しています。
1 |
contents_title = webpage_soup.select_one("title").text.strip() |
このように、タイトルや見出しなどを指定することはできるのですが、例えば\ (バックスラッシュ)や: (コロン)などファイル名に使用できない文字列が要素に含まれている可能性があります。
以下の記事ではファイル名に適さない文字列を削除する関数について解説しています。
⑦ Pythonでファイル名に適さない文字を一括削除・置換する方法を解説【サンプルコード】
このブログではPythonを使ったスクレイピングを、初心者向けにサンプルコード付きで解説しています。以下に紹介する記事では、①から⑨のステップでスクレイピ…
関数の実行
1 |
get_contents_from_link(link) |
これで画像をダウンロードできます。
まとめ
今回紹介した画像ダウンロード関数を使用することで、ページ内にある全てのimg要素を取得することができます。また、アイコンなどの小さい画像を除外し、不要な画像を指定して削除する機能も付けています。
今回は単一のページをスクレイピングしていますが、複数のページに渡ってまとめてスクレイピングすることもできます。詳しくは以下の記事を参照ください。
④Pythonで複数ページをまとめてスクレイピングする方法を解説【サンプルコード】
このブログではPythonを使ったスクレイピングを、初心者向けにサンプルコード付きで解説しています。以下に紹介する記事では、①から⑨のステップでスクレイピ…