画像のスクレイピングを自分のブログサイトhttps://py.k-hp.com/test/に置き換えて実行したのですが、以下のエラーが出ました。
画像のスクレイピングエラー
PS C:\Users\DELL\OneDrive\Python\本python&excel\Chapter7\s057> cd “c:/Users/DELL/OneDrive/Python/本python&excel/Chapter7/s057g”
PS C:\Users\DELL\OneDrive\Python\本python&excel\Chapter7\s057g> & C:/Users/DELL/AppData/Local/Programs/Python/Python313/python.exe “c:/Users/DELL/OneDrive/Python/本python&excel/Chapter7/s057g/booklist_img.py”
Traceback (most recent call last):
File “c:\Users\DELL\OneDrive\Python\本python&excel\Chapter7\s057g\booklist_img.py”, line 19, in <module>
image_url = parse.urljoin(url, bs4img[0][“src”])
IndexError: list index out of range
PS C:\Users\DELL\OneDrive\Python\本python&excel\Chapter7\s057g>
対策
今回も IndexError: list index out of range が出た理由は、ブログサイト(https://py.k-hp.com/test/)の構造が、プログラムで指定している条件(セレクタ)と一致せず、画像が見つからなかったためです。
サイトを拝見したところ、2025年12月現在のHTML構造に合わせて画像を正しく取得するには、以下の修正が必要です。
1. セレクタの修正
ブログ内の画像(書籍の表紙など)を取得する場合、多くのブログでは画像が記事エリア(article)や特定のクラスの中にあります。このテストサイトの場合、img タグを直接指定するか、より確実に取得できるセレクタに変更します。
修正箇所(13行目付近)
誤(前のサイト用):
python
bs4img = soup.select(“section img”)
正(現在のブログサイト用):
python
# サイト内のすべての画像を取得、あるいは記事内の画像に絞る
bs4img = soup.select(“img”)
2. なぜエラーになったのか?(解説)
ご自身のブログサイトには #module-bs4 というIDや、特定の section 構造が存在しなかったため、bs4img というリストが 空(0件) になっていました。
その状態で bs4img[0](1番目を取り出せ)と命令したため、「存在しない番号を指定した」というエラー(IndexError)が発生しました。
3. 解決後の完全なコード例
画像が見つからなかった場合にエラーで止まらないよう、安全策(if文)を入れたコードです。
python
# ...(前略)
bs4img = soup.select("img") # ここを修正
if bs4img: # 画像が1枚以上見つかった場合のみ実行
# 0番目(最初の画像)のsrc属性を取得
image_url = parse.urljoin(url, bs4img[0]["src"])
ws["A1"] = image_url
image_r = requests.get(image_url)
image = Image(BytesIO(image_r.content))
image.width = 80
image.height = 120
ws.add_image(image, ws["B1"].coordinate)
print(f"画像を保存しました: {image_url}")
else:
print("画像が見つかりませんでした。URLやセレクタを確認してください。")
wb.save("画像.xlsx")
補足:自分のサイトで試すときのコツ
自分のサイトをスクレイピングする場合、どの画像を取得したいかによって指定を変えるのがコツです。
全部の画像: soup.select(“img”)
特定のクラスの画像: soup.select(“.example-class img”)
ID指定: soup.select(“#example-id img”)
print(len(bs4img)) と1行入れるだけで、実行時に「何枚見つかったか」を確認できるので、デバッグが楽になりますよ!
2枚目の画像を取得するには
全部の画像: soup.select(“img”)でうまく行きました。でも画像は一番上のヘッダー画像1枚のみの取得でした。下の2枚目も取得するにはどうしたらいいですか?
2枚目以降の画像も取得してExcelに並べるには、プログラムを「1枚だけ処理する(bs4img[0])」書き方から、「見つかった分だけ繰り返す(forループ)」書き方に変更する必要があります。
2025年現在、複数の画像をExcelに縦に並べていくための具体的な修正案は以下の通りです。
修正後のプログラム
python
# ...(前略:Workbookの作成、列幅の設定まで)
ws.column_dimensions["A"].width = 60
ws.column_dimensions["B"].width = 30
# すべてのimgタグを取得
bs4img = soup.select("img")
# 画像を貼り付ける「行番号」の初期値
current_row = 1
for img_tag in bs4img:
try:
# 画像のURLを組み立て
src = img_tag.get("src")
if not src: continue
image_url = parse.urljoin(url, src)
# A列にURLを記入
ws[f"A{current_row}"] = image_url
# 画像をダウンロード
image_r = requests.get(image_url)
image = Image(BytesIO(image_r.content))
# 画像のサイズ調整
image.width = 160 # 少し大きくしてみました
image.height = 120
# B列の現在の行に画像を貼り付け
# 例:B1, B2, B3... と順番に指定
cell_address = f"B{current_row}"
ws.add_image(image, cell_address)
# 次の画像のために行番号を増やす
# Excelの行の高さも画像に合わせて調整(任意)
ws.row_dimensions[current_row].height = 100
current_row += 1
print(f"{cell_address} に保存成功: {image_url}")
except Exception as e:
print(f"スキップ(エラー): {e}")
wb.save("全画像リスト.xlsx")
修正のポイント
for img_tag in bs4img::
見つかった画像リスト(bs4img)を、上から順番に一つずつ img_tag という名前で取り出して処理します。
current_row(行番号)の使用:
bs4img[0] のように数字を固定せず、current_row という変数を作って、1回処理が終わるたびに +1 していくことで、Excelの1行目、2行目、3行目…と順番に書き込めます。
f”B{current_row}”:
「f文字列(エフ・ストリング)」という2025年現在最も推奨される書き方です。current_row が 1 なら “B1″、2 なら “B2” に自動的に変換されます。
try…except(エラー回避):
Webサイトには時々「壊れた画像データ」や「取得できない形式」が混ざっています。これを入れておくことで、1枚失敗しても途中で止まらずに最後まで実行できるようになります。
実行結果
これを実行すると、ExcelのA列にURLがズラリと並び、B列にそのサイトで使われているすべての画像(ロゴ、ヘッダー、記事中の写真など)が縦に並んで表示されるはずです。ぜひ試してみてください!
2枚目の画像のみを取り出すようにするには?
2枚目の画像「だけ」を取り出したい場合は、リストのインデックス(添え字)を [1] に指定します。
プログラミングの世界では、順番を 0, 1, 2… と数えるため、以下のようになります。
bs4img[0] : 1枚目(ヘッダー画像など)
bs4img[1] : 2枚目(目的の画像)
修正方法
19行目付近の、画像URLを組み立てる部分を以下のように書き換えてください。
python
# 2枚目(インデックス1)の画像URLを取得
image_url = parse.urljoin(url, bs4img[1][“src”])
コードは注意してご使用ください。
エラーを防ぐための安全な書き方
もし画像が1枚しかなかった場合に、再び IndexError で止まるのを防ぐため、以下のように「2枚以上あるか」を確認する条件を入れるのが2025年現在のプロレベルの書き方です。
python
# imgタグをすべて取得
bs4img = soup.select("img")
# 画像が2枚以上存在するかチェック
if len(bs4img) >= 2:
# 2枚目(インデックス1)を指定
target_img = bs4img[1]
image_url = parse.urljoin(url, target_img["src"])
ws["A1"] = image_url
image_r = requests.get(image_url)
image = Image(BytesIO(image_r.content))
# ...(以下、画像のサイズ調整と保存の処理)
ws.add_image(image, "B1")
print(f"2枚目の画像を保存しました: {image_url}")
else:
print("画像が2枚見つかりませんでした。")
なぜ [1] なのか?
Pythonのリスト(配列)は、「0番目から数え始める」というルールがあります。
bs4img[0] → 1番目の要素
bs4img[1] → 2番目の要素
これで、ヘッダー画像を飛ばして、その下にある目的の画像だけをピンポイントでExcelに取り込むことができます。
2枚目の画像抽出OK
2枚目の画像取得うまく行きました。全画像についてはIF命令をもう少し勉強してからやってみたいと思います。ありがとうございました。
2枚目の画像取得の成功、おめでとうございます!「0番ではなく1番を指定する」というリストの仕組みをマスターされましたね。
全画像の取得に挑戦される際の「IF命令(条件分岐)」と「FOR命令(繰り返し)」は、Pythonの自動化において最も強力な武器になります。これが使えるようになると、100枚の画像も、数千行のデータも一瞬で処理できるようになります。
2025年の学習において、次に進むためのヒントを少しだけ置いておきます。
IF命令: 「もし画像があったら実行する(なければスキップ)」という安全装置になります。
FOR命令: 「見つかった数だけ同じ作業を繰り返す」という自動化の心臓部です。
ご自身のブログサイト(py.k-hp.com)は、ご自身で構造を自由に変えられる最高の練習台です。まずは今回の「2枚目取得」を確実に自分のものにしてから、ゆっくりとステップアップしていってください。
また疑問が出てきたときは、いつでもお気軽にご相談ください。Python学習、応援しています!



コメント