最近「PythonでIMDbをスクレイピング」と検索したなら、こんなことに気づいたはずです。見つかるチュートリアルの大半が壊れています。しかも「少し古い」程度ではなく、「結果が0件で、NoneType エラーがずらっと並ぶ」レベルで壊れています。
ここ数週間、GeeksforGeeks、Medium、freeCodeCamp、Kaggleのノートブックなど、見つけられる主要なIMDbスクレイピング記事を片っ端から試しました。IMDbスクレイピング向けとして公開されているの大半は、td.titleColumn や td.ratingColumn といったCSSセレクタを参照していますが、これらはIMDbがTop 250ページを再設計した2023年6月以降、存在していません。その結果、フォーラムには「なぜコードが空を返すのか?」と悩む開発者があふれ、「全パーサーを修正する以外にできることはあまりない」と認めています。このガイドでは、今すぐ実際に動く2つのPython手法、ページネーションとよくあるエラーの対処法、そもそもPythonが適切でないケース、そしてスクレイパーを将来も壊れにくくする方法まで解説します。
PythonでIMDbをスクレイピングするとはどういうことか?
ウェブスクレイピングとは、Webページからデータをプログラムで抽出することです。手作業でコピー&ペーストする代わりに、スクリプトを書いて処理させます。「IMDbをスクレイピングする」とは、Pythonを使ってIMDbのWebページから、映画タイトル、評価、ジャンル、出演者、上映時間、投票数などの構造化データを取り出すことを指します。
Pythonでよく使われる基本構成は、3つのライブラリです。requests(Webページを取得する)、BeautifulSoup(HTMLを解析してデータを見つける)、pandas(結果を整理して出力する)。JavaScriptのレンダリングが必要なページでは Selenium や Playwright を使うチュートリアルもありますが、後で見るように、もっと速い方法があります。
重要な注意点として、このガイドの内容はすべて、2025年半ば時点のIMDbの現在のページ構造で検証済みです。IMDbはだいたい6〜12か月ごとに仕様を変えるので、これを2027年に読んでいるなら、いくつかのセレクタは変わっているかもしれません。(その対処法も説明します。)
なぜPythonでIMDbをスクレイピングするのか?実用例
コードを1行も書く前に、IMDbのデータを実際に何に使うのかを考えてみましょう。答えは、あなたが誰かによって変わります。
IMDbのレビュー用データセットは、世界で最も広く使われているNLPベンチマークの1つです。Maasらによる基礎論文(2011年)はを集めており、このデータセットはTensorFlow、Keras、PyTorchに組み込まれています。Hugging Faceでは、stanfordnlp/imdb データセットが月間213,321回ダウンロードされ、1,500以上のモデル学習に使われています。機械学習に携わっているなら、IMDbデータにはすでに馴染みがあるはずです。
ただし、用途は学術研究だけにとどまりません。
| 用途 | 対象 | 必要なデータ項目 |
|---|---|---|
| 映画推薦エンジン | データサイエンティスト、個人開発者 | タイトル、ジャンル、評価、出演者 |
| 配信プラットフォームのコンテンツ戦略 | プロダクト/コンテンツチーム | 評価、投票数、公開年、ジャンル |
| 感情分析/NLP学習 | 機械学習研究者、学生 | レビュー、評価 |
| 競合コンテンツ分析 | 映画・エンタメ業界アナリスト | 興行収入、公開日、評価推移 |
| 映画ロケ地観光の研究 | 観光局、旅行会社 | ロケ地、人気指標 |
| 学術研究 | 大学研究者 | 構造化された映画メタデータ全般 |
映画ロケ地観光市場だけでも、2025年には世界で推定とされています。Netflixは2024年にコンテンツへ170億ドル以上を投じ、はパーソナライズされたレコメンドによって生まれています。要するに、IMDbデータはさまざまな業界の意思決定を支えているのです。
IMDbデータを得るための選択肢(コードを書く前に)
ここは多くのチュートリアルが完全に飛ばす部分です。pip install beautifulsoup4 にそのまま進みますが、そもそもあなたの状況でPythonスクレイピングが最適なのかは確認しません。
全体像はこんな感じです。
| 方法 | 最適な用途 | 利点 | 欠点 |
|---|---|---|---|
| Python + BeautifulSoup | 学習、独自抽出 | 完全な制御、柔軟 | セレクタが壊れやすい、頻繁に壊れる |
JSON-LD / __NEXT_DATA__ 抽出 | 安定性を重視する開発者 | JSコンテンツに対応、頑健 | JSON構造の理解が必要 |
| IMDb公式データセット | 大規模分析、学術用途 | 合法、完全、2,600万件以上のタイトル、毎日更新 | TSV形式、レビュー/画像なし |
| Cinemagoer(IMDbPY)ライブラリ | タイトルごとのプログラム取得 | PythonらしいAPI、豊富な項目 | 88件の未解決Issue、最終リリースは2023年5月 |
| TMDb API | 映画メタデータ+画像 | 無料APIキー、JSON、ドキュメントが充実 | 情報源がIMDbではない(IMDbの評価ではない) |
| Thunderbit(ノーコード) | 非エンジニア、素早い出力 | 2クリックでスクレイピング、AIが項目を提案、Excel/Sheetsに出力 | 大規模スクレイピングではクレジット制 |
これらの選択肢について少し補足します。Cinemagoerは2023年5月以来PyPIリリースがなく、IMDbの2025年6月の再設計後にパーサーの大半が壊れました。現時点で本番用途にはおすすめしません。TMDbは優秀ですが、IMDbではなく独自の評価システムを使っています。IMDbの公式エンタープライズAPIはAWS Data Exchange経由で年間かかるため、ほとんどの人には現実的ではありません。
コードを書きたくない読者には、が最適です。IMDbページを読み取り、抽出項目(タイトル、評価、公開年、ジャンルなど)を自動提案し、Excel、Google Sheets、Airtable、Notionへ2クリックで出力できます。IMDbのレイアウトが変わってもAIが追従するので、セレクタの保守は不要です。この点は後ほど詳しく説明します。
では、Pythonを書きたい人向けに、実際に動く2つの方法を紹介します。
方法1:BeautifulSoupを使ってPythonでIMDbをスクレイピングする(従来型)
これは多くのチュートリアルで紹介される定番の方法です。動きますが、はっきり言うと、ここで紹介する中では最も壊れやすい方法です。IMDbのCSSクラス名は自動生成で、再設計のたびに変わります。とはいえ、ウェブスクレイピングの基礎を学ぶには最適です。
ステップ1:Pythonライブラリをインストールして読み込む
必要なのは4つのパッケージです。
1pip install requests beautifulsoup4 pandas lxml
それぞれの役割は次のとおりです。
requests— HTTPリクエストを送ってWebページを取得するbeautifulsoup4— HTMLを解析し、特定の要素を検索できるようにするpandas— 抽出したデータを表にまとめ、CSV/Excelへ出力するlxml— 高速なHTMLパーサー(BeautifulSoupのバックエンドとして使える)
インポート部分はこちらです。
1import requests
2from bs4 import BeautifulSoup
3import pandas as pd
ステップ2:IMDbにHTTPリクエストを送る
多くの初心者が最初につまずくのがここです。IMDbは適切な User-Agent ヘッダーがないリクエストをブロックします。403 Forbiddenエラーが返ります。Python Requestsのデフォルトのユーザーエージェント文字列(python-requests/2.31.0)は、すぐに検知されます。
1url = "https://www.imdb.com/chart/top/"
2headers = {
3 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
4 "Accept-Language": "en-US,en;q=0.9"
5}
6response = requests.get(url, headers=headers)
7if response.status_code != 200:
8 print(f"ページの取得に失敗しました: {response.status_code}")
9else:
10 print("ページの取得に成功しました")
Accept-Language ヘッダーも重要です。これがないと、IMDbはIPの地理情報に応じて別言語のコンテンツを返すことがあります。
ステップ3:BeautifulSoupでHTMLを解析する
HTMLを取得したら、BeautifulSoupオブジェクトを作成して、必要な要素を探します。ChromeでIMDbのTop 250ページを開き、映画タイトルを右クリックして「検証」を選ぶと、HTML構造を確認できます。
1soup = BeautifulSoup(response.text, "lxml")
2025年半ば時点では、Top 250ページは次のセレクタを使っています。
- 映画コンテナ:
li.ipc-metadata-list-summary-item - タイトル:
h3.ipc-title__text - 年:
span.cli-title-metadata-item(最初のspan) - 評価:
span.ipc-rating-star--rating
注意しておくと、ipc- で始まるこれらのクラス名は、IMDbのコンポーネントシステムによって生成されています。2023年6月の再設計以降は安定していますが、今後も変わらない保証はありません。
ステップ4:映画データ(タイトル、年、評価)を抽出する
ここで、私は多くのチュートリアルと少し違う書き方をしています。try/except によるエラー処理を入れています。調べた競合ガイドのどれもこれをやっていませんでした。そのため、セレクタが変わったときに静かに壊れてしまうのです。
1movies = []
2movie_items = soup.select("li.ipc-metadata-list-summary-item")
3for item in movie_items:
4 try:
5 title_tag = item.select_one("h3.ipc-title__text")
6 title = title_tag.text.strip() if title_tag else "N/A"
7 year_tag = item.select_one("span.cli-title-metadata-item")
8 year = year_tag.text.strip() if year_tag else "N/A"
9 rating_tag = item.select_one("span.ipc-rating-star--rating")
10 rating = rating_tag.text.strip() if rating_tag else "N/A"
11 movies.append({
12 "title": title,
13 "year": year,
14 "rating": rating
15 })
16 except Exception as e:
17 print(f"映画の解析中にエラーが発生しました: {e}")
18 continue
19print(f"{len(movies)}件の映画を抽出しました")
ステップ5:PandasでCSVまたはExcelに保存する
1df = pd.DataFrame(movies)
2df.to_csv("imdb_top_250.csv", index=False)
3df.to_excel("imdb_top_250.xlsx", index=False)
4print(df.head())
出力例:
1 title year rating
20 1. The Shawshank Redemption 1994 9.3
31 2. The Godfather 1972 9.2
42 3. The Dark Knight 2008 9.0
53 4. The Godfather Part II 1974 9.0
64 5. 12 Angry Men 1957 9.0
これで動きます。ただし、CSSセレクタだけでつながっていて、いつ壊れてもおかしくありません。そこで次に、私が実際におすすめする方法を紹介します。
方法2:JSON-LDを使う方法 — HTML解析を丸ごと飛ばす
これは競合記事のどれも紹介していない手法で、真面目なプロジェクトなら私ならこちらを使います。IMDbは、各ページの <script type="application/ld+json"> タグ内に、(Linked Data用のJavaScript Object Notation)という構造化データを埋め込んでいます。このデータはSchema.org標準に従っており、Googleのリッチ検索結果にも使われます。CSSクラス名よりはるかに変わりにくいのが特徴です。
ApifyのIMDbスクレイパーのような実運用向けツールでも、抽出優先順位は「JSON-LD > NEXT_DATA > DOM」になっています。私もこの順番をおすすめします。
なぜJSON-LDはCSSセレクタより信頼できるのか
| 手法 | JSコンテンツ対応 | UI変更への強さ | 速度 | 複雑さ |
|---|---|---|---|---|
| BeautifulSoup + CSSセレクタ | ❌ いいえ | ⚠️ 弱い(クラス名が変わる) | 高速 | 低 |
| JSON-LD抽出 | ✅ はい | ✅ Schema.org標準に準拠 | 高速 | 低〜中 |
__NEXT_DATA__ のJSON抽出 | ✅ はい | ✅ 比較的安定 | 高速 | 低〜中 |
| Selenium / Playwright | ✅ はい | ⚠️ 弱い | 遅い | 中〜高 |
| Thunderbit(ノーコード、2クリック) | ✅ はい(AIがページを読む) | ✅ AIが自動で追従 | 高速 | なし |
ipc-metadata-list-summary-item のようなCSSクラス名は、IMDbのReactコンポーネントシステムによって自動生成され、再設計のたびに変わります。JSON-LDのスキーマは見た目のレイヤーではなく、実際のデータモデルを表します。本の目次を読むのと、文字サイズだけで章を判別しようとする違いのようなものです。

