【初心者向け】PHPを使ってスクレイピングをする方法をわかりやすく解説
PHPでスクレイピングを始めるなら、「HTTPでHTMLを取得して、DOMで必要な要素を抜き出す」が基本です。本記事では、cURL(またはGuzzle)で取得し、DOMDocument/XPathやSymfony DomCrawlerで抽出する手順を、失敗しやすいポイントも含めて整理します。
- PHPでHTMLを取得し、要素を抽出する基本手順
- DOMDocument・XPathとDomCrawlerの使い分け
- 失敗を減らすエラー処理とマナー(負荷・規約)
スクレイピング概要
スクレイピングは、Webページ(主にHTML)から必要な情報を取り出して加工・保存する一連の処理です。初心者が最初に押さえるべき構成は次の2段階です。
- HTTPでページを取得する(GET)
- HTMLを解析して、必要な要素を抽出する(DOM/CSS/XPath)
まずは静的ページから始めるのがおすすめです。JavaScriptで描画されるページ(動的ページ)は、取得したHTMLに目的の要素が含まれないことが多く、難易度が上がります。
事前に確認すること
規約とrobots.txt
スクレイピングを始める前に、対象サイトの利用規約・ガイドライン、そしてrobots.txtを確認してください。robots.txtはクローラ向けのアクセス方針を示す仕組みとして標準化されています(Robots Exclusion ProtocolはRFC 9309として文書化)。
注意: robots.txtの許可・禁止は「技術的に強制するもの」ではありませんが、運用上の重要な合意事項です。禁止されているパスの収集や高頻度アクセスは、ブロックや法的トラブルにつながる可能性があります。
取得方式の見極め
- 静的HTML: cURL/Guzzleで取得→DOM解析でOK
- 動的描画: APIが裏にある場合はAPIを叩く(規約の範囲で)/ブラウザ自動化が必要になることも
全体フロー
実装の流れを最短で掴むために、最小構成を先に提示します。
- URLにGETしてHTML文字列を得る
- 文字化け対策(必要なら)
- DOMとしてパースする
- XPath/CSSセレクタで要素を特定して抽出
- 保存(CSV/DB/JSON)
HTMLを取得する
cURLで取得する
PHP標準のcURL拡張で取得する方法です。User-Agentの設定、リダイレクト追従、タイムアウト、文字コードなどを最低限入れておくと失敗が減ります。PHPのcURL利用例として、CURLOPT_RETURNTRANSFERやCURLOPT_FOLLOWLOCATION、CURLOPT_USERAGENTなどが一般的に使われます。
<?php
$url = 'https://example.com/';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 20,
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; MyScraper/1.0; +https://example.com/bot)',
]);
$html = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($html === false) {
throw new RuntimeException('cURL error: ' . $error);
}
if ($httpCode < 200 || $httpCode >= 300) {
throw new RuntimeException('HTTP error: ' . $httpCode);
}
echo $html;ポイント: 一部サイトはUser-Agent未設定だと403になることがあります。最低限のUA設定と、タイムアウト設定は入れておきたいところです。
Guzzleで取得する
実務では、HTTPクライアントとしてGuzzleを使うと、例外処理・ヘッダ管理・ミドルウェアなどが整理しやすくなります。Guzzleは「PHP HTTP client」として機能を提供し、Composerで導入できます。github.com
composer require guzzlehttp/guzzle<?php
require __DIR__ . '/vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client([
'timeout' => 20,
'connect_timeout' => 10,
'headers' => [
'User-Agent' => 'Mozilla/5.0 (compatible; MyScraper/1.0; +https://example.com/bot)',
],
]);
$response = $client->request('GET', 'https://example.com/');
$html = (string) $response->getBody();
echo $html;HTMLを解析する
DOMDocumentの注意
PHPのDOMDocumentでHTMLを読み込むにはDOMDocument::loadHTML()を使います。ただし公式ドキュメントでは、loadHTML()はHTML4パーサであり、モダンHTML(HTML5)のパースルールと差が出る可能性がある点、そして無害化目的で安全に使えない点が明確に警告されています。php.net
注意: 「ブラウザで見えているDOM」と「DOMDocumentが作るDOM」が一致しないケースがあります。要素が取れないときは、(1)取得HTMLが想定と違う (2)動的描画 (3)パース差分 の順で疑ってください。
XPathで抽出する
DOMDocumentとDOMXPathを組み合わせると、追加ライブラリなしで抽出できます。エラー抑制と後処理をするために、libxmlの内部エラー管理も合わせて使うのが定番です。libxmlはエラーを内部に保持でき、後から取り出して処理できます。php.net
<?php
libxml_use_internal_errors(true);
autoload(); // 必要に応じて
$html = '<html><body><h1 class="title">Hello</h1></body></html>';
$dom = new DOMDocument();
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query("//h1[@class='title']");
if ($nodes !== false && $nodes->length > 0) {
echo trim($nodes->item(0)->textContent);
}
libxml_clear_errors();DomCrawlerで抽出
SymfonyのDomCrawlerを使うと、CSSセレクタで直感的に抽出できます。公式ドキュメントでも、CrawlerがHTML/XMLをたどり、CSSセレクタ(filter())やXPath(filterXpath())でノードを選択できることが説明されています。symfony.com
composer require symfony/dom-crawler symfony/css-selector<?php
require __DIR__ . '/vendor/autoload.php';
use Symfony\Component\DomCrawler\Crawler;
$html = '<html><body><h1 class="title">Hello</h1></body></html>';
$crawler = new Crawler($html);
$title = $crawler->filter('h1.title')->text();
echo trim($title);使い分け: 小規模・依存を増やしたくないならDOMDocument+XPath。抽出が増える・CSSセレクタで書きたいならDomCrawlerが便利です。
実用テンプレ
「取得→抽出」を1ファイルで回せる、学習用の最小テンプレです(静的ページ想定)。
<?php
// 1) 取得
function fetchHtml(string $url): string {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 20,
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; MyScraper/1.0; +https://example.com/bot)',
]);
$html = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($html === false) {
throw new RuntimeException('cURL error: ' . $error);
}
if ($httpCode < 200 || $httpCode >= 300) {
throw new RuntimeException('HTTP error: ' . $httpCode);
}
return $html;
}
// 2) 抽出(XPath)
function extractTitles(string $html): array {
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query("//h2");
$titles = [];
if ($nodes !== false) {
foreach ($nodes as $node) {
$titles[] = trim($node->textContent);
}
}
libxml_clear_errors();
return $titles;
}
$url = 'https://example.com/';
$html = fetchHtml($url);
$titles = extractTitles($html);
foreach ($titles as $t) {
echo $t . PHP_EOL;
}よくある失敗
取得HTMLが空
- 403/429(アクセス制限): User-Agent、アクセス頻度、IP、Cookie要件を確認
- リダイレクト先でブロック:
CURLOPT_FOLLOWLOCATIONの有無を確認 - タイムアウト: 接続/全体タイムアウトを調整
要素が取れない
- ページが動的描画で、HTML内に目的要素が無い
- DOMDocumentのパース差分でDOM構造が変わる(HTML4パーサ警告に該当)php.net
- セレクタが弱い(クラス名変更に弱い)
libxmlの警告が多い
壊れたHTMLでは警告が出やすいです。libxmlの内部エラー管理を使い、必要ならエラー内容をログに回してください。php.net
ライブラリ比較
初心者が選びやすいように、取得と抽出を分けて比較します。
| 用途 | 選択肢 | 強み | 弱み |
|---|---|---|---|
| HTTP取得 | cURL | 標準機能で完結しやすい | 実装が手続き的になりやすい |
| HTTP取得 | Guzzle | HTTP周りの整理がしやすい(PSR対応など) | Composer導入が前提 |
| HTML抽出 | DOMDocument+XPath | 軽量・依存が少ない | HTML5とのパース差分が出ることがある |
| HTML抽出 | Symfony DomCrawler | CSSセレクタで書けて保守しやすい | ライブラリ導入が必要 |
公式仕様の要点
DOMDocument::loadHTMLはHTML4パーサを使い、HTML5のパースルールとは異なるため、DOM構造が異なる可能性がある(公式ドキュメントの警告)。php.net
「取れない=コードが悪い」と決めつけず、パーサ仕様や取得できているHTML自体を検証するのが近道です。
安全に運用する
アクセス頻度を抑える
- 1リクエストごとに待機(例: 1〜3秒)
- リトライは上限回数を決める
- 429/503が出たら中断・間隔を延ばす
取得結果をキャッシュ
同じページを何度も取得しないだけで、ブロックや負荷のリスクが下がります。学習段階でも、取得HTMLをローカルに保存して解析を繰り返すと効率的です。
収集を自動化しませんか?
スクレイピングの設計から運用(ブロック対策・監視・安定稼働)まで一貫して相談できます。要件に合わせて安全な収集フローをご提案します。
まとめ
- PHPスクレイピングは「取得(cURL/Guzzle)+抽出(XPath/DomCrawler)」が基本
- DOMDocumentはHTML5と差分が出ることがあるため、取れないときは仕様と取得HTMLを確認
- 規約・robots.txt確認、低頻度アクセス、キャッシュで安全に運用する