curlコマンドは、静的なHTMLを取得する分にはシンプルかつ高速なツールです。
しかし、JavaScriptによってDOMが構築されるSPA(Single Page Application)やAjaxで後から読み込まれるコンテンツを対象にすると、期待したデータが取得できず、空のタグや骨組みだけのHTMLが返ってくるという壁にぶつかった経験がある方も多いのではないでしょうか。
これはcurlの不具合ではなく、そもそもの仕組み上の制約に起因しています。
curlはHTTPリクエストを送り、サーバーから返却されたレスポンスをそのまま出力するだけであり、ブラウザのようにJavaScriptエンジンを内蔵していません。
つまり、レンダリング前の「素材」であるHTMLしか取得できず、クライアントサイドで実行される描画処理の結果は反映されないのです。
この仕組みを理解せずにcurlだけで解決しようとすると、無駄な試行錯誤を重ねることになります。
本記事では、こうした技術的背景を踏まえたうえで、動的コンテンツを確実に取得するための実践的なアプローチを整理して解説します。
具体的には、APIエンドポイントを直接叩く方法、ヘッドレスブラウザを併用する方法、レンダリング後のHTMLを取得できる外部サービスを利用する方法といった選択肢を、それぞれのメリットとデメリット、そして適用すべき場面とともに比較していきます。
単なる小手先のテクニックではなく、なぜその手法が有効なのかという原理から理解することで、今後同種の問題に直面した際にも応用が利く知識を身につけていただければと思います。
なぜcurlでは動的コンテンツが取得できないのか?仕組みを理解する

curlを使ってWebページを取得した際、ブラウザで見えているはずの情報が欠落しているという経験は、スクレイピングに取り組んだことがある方であれば一度は直面する問題ではないでしょうか。
この現象を正しく解決するためには、まずcurlが何を取得し、何を取得していないのかという仕組みのレベルから理解する必要があります。
原因を特定しないまま対処療法的な手法を試しても、根本的な解決には至りません。
HTTPリクエストとレスポンスの基本構造
curlの動作は非常にシンプルで、指定したURLに対してHTTPリクエストを送信し、サーバーから返却されたレスポンスをそのまま標準出力に書き出すだけです。
curl -X GET https://example.com/page
このコマンドを実行すると、サーバーが返すHTMLソースがそのまま出力されます。
重要なのは、ここで取得できるのはあくまでサーバーが最初に返す素のHTMLであり、ブラウザ上で表示される完成形のページとは異なるという点です。
サーバーサイドでレンダリングされている静的サイトであれば問題ありませんが、クライアントサイドで処理が行われるページでは、この時点で情報が不足しています。
JavaScriptレンダリングとDOM構築の仕組み
現代の多くのWebサイトは、初期HTMLを最小限にとどめ、JavaScriptによってDOM(Document Object Model)を動的に構築する設計を採用しています。
ブラウザは以下のような手順でページを完成させます。
- サーバーから初期HTMLを受信する
- HTMLに埋め込まれた、あるいは外部読み込みされたJavaScriptファイルを取得する
- JavaScriptエンジンがスクリプトを実行し、DOMに要素を追加・変更する
- 完成したDOMをレンダリングし、画面に表示する
curlはこのうち1のステップまでしか実行できません。
JavaScriptエンジンを持たないため、2以降の処理が一切行われず、結果として骨組みだけのHTMLが返ってくることになります。
SPAとAjaxコンテンツが空になる原因
特にReactやVueといったフレームワークで構築されたSPA(Single Page Application)では、初期HTMLに<div id="root"></div>のような空のコンテナしか存在しないケースが一般的です。
実際のコンテンツはすべてJavaScriptによって後から挿入されるため、curlで取得した時点では中身が空になります。
また、一覧ページなどでAjax通信により追加データを非同期取得している場合も同様です。
ページ読み込み後にユーザーの操作やタイマーをきっかけとして別途APIリクエストが発行され、そのレスポンスがDOMに反映される仕組みになっているため、初期HTMLだけを見ても該当データは存在しません。
この構造を理解することが、次章以降で紹介する解決策を選ぶうえでの土台になります。
動的コンテンツ取得前に確認すべき事前調査のポイント

