Scrapy が「最新のWebサイトには対応できない」と見られがちなのは、JavaScript を実行しないからです。でも、その見方はちょっとズレています。ページをレンダリングしないことこそが Scrapy の本質で、実際の挙動を見れば、それは欠点というより設計思想だとすぐ分かります。
私はそれを1回の検証で自分の目で確かめました。JavaScript で描画されるカタログの検証用ページを用意し、Scrapy をブラウザで表示されるページに向けたところ、取得できた商品カードは 0 件でした。次に、同じページが裏側で静かに呼び出していた JSON エンドポイントに同じ spider を向けると、8/8 件すべてをきれいに取得できました。ツールは同じ、セッションも同じ、それなのに結果は真逆。この2つの数字の差こそが、今回のレビューの核心です。
Scrapy は実際には何なのか(そして何ではないのか)

Scrapy は、サイトをクロールして構造化データを取り出すための Python フレームワークです。これはメンテナー自身が 概要ドキュメント で示している位置づけで、実際に使ってみてもその説明どおりでした。誇張したマーケティング表現は必要ありません。Python 開発者が「本気でスクレイピングするなら何を使うの?」と聞いたとき、反射的に名前が挙がるくらいには古参で定番ですし、リポジトリの実績もそれを裏付けています。2026-07-07 時点で GitHub スターは約 62,981(scrapy/scrapy)、フォークは 11,773、同日時点のオープン issue は 590 件。ライセンスは BSD-3-Clause、Python 3.10 以上対応で、私が試したのは 2.17.0 でした。しかもこのバージョンは、ちょうどテストを始めた朝にリリースされたものだったので、古い版を使ったことによる言い訳は一切ありません。
新しい AI 系クローラーと大きく違うのはここです。Scrapy はデフォルトで HTTP のみ、つまりブラウザもレンダリングエンジンも使いません。HTML をネットワーク経由で取得し、パーサーに渡し、CSS セレクタや XPath で必要な項目を抜き出します。これを「制限」と呼ぶのは半分だけ正しくて、設計の意図を見落としています。Scrapy の考え方は、単純なスクレイピングのために headless Chrome を立ち上げるのはたいてい遠回りだ、というものです。より賢い方法は、ページがすでに呼び出しているデータリクエストを見つけて、そこへ直接アクセスすることです。
この考え方は、私が勝手に解釈しているわけではありません。公式の 動的コンテンツのドキュメント にもはっきり書かれています。まずは下層のデータリクエストを特定して再現し、それが難しい場合の最終手段として headless ブラウザを使う、という順番です。多くのスクレイパーは最初からブラウザを開き、API の存在を見に行こうともしません。Scrapy はその前提を逆にしています。
主な機能と、その設計判断
内部を見ると、Scrapy はいくつもの部品でできていますが、そこには一つの前提があります。使う人は、ワンクリックの魔法を求める人ではなく、細かく制御したい開発者だ、という前提です。
Spiders。クラスを作り、開始 URL を渡し、parse コールバックで item を返したり次のリンクを辿ったりします。ノーコード型の抽出ツールよりは手間がかかりますが、その分、何を取得し、次にどこへ進むかを自分で正確に決められます。
Selectors。パースには parsel が使われ、その下には lxml があります。CSS と XPath の両方が最初から使える標準機能です。lxml が土台にあるからこそ、選択処理は速く、抽出コードも文字列操作の寄せ集めではなく、意図がそのまま読める形になります。
Feed exports。spider をファイルに向けるだけで、Scrapy は item を JSON、JSON Lines、CSV、XML にそのまま出力します。私の検証でも、静的カタログの spider が私の手で export 用コードを1行も書かずに JSON と CSV の両方を書き出しました。 feed export の説明は本物で、記載どおりに動きます。
AutoThrottle とクロール制御。リクエストは Twisted 上で非同期にスケジューリングされ、同時接続数の上限、ダウンロード遅延、深さ制限、適応型レート制限のための AutoThrottle、robots.txt の遵守が使えます。大規模クロールがサーバーを叩き壊す事故に変わるのを防ぐための制御です。
HTTP のみ、を機能として言い換えると。ブラウザがなければ、メモリ消費は少なく、スループットは高く、レンダリングエンジンの世話も不要です。もちろん、欲しいデータが普通の HTTP で取れる場合に限ります。とはいえ、ブラウザ先行の人たちが思っているより、そのケースはかなり多いのです。
セットアップ:誰もスクリーンショットに載せない依存関係の実態