手順:JSON-LDからIMDbデータを抽出する
ステップ1:ページを取得する
前と同じく、適切な User-Agent ヘッダーを付けて requests を使います。
1import requests
2from bs4 import BeautifulSoup
3import json
4import pandas as pd
5url = "https://www.imdb.com/chart/top/"
6headers = {
7 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
8 "Accept-Language": "en-US,en;q=0.9"
9}
10response = requests.get(url, headers=headers)
11soup = BeautifulSoup(response.text, "lxml")
ステップ2:JSON-LDのscriptタグを見つける
1script_tag = soup.find("script", {"type": "application/ld+json"})
2if not script_tag:
3 print("このページにはJSON-LDが見つかりませんでした")
4else:
5 data = json.loads(script_tag.string)
6 print(f"JSON-LDを見つけました。型: {data.get('@type', 'unknown')}")
ステップ3:構造化データを解析する
Top 250ページでは、JSON-LDに250本の映画すべてを含む itemListElement 配列があります。各要素には、順位、名前、URL、aggregateRating、datePublished、genre、description、director、actor 配列が含まれます。
1movies = []
2for item in data.get("itemListElement", []):
3 movie = item.get("item", {})
4 rating_info = movie.get("aggregateRating", {})
5 movies.append({
6 "rank": item.get("position"),
7 "title": movie.get("name"),
8 "url": movie.get("url"),
9 "rating": rating_info.get("ratingValue"),
10 "vote_count": rating_info.get("ratingCount"),
11 "date_published": movie.get("datePublished"),
12 "genre": ", ".join(movie.get("genre", [])),
13 "description": movie.get("description"),
14 })
ステップ4:CSVに出力する
1df = pd.DataFrame(movies)
2df.to_csv("imdb_top_250_json_ld.csv", index=False)
3print(df.head())
出力例:
1 rank title url rating vote_count date_published genre
20 1 The Shawshank Redemption https://www.imdb.com/title/tt0111161/ 9.3 2900000 1994-10-14 Drama
31 2 The Godfather https://www.imdb.com/title/tt0068646/ 9.2 2000000 1972-03-24 Crime, Drama
42 3 The Dark Knight https://www.imdb.com/title/tt0468569/ 9.0 2800000 2008-07-18 Action, Crime, Drama
250本すべて取得できます。きれいで構造化されていて、CSSセレクタの細かい調整も不要です。しかもこのデータはSchema.org標準に従っているため(Googleの検索結果もこれに依存しています)、見た目のレイアウトよりずっと変わりにくいのです。
おまけ:個別映画ページの __NEXT_DATA__
個別のタイトルページからより豊富な情報(上映時間、フルキャスト、あらすじ、ポスター画像)を取りたい場合、IMDbは __NEXT_DATA__ というJSONオブジェクトも埋め込んでいます。これはReactがページをハイドレートするために使うデータで、サイトの動作を壊さずに削除することはできません。
1# /title/tt0111161/ のような個別映画ページで
2next_data_tag = soup.find("script", {"id": "__NEXT_DATA__"})
3if next_data_tag:
4 next_data = json.loads(next_data_tag.string)
5 above_fold = next_data["props"]["pageProps"]["aboveTheFoldData"]
6 title = above_fold["titleText"]["text"]
7 year = above_fold["releaseYear"]["year"]
8 rating = above_fold["ratingsSummary"]["aggregateRating"]
9 runtime_seconds = above_fold.get("runtime", {}).get("seconds", 0)
10 genres = [g["text"] for g in above_fold["genres"]["genres"]]
11 plot = above_fold["plot"]["plotText"]["plainText"]
チャート/一覧ページにはJSON-LD、個別タイトルページには __NEXT_DATA__ を使います。これが実運用向けのやり方です。
なぜIMDbスクレイパーは壊れ続けるのか?どう直すのか?
私が確認したIMDbスクレイピング関連のフォーラムで、最もよく挙がっていた悩みです。ユーザーは「UI変更で一部のコードが壊れた」「2024年に動かない!」と書き込みますが、返答はたいてい沈黙か「Seleniumを試してみて」です。
根本原因は、IMDbがReact/Next.jsフロントエンドへ継続的に移行していることです。主な破壊的変更の時系列は次のとおりです。
| 日付 | 変更内容 | 壊れたもの |
|---|---|---|
| 2022年11月 | Name Pagesを再設計 | 旧nameページ用スクレイパー |
| 2023年6月 | Top 250ページを再設計 | すべての td.titleColumn / td.ratingColumn セレクタ |
| 2023年4月 | タイトル下層ページを再設計 | biography、受賞歴、ニュース用スクレイパー |
| 2023年10月 | Advanced Searchを再設計 | 検索ベースのスクレイパー |
| 2025年6月 | /reference ページを再設計 | Cinemagoerライブラリ(大半のパーサー) |
このような大きな破壊的変更は、だいたい6〜12か月に1回起きています。CSSクラス名に依存したスクレイパーは、常にランニングマシンの上にいるようなものです。
よくあるエラーと対処法
結果が空/NoneType エラー
最もよくあるエラーです。AttributeError: 'NoneType' object has no attribute 'text' が出ます。これはBeautifulSoupが対象要素を見つけられなかったことを意味します。多くはCSSクラス名が変わったか、コンテンツがJavaScriptで描画されているのが原因です。
対処法: JSON-LD抽出(上記の方法2)に切り替えます。データは初期HTMLレスポンスに含まれているので、JavaScriptは不要です。
403 Forbidden
IMDbはを使ってボットを検知・遮断しています。最大の原因は、User-Agent ヘッダーがない、または明らかに不自然なことです。これはオープンソースプロジェクトや、IMDb社員が問題を認めたでも確認されています。
対処法: 現実的なブラウザの User-Agent 文字列と Accept-Language: en-US ヘッダーを常に付けます。接続の再利用には requests.Session() を使いましょう。
25件しか返らない
IMDbの検索ページや「Most Popular」リストは遅延読み込みを使っています。最初は約25件だけ描画し、スクロールに応じてAJAXで追加読み込みされます。
対処法: URLパラメータでページネーションを行う(次のセクションで説明)か、250件すべてが1回のレスポンスで読み込まれるTop 250ページに切り替えます。
セレクタが突然動かなくなる
もう使えない古いセレクタ: td.titleColumn、td.ratingColumn、.lister-item-header、.inline-block.ratings-imdb-rating。コードがこれらを使っているなら壊れています。
対処法: 自動生成クラス名より、data-testid 属性(たとえば h1[data-testid="hero-title-block__title"])を優先します。さらに良いのはJSON-LDを使うことです。
判断のフレームワーク:短期修正と長期修正
- 短期修正: 各セレクタを
try/exceptで囲み、HTTPステータスコードを確認し、クラッシュせずにエラーをログに残す - 中期修正: CSSセレクタからJSON-LD抽出へ切り替える(方法2)
- 長期修正: 大規模分析にはを使うか、ページ構造を毎回AIが読み直すのようなツールを使う。セレクタの保守は不要で、AIがレイアウト変更に自動対応します
25件の壁を超える:IMDbのページネーションと大規模データセットのスクレイピング
私が確認した競合チュートリアルは、どれも1ページしかスクレイピングしていません。ページネーションの説明がないのです。しかし、単一の一覧以上が必要なら、すぐに壁にぶつかります。
ページネーションが不要なページ
朗報です。Top 250ページは、250本の映画をすべて1回のサーバーレンダリングレスポンスで読み込みます。JSON-LDにも __NEXT_DATA__ にも完全なデータセットが含まれているので、ページネーションは不要です。
IMDbの検索ページのページネーションの仕組み
IMDbの検索ページは、start= URLパラメータを使い、50件ずつ増やしていきます。
1https://www.imdb.com/search/title/?groups=top_1000&start=1
2https://www.imdb.com/search/title/?groups=top_1000&start=51
3https://www.imdb.com/search/title/?groups=top_1000&start=101
結果を順にたどるPythonループはこちらです。
1import time
2all_movies = []
3for start in range(1, 1001, 50): # Top 1000をページ送り
4 url = f"https://www.imdb.com/search/title/?groups=top_1000&start={start}"
5 response = requests.get(url, headers=headers)
6 if response.status_code != 200:
7 print(f"start={start} で失敗しました: {response.status_code}")
8 break
9 soup = BeautifulSoup(response.text, "lxml")
10 # お好みの方法で映画を抽出
11 # ...
12 print(f"start={start} のページを取得しました")
13 time.sleep(3) # 配慮を忘れずに — IMDbは約50回の高速リクエストでブロックします
この time.sleep(3) は重要です。コミュニティ報告によると、IMDbはおよそ50回の高速リクエスト後にIPをブロックし始めます。2〜5秒のランダムな遅延を入れるのが良い実践です。
スクレイピング自体をやめるべき時:IMDb公式の一括データセット
本当に大規模な用途なら、IMDbは毎日更新される7つの無料TSVファイルをで提供しています。
| ファイル | 内容 | サイズ |
|---|---|---|
| title.basics.tsv.gz | タイトル、種類、ジャンル、上映時間、公開年 | 約800 MB |
| title.ratings.tsv.gz | 平均評価、投票数 | 約25 MB |
| title.crew.tsv.gz | 監督、脚本家 | 約300 MB |
| title.principals.tsv.gz | 上位クレジットの出演者・スタッフ | 約2 GB |
| title.akas.tsv.gz | 地域別の別タイトル | 約1.5 GB |
| title.episode.tsv.gz | TVエピソード情報 | 約200 MB |
| name.basics.tsv.gz | 人物名、生年、代表作 | 約700 MB |
Pandasに読み込むのは簡単です。
1ratings = pd.read_csv("title.ratings.tsv.gz", sep="\t", compression="gzip")
2basics = pd.read_csv("title.basics.tsv.gz", sep="\t", compression="gzip", low_memory=False)
3# tconst(IMDbのタイトルID)で結合
4merged = basics.merge(ratings, on="tconst")
5top_movies = merged[merged["titleType"] == "movie"].nlargest(250, "averageRating")
これらのデータセットは2,600万件以上のタイトルをカバーします。ページネーションもセレクタも403エラーもありません。ライセンスは個人・非商用利用に限られており、再公開や再販はできません。
ノーコードの近道:Thunderbitがページネーションを処理する
ページネーションされたIMDbデータが必要だけれど、ページ送りのロジックを書きたくない方には、 がクリック式ページネーションと無限スクロールの両方にネイティブ対応しています。スクレイピングしたいページを指定するだけで、あとは任せられます。遅延読み込みのコンテンツをスクロールしながら処理するのも自動です。
PythonでIMDbをスクレイピングする:完全に動くコード(コピペ可)
すぐに実行できる、自己完結型のスクリプトを2本紹介します。
スクリプトA:BeautifulSoup版(CSSセレクタ)
1import requests
2from bs4 import BeautifulSoup
3import pandas as pd
4url = "https://www.imdb.com/chart/top/"
5headers = {
6 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
7 "Accept-Language": "en-US,en;q=0.9"
8}
9response = requests.get(url, headers=headers)
10if response.status_code != 200:
11 print(f"エラー: {response.status_code}")
12 exit()
13soup = BeautifulSoup(response.text, "lxml")
14movie_items = soup.select("li.ipc-metadata-list-summary-item")
15movies = []
16for item in movie_items:
17 try:
18 title = item.select_one("h3.ipc-title__text")
19 year = item.select_one("span.cli-title-metadata-item")
20 rating = item.select_one("span.ipc-rating-star--rating")
21 movies.append({
22 "title": title.text.strip() if title else "N/A",
23 "year": year.text.strip() if year else "N/A",
24 "rating": rating.text.strip() if rating else "N/A",
25 })
26 except Exception as e:
27 print(f"エラーのため映画をスキップします: {e}")
28df = pd.DataFrame(movies)
29df.to_csv("imdb_top250_bs4.csv", index=False)
30print(f"{len(df)}件の映画を保存しました")
31print(df.head())
スクリプトB:JSON-LD版(推奨)
1import requests
2from bs4 import BeautifulSoup
3import json
4import pandas as pd
5url = "https://www.imdb.com/chart/top/"
6headers = {
7 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
8 "Accept-Language": "en-US,en;q=0.9"
9}
10response = requests.get(url, headers=headers)
11if response.status_code != 200:
12 print(f"エラー: {response.status_code}")
13 exit()
14soup = BeautifulSoup(response.text, "lxml")
15script_tag = soup.find("script", {"type": "application/ld+json"})
16if not script_tag:
17 print("JSON-LDデータが見つかりませんでした")
18 exit()
19data = json.loads(script_tag.string)
20movies = []
21for item in data.get("itemListElement", []):
22 movie = item.get("item", {})
23 rating_info = movie.get("aggregateRating", {})
24 directors = movie.get("director", [])
25 director_names = ", ".join(
26 d.get("name", "") for d in (directors if isinstance(directors, list) else [directors])
27 )
28 movies.append({
29 "rank": item.get("position"),
30 "title": movie.get("name"),
31 "url": movie.get("url"),
32 "rating": rating_info.get("ratingValue"),
33 "votes": rating_info.get("ratingCount"),
34 "year": movie.get("datePublished", "")[:4],
35 "genre": ", ".join(movie.get("genre", [])),
36 "director": director_names,
37 "description": movie.get("description"),
38 })
39df = pd.DataFrame(movies)
40df.to_csv("imdb_top250_jsonld.csv", index=False)
41print(f"{len(df)}件の映画を保存しました")
42print(df.head())
どちらのスクリプトにもエラー処理が含まれており、きれいなCSV出力が得られます。スクリプトBのほうが、監督、説明、URLなどより豊富なデータを取得でき、レイアウト変更にも強いです。
コードを書かずにIMDbをスクレイピングする方法(Thunderbitを使う)
誰もがPythonを書きたいわけでも、書く必要があるわけでもありません。たとえば、オペレーション担当で、今週の高評価映画をスプレッドシートに入れたいだけかもしれません。あるいは、コンテンツ戦略担当で、年ごとのジャンル傾向を比較したいのかもしれません。そうした場合、スクレイパーを自作するのはやりすぎです。
を使って同じデータを取得する方法は次のとおりです。
始める前に:
- 難易度: 初級
- 所要時間: 約2分
- 必要なもの: Chromeブラウザ、(無料プランでも可)
ステップ1: スクレイピングしたいIMDbページを開きます。ChromeでIMDbのTop 250(または他のIMDb一覧/検索ページ)を開いてください。
ステップ2: Thunderbitのサイドバーで「AIで項目を提案」をクリックします。AIがページを解析し、通常はタイトル、年、評価、ジャンルなどの列を提案します。提案された項目のプレビュー表が表示されます。
ステップ3: 必要に応じて項目を調整します。不要な列を削除したり、「+ 列を追加」をクリックして、欲しい内容を自然な英語で説明してカスタム列を追加できます(例:「監督名」「投票数」)。
ステップ4: 「スクレイピング」をクリックします。Thunderbitがデータを抽出します。無限スクロールやページネーションのあるページでは、スクロールも自動で処理します。
ステップ5: エクスポートします。エクスポートボタンをクリックし、Excel、Google Sheets、CSV、Airtable、Notionから形式を選びます。データは数秒で目的地に届きます。
ここでの最大の利点は、単なる便利さではありません。ThunderbitのAIが毎回ページ構造を新しく読み取る点です。IMDbのレイアウトが変わっても(実際に変わります)、AIが追従します。セレクタの更新も、壊れたコードの修正も不要です。締め切り前夜2時に壊れたスクレイパーに泣かされたことがある人なら、この価値は大きいはずです。
Thunderbitはサブページスクレイピングにも対応しており、各映画の詳細ページに進んで、一覧ページには表示されない出演者、監督、上映時間などの項目を表に追加できます。動作を見たい方は、をご覧ください。
IMDbのスクレイピングは合法か?知っておくべきこと
フォーラムでは、ユーザーがはっきりこう聞きます。「こういうのって合法なんですか? IMDbはウェブサイトのスクレイピングを望んでいないはずです。」もっともな疑問ですが、競合記事のどれもこれに答えていません。
IMDbのrobots.txt: Top 250チャート(/chart/top/)、個別タイトルページ(/title/ttXXXXXXX/)、nameページ(/name/nmXXXXXXX/)は robots.txt でブロックされていません。ブロックされているパスには、/find、/_json/*、/search/name-text、/user/ur*/ratings、および各種AJAXエンドポイントがあります。Crawl-delay の指定はありません。
IMDbの利用条件: 該当条項には次のようにあります。「当サイト上で、当社の明示的な書面による同意なしに、データマイニング、ロボット、スクリーンスクレイピング、または類似のデータ収集・抽出ツールを使用してはなりません。」 さらに、スクレイピングしたデータの再販や商用利用を禁じる条項もあります。
実務上の意味: 2024年の最近の判例(Meta v. Bright Data、X Corp v. Bright Data)では、そもそも利用規約に同意していないユーザーには、利用規約が拘束力を持たない可能性があるとされました。ログインせずに公開データをスクレイピングする場合、利用規約の執行可能性は議論の余地があります。ただし、法的にはまだ変化の大きい分野です。
安全な代替手段: IMDbのは、個人・非商用利用向けに明確に認められています。TMDbのAPIも、無料APIキーで柔軟に使えます。グレーゾーンを避けたいなら、どちらも有力な選択肢です。
実践的な指針: もしスクレイピングするなら、配慮あるクロール速度(リクエスト間に time.sleep(3))、適切なヘッダー設定、robots.txtでブロックされたパスを叩かないことを守ってください。商用プロジェクトでは、法務の専門家に相談するか、公式データセット/APIを使いましょう。
Thunderbitブログでは、を詳しく解説しています。
結論:PythonでIMDbをスクレイピングする正しい方法を選ぶ
要点は次のとおりです。
- BeautifulSoup + CSSセレクタ: 基礎を学ぶのに向いています。6〜12か月ごとに壊れる前提で使いましょう。必ずエラー処理を入れてください。
- JSON-LD抽出: 継続的に使うPythonプロジェクトなら、私ならこれを推します。Schema.org標準に従い、CSSクラスよりずっと変わりにくく、JavaScriptレンダリングなしで整った構造化データが得られます。
__NEXT_DATA__JSON: 個別タイトルページのより豊富なデータ(上映時間、フルキャスト、あらすじ、ポスター画像)の補助として使います。- IMDb公式データセット: 大規模分析に最適です。2,600万件以上のタイトル、毎日更新、スクレイピング不要。個人・非商用利用のみ。
- : コーディング不要で、保守なしで素早くデータが欲しい人に最適です。AIがレイアウト変更に追従し、ページネーションにも対応し、Excel/Sheets/Airtable/Notionへ出力できます。
このガイドはブックマークしておいてください。IMDbの構造が次に変わったら更新します。コードをまったく使いたくないなら、。IMDbページからきれいなスプレッドシートまで、どれだけ速く進めるか実感できるはずです。他のサイトも扱うなら、も、より広いワークフローをカバーしています。
FAQ
IMDbをスクレイピングするのは合法ですか?
IMDbの利用規約では、同意なしのスクレイピングは禁止されています。ただし、2024年の最近の判例以降、公開データに対する利用規約の拘束力は法的に争点になっています。最も安全なのは、IMDbの(個人・非商用利用)かTMDb API(無料キー)です。スクレイピングする場合は、robots.txtを尊重し、リクエスト間に十分な遅延を入れ、ブロックされたパスは避けてください。商用利用では法務の専門家に相談しましょう。
IMDbスクレイパーが空の結果を返すのはなぜですか?
ほとんどの場合、原因は古いCSSセレクタです。td.titleColumn や td.ratingColumn のようなクラス名は、2023年6月以降存在していません。解決策は、JSON-LD抽出(<script type="application/ld+json"> タグを解析する)へ切り替えるか、現在の ipc- 系クラスにセレクタを更新することです。また、適切な User-Agent ヘッダーを付けているかも確認してください。ヘッダーがないと403エラーになり、空結果のように見えることがあります。
IMDbから25件以上を取得するにはどうすればいいですか?
Top 250ページは250本すべてを1回のレスポンスで読み込むので、ページネーションは不要です。検索結果では、start= URLパラメータを50件ずつ増やしてページを進めます。たとえば start=1、start=51、start=101 です。ブロックを避けるため、リクエスト間に time.sleep(3) を入れてください。別の方法として、 のIMDb公式データセットには2,600万件以上のタイトルが含まれており、ページネーションは不要です。
__NEXT_DATA__ とは何ですか? IMDbのスクレイピングに使うべき理由は?
__NEXT_DATA__ は、IMDbのReact/Next.jsページ内の <script id="__NEXT_DATA__"> タグに埋め込まれたJSONオブジェクトです。Reactがページを描画するために使う完全な構造化データ、つまりタイトル、評価、出演者、ジャンル、上映時間などが入っています。見た目のレイアウトではなく、基礎となるデータモデルを表しているため、CSSセレクタよりUI再設計に強いです。最も堅牢な抽出方法として、JSON-LDと併用してください。
コーディングなしでIMDbをスクレイピングできますか?
はい。主な方法は2つあります。(1) IMDbのをダウンロードする — 2,600万件以上のタイトルをカバーする7つのTSVファイルで、毎日更新、非商用利用なら無料です。(2) を使う — IMDbページを読み取り、抽出項目を自動提案し、Excel、Google Sheets、CSVへ2クリックで出力できます。コード不要、保守すべきセレクタもありません。
詳しく知る