前章で解説した通り、動的コンテンツの多くはJavaScriptによる後処理を経て初めて画面に表示されます。
ここで安易にヘッドレスブラウザの導入に踏み切る前に、まず行うべきなのが事前調査です。
多くの場合、目的のデータは裏側でAPI通信によって取得されており、そのエンドポイントを特定できれば、curlだけで軽量かつ高速に目的を達成できます。
事前調査を怠ると、本来不要な重量級のツールを導入してしまい、無駄な開発コストと運用コストを抱えることになりかねません。
ブラウザの開発者ツールでネットワーク通信を確認する方法
対象ページがどのようにデータを取得しているかを調べるには、ブラウザの開発者ツールが最も有効な手段です。
ChromeやFirefoxであれば、以下の手順で通信内容を確認できます。
- 対象ページを開き、キーボードの
F12キーを押して開発者ツールを起動する - Network(ネットワーク)タブを選択する
- ページをリロードするか、対象の操作(スクロールやボタンクリックなど)を実行する
- 発生した通信の一覧から、目的のデータを含んでいそうなリクエストを探す
この時点で通信量が多い場合は、ファイルタイプによる絞り込み機能を使うと効率的です。
画像や静的なスクリプトファイルを除外し、データ通信のみに焦点を当てることで、目的のリクエストを見つけやすくなります。
XHR/Fetchリクエストの特定手順
開発者ツールのNetworkタブには、通信の種類を絞り込むフィルタ機能が備わっています。
ここでXHRまたはFetchを選択することで、JavaScriptから発行された非同期通信のみを一覧表示できます。
目的のリクエストを特定できたら、以下の観点を確認しておくと、後の実装作業が円滑に進みます。
| 確認項目 | 内容 | 確認する理由 |
|---|---|---|
| リクエストURL | エンドポイントのパスとクエリパラメータ | curlで再現する際のURLの基礎になる |
| リクエストメソッド | GET/POST等の種別 | 誤ったメソッドではレスポンスが得られない |
| リクエストヘッダー | Authorization、Cookie等の付与情報 | 認証やセッション維持に必要な情報を把握する |
| レスポンス形式 | JSON/HTML等のデータ形式 | 取得後の解析方法を決定する材料になる |
特に注意すべきは、ブラウザが自動的に付与しているヘッダーやCookieの存在です。
これらが欠けていると、サーバー側で不正なリクエストと判断され、正常なレスポンスが返ってこない場合があります。
該当リクエストを右クリックし、Copy as cURLを選択することで、ブラウザが実際に送信したリクエストの内容をcurlコマンドの形式でそのまま取得できるため、次章で解説する再現作業の大きな助けとなります。
APIエンドポイントを直接叩いて動的データを取得する方法