インストールは驚くほど平穏でした。こうしたフレームワークでは、それ自体がまず価値として明記されるべきことです。macOS arm64 の新しい仮想環境で pip install Scrapy==2.17.0 を実行すると、バイナリ wheel が取得され、コンパイルで止まることもなく、きれいに完了しました。特筆すべきトラブルは何もありませんでした。ですが、それこそが重要です。
とはいえ、実際に何が入ってくるのかは見ておく価値があります。scrapy version -v では、Scrapy 2.17.0 が lxml 6.1.1、Twisted 26.4.0、pyOpenSSL 26.3.0、cryptography 49.0.0 の上で動いており、さらに parsel、cssselect、tldextract などが加わっていました。これは単なる HTML パーサーではなく、クロールフレームワーク一式の重みです。このマシンではすべてに wheel が用意されていて、インストールは快適でした。ただ、環境によっては公式ドキュメントでもプラットフォーム固有の依存関係の摩擦に注意が必要とされています。特に歴史的に引っかかりやすいのは cryptography と Twisted 周りです。特殊な環境なら、その前提で見積もっておくべきです。今回はスムーズでしたが、入ってくるものの多さは無視できません。フレームワークを入れている以上、その重さもフレームワーク相応です。
実機検証:うまくいった点

インストール後、静的なケースは問題なく動きました。取得漏れはなく、完全に回収できました。
| テスト | 結果 | 実行時間 |
|---|---|---|
| ローカル静的カタログ + ページネーション | 12/12 商品 | 0.557秒 |
| 静的カタログの CSV 出力 | 12 行を書き出し | (同一実行) |
| 記事抽出 | タイトル + 本文3/3段落 | 0.416秒 |
| クロールグラフ、DEPTH_LIMIT=2 | 深さ0/1/2で11ページ | 0.904秒 |
| ローカル 500 ページ | status 500 を取得、クラッシュなし | 0.424秒 |
| Books to Scrape(公開) | 20 商品 | 2.053秒 |
| Quotes to Scrape spider(公開) | 12 件の quote | 3.465秒 |
静的カタログの spider は、1ページ目から2ページ目までページネーションをたどり、期待された 12/12 件をすべて取得し、そのまま JSON と CSV の両方に書き出しました。中でも注目すべきは記事の検証です。Scrapy はページを自動できれいな Markdown に整形しようとはしません。代わりに、article の各フィールドを明示的なセレクタで狙い撃ちし、ナビゲーションやフッターの文言は別フィールドに分けられました。その結果、本文は 3/3 段落を取得し、定型文は出力に混ざらず隔離されました。これがトレードオフです。セレクタを書けば、欲しいものだけを、欲しい形で取得できます。
クロール制御も小規模ではしっかり機能しました。DEPTH_LIMIT=2、短めのダウンロード遅延、ドメインごとの同時実行制限、robots.txt の有効化という条件で、クロールグラフは深さ0、1、2にまたがる 11 ページを巡回し、深さのカウントも正しく動作しました。エラー処理も同じくらい落ち着いていました。意図的に用意した 500 ページは handle_httpstatus_list 経由で status 500 を持つ構造化 item として返り、例外もなく、クロール全体も止まりませんでした。Scrapy はエラーステータスを、クロールを落とす予期せぬ事故ではなく、spider のロジック内で処理する対象として扱います。
実機検証:JavaScript の壁と、その隣にある扉