前章の事前調査でAPIエンドポイントを特定できていれば、あとはそのリクエストをcurlで再現するだけで目的のデータを取得できます。
ヘッドレスブラウザのようにJavaScriptエンジンやレンダリングプロセスを起動する必要がないため、実行速度が速く、サーバーリソースの消費も最小限に抑えられます。
ここでは、特定したAPIリクエストを実際にcurlで再現していく具体的な手順を解説します。
curlでAPIリクエストを再現する手順
開発者ツールでCopy as cURLによって取得したコマンドをベースに、必要な要素だけを整理していきます。
基本的なGETリクエストであれば、以下のような形になります。
curl -X GET "https://example.com/api/v1/items?page=1&limit=20"
POSTリクエストでデータを送信する必要がある場合は、-dオプションでリクエストボディを指定します。
curl -X POST "https://example.com/api/v1/search" \
-H "Content-Type: application/json" \
-d '{"keyword": "sample", "sort": "new"}'
この際、開発者ツールで確認したリクエストメソッドとボディの形式を正確に一致させることが重要です。
形式が異なると、サーバー側でリクエストを正しく解釈できず、エラーレスポンスが返されることがあります。
リクエストヘッダーとCookieの設定方法
多くのAPIでは、ブラウザからのリクエストであることを前提としたヘッダー検証や、認証情報を含むCookieの送信を求めています。
これらが不足していると、正常なレスポンスが得られません。
代表的なヘッダーには以下のようなものがあります。
| ヘッダー名 | 役割 | 設定が必要になるケース |
|---|---|---|
| User-Agent | クライアントの種別を示す | ボット判定を回避する必要がある場合 |
| Authorization | 認証トークンを付与する | ログインが必要なAPIにアクセスする場合 |
| Referer | リクエスト元のページを示す | リファラチェックを行うサーバーの場合 |
| Cookie | セッション情報を保持する | ログイン状態を維持する必要がある場合 |
curlでこれらを付与する場合は、-Hオプションと-bオプションを組み合わせます。
curl -X GET "https://example.com/api/v1/items" \
-H "User-Agent: Mozilla/5.0" \
-H "Authorization: Bearer YOUR_TOKEN" \
-b "session_id=abcdef123456"
Cookieについては、認証後にサーバーから発行された値をブラウザの開発者ツールから確認し、そのまま設定するのが確実です。
レスポンスがJSON形式の場合の解析方法
APIから返却されるレスポンスは、多くの場合JSON形式です。
curl単体では整形されていない状態で出力されるため、可読性を高めたり、特定のフィールドだけを抽出したりするには、jqコマンドを組み合わせるのが効果的です。
curl -s "https://example.com/api/v1/items" | jq '.items[] | {name, price}'
このように取得したレスポンスをパイプでjqに渡すことで、必要な項目だけを抽出したり、後続のシェルスクリプトやバッチ処理に連携させたりすることが容易になります。
APIから直接データを取得できるこの方法は、動的コンテンツ取得における最も効率的な選択肢と言えますが、エンドポイントの仕様が非公開であったり、認証が複雑であったりする場合には、次章で紹介するヘッドレスブラウザの活用も検討する必要があります。
ヘッドレスブラウザを活用したスクレイピングの実践

APIエンドポイントが特定できない、あるいは認証やトークンの仕組みが複雑でリクエストの再現が困難な場合には、ヘッドレスブラウザの活用が有効な選択肢となります。
ヘッドレスブラウザとは、画面描画を行わずにバックグラウンドで動作するブラウザのことで、実際のブラウザと同様にJavaScriptを実行し、DOMを構築できるため、curlでは取得できなかった動的コンテンツも問題なく取得できます。
ここでは代表的な3つのツールについて、それぞれの特徴と実装方法を解説します。
Puppeteerによる動的コンテンツ取得の基本
Puppeteerは、Google Chromeの開発チームが提供しているNode.js向けのライブラリで、Chrome DevTools Protocolを通じてブラウザを直接制御します。
導入が容易で情報量も豊富なため、ヘッドレスブラウザによるスクレイピングの入門としてよく選ばれています。
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com', { waitUntil: 'networkidle0' });
const content = await page.content();
console.log(content);
await browser.close();
})();
waitUntil: 'networkidle0'のようなオプションを指定することで、Ajax通信が完了しネットワークが落ち着いたタイミングを待ってからHTMLを取得できます。
これにより、JavaScriptによる描画が完了した状態のDOMを確実に取得することが可能になります。
Playwrightを使った実装例
Playwrightは、Microsoftが開発しているブラウザ自動化ライブラリで、Chromium、Firefox、WebKitという複数のブラウザエンジンに対応している点がPuppeteerとの大きな違いです。
特定のブラウザに依存した挙動の差異を検証したい場合や、より堅牢な自動化処理を組みたい場合に適しています。
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://example.com", wait_until="networkidle")
content = page.content()
print(content)
browser.close()
Pythonでの実装例のように、複数言語向けの公式ライブラリが用意されている点もPlaywrightの強みであり、既存のプロジェクトの言語構成に合わせて柔軟に選択できます。
Seleniumとの比較検討
Seleniumは、ブラウザ自動化ツールとして最も歴史が長く、対応言語やブラウザの種類も豊富です。
ただし、近年の新規プロジェクトにおいては、後発のPuppeteerやPlaywrightの方が採用されるケースが増えています。
それぞれの特徴を整理すると、以下のようになります。
| 項目 | Puppeteer | Playwright | Selenium |
|---|---|---|---|
| 対応ブラウザ | Chromium系が中心 | Chromium/Firefox/WebKit | 主要ブラウザ全般 |
| 対応言語 | JavaScript/TypeScript | JS/Python/Java/C#等 | 多言語対応 |
| 実行速度 | 高速 | 高速 | やや低速な傾向 |
| 学習コストの目安 | 低い | 低い | 中程度 |
新規でスクレイピング環境を構築する場合は、実行速度と対応ブラウザの幅広さを兼ね備えたPlaywrightが有力な候補となりますが、既存システムにSeleniumを用いた資産が存在する場合は、無理に置き換える必要はありません。
プロジェクトの状況に応じて適切なツールを選択することが重要です。
curlとヘッドレスブラウザのパフォーマンスと運用コストを比較する

ここまで、APIエンドポイントを直接叩く方法とヘッドレスブラウザを利用する方法という2つのアプローチを紹介してきました。
どちらも動的コンテンツを取得できる手段ではありますが、実際の運用を考えるうえでは、パフォーマンスと運用コストの違いを正しく把握しておく必要があります。
手段の選択を誤ると、想定していなかったサーバー費用の増大や処理時間の遅延を招くことになりかねません。
実行速度とリソース消費量の違い
curlによるAPI直接アクセスと、ヘッドレスブラウザによるレンダリングでは、処理の重さが根本的に異なります。
curlはHTTPリクエストとレスポンスの送受信のみを行うシンプルな処理であるのに対し、ヘッドレスブラウザはブラウザプロセス自体の起動、JavaScriptエンジンの実行、DOMの構築、レンダリングという複数の重い処理を内部で行っています。
両者の違いを整理すると、以下のようになります。
| 項目 | curl(API直接) | ヘッドレスブラウザ |
|---|---|---|
| 処理内容 | HTTP通信のみ | ブラウザ起動+JS実行+DOM構築 |
| 実行速度 | 高速(ミリ秒単位) | 低速(秒単位になることが多い) |
| メモリ消費量 | 少ない | 多い(ブラウザプロセス分が加算される) |
| 同時実行時の負荷 | 低い | 高い |
特に大量のページを並列でスクレイピングする必要があるバッチ処理においては、この差は顕著に現れます。
ヘッドレスブラウザを数十プロセス同時に起動すると、メモリ不足やCPU使用率の高騰によって処理全体が不安定になることも珍しくありません。
そのため、可能な限りAPIエンドポイントを直接叩く方法を優先し、それが不可能な場合に限ってヘッドレスブラウザを採用するという判断基準を持つことが、安定した運用につながります。
サーバー環境での運用における注意点
ヘッドレスブラウザを本番環境やサーバー上で稼働させる場合には、ローカル開発環境とは異なるいくつかの注意点があります。
- ブラウザ本体の依存ライブラリをサーバーに事前インストールしておく必要がある
- コンテナ環境で実行する場合、公式が提供するDockerイメージを利用すると依存関係の管理が容易になる
- 同時実行数を制限し、メモリやCPUの上限を超えないよう設計する
- 長時間稼働させる場合、ブラウザプロセスのメモリリークを想定し、定期的な再起動処理を組み込む
また、クラウド環境でサーバーレス関数として実行する場合には、実行時間の上限やパッケージサイズの制限に注意する必要があります。
ヘッドレスブラウザはバイナリサイズが大きいため、軽量版のビルドを利用したり、専用のレイヤーを用意したりといった工夫が求められる場面もあります。
こうした運用コストを事前に見積もったうえで、curlによるAPI直接アクセスとヘッドレスブラウザのどちらを採用するかを判断することが、長期的に安定したスクレイピング基盤を構築するうえで欠かせない視点となります。
動的コンテンツを取得できるレンダリング代行サービスの活用