ここからが、このレビューの中心です。
Scrapy の HTTP フェッチャーを JavaScript 描画型のカタログ検証ページに向けました。すると、ソース HTML を取得し、.product-card ノードは 0 件、そこで終了です。なぜなら、カードを描画するはずのスクリプトは実行していないからです。公開されている Quotes to Scrape の JS ページ でも同じ結果でした。レンダリングされた quote ノードは 0 件。ここでテストを終えれば、「今どきのサイトには使えない」と Scrapy を切り捨てたくなるでしょう。
でも、そこで終わるべきではありません。その JS カタログは、ほとんどのケースと同じように、裏側で JSON API からデータを取っていました。同じ Scrapy spider をそのエンドポイントに向けると、0.416秒 で 8/8 件の product を取得できました。ブラウザもレンダリングも不要。ただ、ページが既に呼び出していた URL にリクエストし、返ってきた JSON をパースしただけです。
この比較は、「リクエストを再現する」という哲学を小さく示したものです。レンダリング済みのページは見せかけにすぎず、データはずっと API の向こう側にありました。Scrapy の設計は、headless ブラウザにページ生成を眺めさせるためにコストを払うのではなく、そこへ直接アクセスする方向へユーザーを導きます。速く、軽く、壊れにくい。DOM をたくさん組み立てるクライアント側より、API の契約のほうがずっと安定して頼れます。とはいえ、そこは手作業です。ネットワークタブを開き、リクエストを見つけ、ヘッダーやパラメータを自分で再現しなければなりません。Scrapy が API を見つけてくれるわけではありません。ただ、見つけた後のアクセスを圧倒的に簡単にしてくれるだけです。
境界線もはっきりさせておきます。再現できる下層リクエストが本当に存在しない場合、つまりクライアントサイド描画でデータが埋め込まれているのに API が背後にないケースでは、Scrapy に headless ブラウザ連携を自分で組み込む必要があります。今回の検証では、そのルートは試していません。また、ここまでの検証は小さな fixture と公開デモページで行ったものです。100〜1,000ページ規模のクロールは実施していないので、メモリ、スループット、リトライ挙動についてスケール時の断定はしません。非同期コアとクロール制御は強い兆候ですが、兆候は計測結果ではありません。
長所と短所
長所:
- HTTP のみの設計なので高速で軽い。静的ページは約0.5秒で 12/12、JSON API からは 0.416秒で 8/8。ブラウザ負荷はゼロ。
- 「リクエストを再現する」という考え方が本当に効く。JS ページでは 0 件だったものが、裏側の API からは 8 件すべて取れた。
lxmlベースの CSS / XPath セレクタで、抽出コードが読みやすく高速。- JSON / CSV / XML への feed export を追加コードなしで使える。
- エラー処理が明確で、500 はクラッシュではなく処理対象の status として返る。
- 同時実行、遅延、深さ制限、AutoThrottle、robots.txt など、成熟したクロール制御を備える。
- BSD-3-Clause ライセンスで扱いやすく、最新環境ではインストールも素直。
短所:
- 設計上 JavaScript をレンダリングしない。クライアント描画ページでは、API を自分で見つけるまで 0 件になる。
- 下層リクエストを見つける作業は手動。Scrapy がエンドポイントを教えてくれるわけではない。
- 依存関係が多い(Twisted、lxml、cryptography、pyOpenSSL、parsel、tldextract)。今回は問題なかったが、特殊な環境では摩擦になりやすい。
- ノーコードや自動抽出ツールよりもコード量が多い。spider の作成と保守は自分の仕事。
- テストは小規模 fixture とデモサイト中心で、大規模クロールは未検証。
どんな人向けか、どんな人は別の選択肢を選ぶべきか

Scrapy は、ページではなくリクエスト思考で動けて、コードレベルの制御を求める開発者向けです。重い JavaScript サイトを見ると「この裏に API があるはずだ」と直感する人には、まさにその感覚のために作られたツールです。セレクタを書くのが苦にならず、ネットワークタブを読めて、抽出ロジックを最後まで自分で持ちたい人ほど恩恵があります。静的サイト、ページネーション付きのカタログ、発見可能な JSON エンドポイントがある対象なら、速くて正確です。
一方で、spider コードを書いて保守すること自体に時間を使いたくないなら、あるいは対象が完全にクライアント側で描画され、再現可能なリクエストもなく、headless ブラウザを自分で組み込みたくないなら、Scrapy は最適ではありません。URL を渡すだけで、抽出ルールを書かずにきれいな構造化出力を得たいという期待も、もともと Scrapy の担当ではありませんし、そういうフリもしていません。
代替案と、Thunderbit が入る位置
まず理解しておくべきなのは、これが無料のオープンソースフレームワークであり、自分で運用・保守する前提だということです。spider も依存関係も、各サイトのデータリクエストを見つける作業も、すべて自分の責任です。その代わり、リクエストごとの課金はなく、データは社内に留まり、細部までコントロールできます。多くのチームにとって、それは正しい選択です。このレビューは、それをやめさせるためにあるわけではありません。
違いが出るのはレンダリングと変化への追従の部分で、Scrapy の答えは「そこは自分で解決する」です。API を探し、リクエストを再現し、API がないケースはブラウザを自分で組み込んで対処します。管理型の AI スクレイピング API は、その層をまとめて肩代わりしてくれます。技術者向けにいうと、Thunderbit の開発者向けスタックはその位置にあります。つまり、ブラウザ拡張ではなく、AI スクレイピング API + MCP サーバー + CLI のセットです。営業・運用チーム向けの拡張機能とは別物です。POST /distill はページをきれいな LLM 向け Markdown に変換し、POST /extract は指定したスキーマに従う構造化 JSON を返します。どちらも JavaScript レンダリング、対ボット対策、動的コンテンツをサーバー側で処理します。Scrapy がブラウザを使うよう求める、クライアント描画のケースも含みます。AI エージェントやコーディングアシスタント向けの MCP サーバーもあり、ページの項目候補を事前に確認できる無料の thunderbit_suggest_fields も使えます。さらに npx @thunderbit/thunderbit-cli から使える CLI もあるので、ターミナル、CI、cron でも運用できます。
違いは品質ではなく、責任の持ち方です。Scrapy は明示的なエンジニアリングフレームワークで、spider、パイプライン、JS 対応戦略まで自分で管理します。その代わり、1回ごとの実行コストなしで完全な制御が手に入ります。Thunderbit のスタックは、レンダリングと抽出の層を管理サービスとして引き受けるので、ネットワークタブを掘り起こす手間がなくなり、その代わりに実行ごとに課金されます。小規模で、コード中心で、すべての手順を自分で持ちたいなら、Scrapy のコントロール性のほうが合っています。100サイト規模に広げたくて、サイトごとに手でリクエストを再現したくないなら、管理型の方法がその手間を丸ごと消してくれます。
より広い比較対象としては、こちらのベンチマーク記事も参考になります。オープンソーススクレイパー総比較、Colly のブラウザ不要 Go クローラーレビュー、Scrapling の適応型セレクターレビュー です。
結論
Scrapy を使うべきか? 答えは yes です。ただし、あなたが制御を求める開発者であり、「ページを描画するのではなく、その裏のリクエストを見つける」という考え方に納得できるなら、です。検証では、その思想は宣伝どおりに機能しました。JavaScript カタログは HTTP フェッチャーに 0 件しか返しませんでしたが、そこにデータを供給していた JSON API は同じ spider に 8/8 件を返しました。静的抽出は 12/12 件、記事のセレクタは 3/3 段落を定型文からきれいに分離し、クロールグラフは 11 ページにわたって深さ制限を守り、500 はクラッシュではなく処理済みステータスとして返りました。
ただし、期待値は正しく持つべきです。Scrapy は JavaScript をレンダリングしませんし、API を自動で見つけてもくれません。その反射神経は自分で身につける必要があります。依存関係の層はフレームワーク相応に厚く、今回は問題なくても、特殊なプラットフォームでは痛みが出ることがあります。さらに、今回の検証は fixture とデモページ中心で、千ページ規模のクロールは試していないため、スケール面は有望ではあっても未証明として扱うべきです。その範囲内では、Scrapy は Web ページを最短で抜けるための、静かにラディカルな発想を最後まで貫くツールです。たいていの場合、Web ページを通るのではなく、Web ページの外側を通るのが最速なのです。
Web データ抽出に Thunderbit を試す Get Started Free
FAQ
Scrapy は JavaScript で描画されるページをスクレイピングできますか?
デフォルトの HTTP フェッチャーではできません。JS の検証用ページでも公開されている Quotes の JS ページでも、ブラウザを動かさず HTML だけを取得するため、ノード数は 0 でした。想定されている流れは、ページが裏で呼び出しているデータリクエストを見つけて、それを直接叩くことです。私の検証では、JS カタログの背後にある JSON API から 8 件すべて取得できました。再現可能なリクエストが存在しないページでは、headless ブラウザを自分で組み込みます。
「リクエストを再現する」とは、実際にはどういう意味ですか?
多くの動的ページは、裏側で JSON API からデータを読み込み、その後にクライアント側で描画します。ブラウザでその様子を見る代わりに、ネットワークタブを開いてその API 呼び出しを見つけ、Scrapy から直接そこへ送ります。レンダリングより速く、安定性も高いです。API 契約は DOM より壊れにくいからです。ただし手作業であり、Scrapy がエンドポイントを探してくれるわけではありません。
Scrapy のインストールは難しいですか?
私の環境では問題ありませんでした。macOS の新しい venv に pip install Scrapy==2.17.0 を入れ、バイナリ wheel だけでコンパイルエラーなく完了しました。ただし、Twisted、lxml、cryptography、pyOpenSSL、parsel、tldextract などの大きめのスタックを取り込むので、公式ドキュメントが案内している通り、特殊な環境では依存関係の摩擦に注意が必要です。
Scrapy はどんな出力形式に対応していますか?
標準では JSON、JSON Lines、CSV、XML の feed export に対応しています。spider をファイルに向ければ、追加コードなしで item をそのまま出力できます。私の検証では、1回の実行で JSON と CSV の両方が生成されました。なお、出力されるのは選んだフィールドであって、ページ全体を自動で Markdown に整形してくれるわけではありません。
Scrapy は商用利用できますか?
BSD-3-Clause なので、かなり自由度が高く、商用利用にも向いています。もちろん、実際に組み込む前には リポジトリ 上の最新ライセンスを確認してください。また、user-agent、proxy、レート制限の設定は責任を持って行いましょう。できることと、やってよいことは別です。