自前でヘッドレスブラウザの実行環境を構築・運用することが難しい場合や、そもそも運用の手間そのものを省きたいという場合には、レンダリングを代行してくれる外部サービスの活用が有効な選択肢となります。
これらのサービスは、リクエストされたURLをサービス側のサーバー上でレンダリングし、完成したHTMLやスクリーンショットをレスポンスとして返却してくれるため、開発者側はブラウザの起動やメンテナンスから解放されます。
主要なレンダリングAPIサービスの紹介
レンダリング代行サービスは複数存在しており、それぞれ特徴が異なります。
代表的なサービスの傾向を整理すると、以下のようになります。
| 特徴 | 概要 | 適した用途 |
|---|---|---|
| シンプルなレンダリングAPI | URLを渡すだけでHTMLを返却する | 単純な動的ページの取得 |
| プロキシ機能付きサービス | IPローテーションやCAPTCHA回避機能を持つ | 大規模かつ継続的な収集 |
| スクリーンショット特化型 | ページ画像として取得できる | 見た目の検証や監視用途 |
これらのサービスの多くはREST APIとして提供されているため、利用方法自体はcurlによるAPI直接アクセスとほぼ同様です。
curl "https://render-api.example.com/v1/render?url=https://target-site.com&api_key=YOUR_API_KEY"
このように、対象URLとAPIキーをパラメータとして渡すだけで、レンダリング済みのHTMLを取得できる仕組みになっているサービスが一般的です。
自社でヘッドレスブラウザのインフラを構築する手間を、月額または従量課金の費用に置き換えられる点が、このアプローチの最大の利点と言えます。
導入時のコストと制限事項
レンダリング代行サービスは運用の手間を大幅に削減できる一方で、いくつか確認しておくべき制限事項があります。
- 多くのサービスはリクエスト回数に応じた従量課金制、または月間リクエスト数に上限のあるプラン制を採用している
- 対象サイトによっては、サービス側のIPアドレスがすでにブロック対象となっている場合がある
- レンダリングの完了を待つ時間が加算されるため、自前のAPI直接アクセスと比較するとレスポンスは遅くなる傾向がある
- 機密性の高い情報を扱うページを対象とする場合、外部サービスを経由すること自体がセキュリティポリシー上の問題になり得る
特に大量のページを継続的に取得する必要がある場合には、リクエスト数に応じたコストが積み重なり、想定以上の費用負担になることもあります。
小規模かつ一時的な用途であればコストメリットが大きい一方、大規模な運用を見込む場合は、自前でヘッドレスブラウザ環境を構築するコストとの比較検討を事前に行っておくことをおすすめします。
用途の規模と継続性を軸に、外部サービスの利用と自前実装のどちらが適しているかを見極めることが重要です。
スクレイピング実装時に注意すべき法的・倫理的な観点

ここまで技術的なアプローチを中心に解説してきましたが、スクレイピングを実装するうえで技術と同じくらい重要なのが、法的・倫理的な観点への配慮です。
技術的に取得可能であることと、取得してよいことは必ずしも一致しません。
対象サイトの運営者との無用なトラブルを避けるためにも、実装に着手する前に確認しておくべき事項を整理しておきます。
robots.txtと利用規約の確認方法
多くのWebサイトでは、サイトのルートディレクトリにrobots.txtというファイルを設置し、検索エンジンのクローラーやその他のボットに対して、アクセスを許可する範囲を示しています。
curl "https://example.com/robots.txt"
このコマンドで内容を確認できます。
Disallowディレクティブで指定されているパスは、クロールを許可しないという意思表示であるため、原則として対象から除外すべきです。
また、robots.txtはあくまで技術的な取り決めであり、法的な拘束力を持つものではありません。
より重要なのは、サイトの利用規約です。
利用規約の中には、自動化されたアクセスやデータの収集・再配布を明示的に禁止している場合があります。
以下のような項目を事前に確認しておくと、後々のトラブルを未然に防げます。
- 自動化ツールによるアクセスの可否
- 取得したデータの商用利用や再配布に関する制限
- 著作権や個人情報保護に関する記載
特に個人情報や著作物を含むデータを取得する場合には、取得後の利用方法についても慎重に検討する必要があります。
アクセス頻度とサーバー負荷への配慮
robots.txtや利用規約上で問題がないと確認できた場合でも、対象サーバーに過度な負荷をかけない配慮は欠かせません。
短時間に大量のリクエストを送信すると、対象サイトのサーバーリソースを圧迫し、他の一般利用者のアクセスに支障をきたす可能性があります。
場合によっては、意図せずDoS攻撃に近い状態を引き起こしてしまうリスクも存在します。
具体的な配慮として、以下のような実装が推奨されます。
- リクエストとリクエストの間に、一定の待機時間(スリープ)を設ける
- 同時接続数を必要最小限に制限する
- 可能であれば、アクセスが少ない時間帯を選んで実行する
robots.txtにCrawl-delayが指定されている場合は、その値に従う
これらは技術的にはsleep関数やライブラリのレート制限機能を用いることで容易に実装できますが、根底にあるのは対象サイトの運営者やインフラに対する配慮という姿勢です。
スクレイピングという技術は非常に強力である一方、使い方を誤れば相手に実害を与えかねません。
技術的な実装力と同じだけ、こうした倫理的な視点を持ち合わせることが、長期的に信頼される開発者としての姿勢につながると考えています。
まとめ:動的コンテンツ取得の実践アプローチを状況に応じて選択する

ここまで、curlが動的コンテンツを取得できない理由という技術的な背景から出発し、事前調査の方法、APIエンドポイントの直接活用、ヘッドレスブラウザの導入、レンダリング代行サービスの利用、そして法的・倫理的な配慮に至るまで、動的コンテンツ取得における一連の実践アプローチを解説してきました。
最後に、これらの選択肢をどのような基準で使い分けるべきかを整理しておきたいと思います。
まず前提として押さえておくべきなのは、curlそのものが劣っているツールなのではなく、単にJavaScriptを実行する機構を持たないという設計上の制約があるだけだという点です。
この制約を正しく理解したうえで、状況に応じた補完手段を選び取ることが、効率的なスクレイピング基盤を構築する第一歩になります。
本記事で紹介した各アプローチの特性を、選択の判断材料として改めて整理すると、以下のようになります。
| アプローチ | 適した状況 | 主なメリット | 主なデメリット |
|---|---|---|---|
| APIエンドポイント直接アクセス | 通信解析でAPIを特定できる場合 | 高速かつ軽量、サーバー負荷が低い | エンドポイント仕様の変更に弱い |
| ヘッドレスブラウザ | API特定が困難、複雑な操作が必要な場合 | あらゆる動的コンテンツに対応できる | 実行速度が遅く、リソース消費が大きい |
| レンダリング代行サービス | 自前でのインフラ構築を避けたい場合 | 運用の手間を大幅に削減できる | 従量課金によるコストが発生しやすい |
この表からも分かる通り、優先すべき順序としては、まず開発者ツールによる事前調査でAPIエンドポイントの特定を試み、それが困難な場合に初めてヘッドレスブラウザやレンダリング代行サービスといった、より処理コストの高い手段を検討するという流れが合理的です。
目的に対して過剰な手段を選んでしまうと、実行速度の低下やサーバーコストの増大という形で、後々の運用に負担がのしかかってきます。
また、どの手段を選ぶ場合であっても、対象サイトのrobots.txtや利用規約を確認し、アクセス頻度に配慮するという倫理的な姿勢は共通して欠かせません。
技術的に実現可能であることと、実行してよいことの間には常に一定の距離があるということを、実装者自身が意識しておく必要があります。
動的コンテンツの取得というテーマは、単なる小手先のテクニック集として捉えるのではなく、HTTP通信の仕組みやブラウザのレンダリングプロセスといった基礎的な原理から理解することで、初めて応用の利く知識として身につきます。
今回紹介したアプローチも、時間の経過とともに対象サイトの仕様変更やツールのアップデートによって、細部が変わっていく可能性は十分にあります。
しかし、なぜその手法が有効なのかという根本の理屈さえ押さえておけば、新しい状況に直面した際にも、適切な解決策を自ら組み立てられるはずです。
本記事が、皆さんのスクレイピング実装における判断の一助となれば幸いです。


コメント