Parallels Desktop 25%OFFセール中Go!

PHPでWebスクレイピングをする方法

PHPでWebスクレイピングをする方法

スクレイピングといえばPythonみたいな風潮がありますが、私はPHP派なのでPHPでWebスクレイピングをする方法を解説します。

目次

Webスクレイピングとは

Webスクレイピングとは、Webサイトから特定の情報を自動的に抽出する技術のことです。

Webスクレイピングを使うと、例えば、ショッピングサイトに掲載されている商品の価格を定期的に取得して、そのデータをグラフ化するなんてことができますね。

通常ならば、人間がブラウザを使って手動でデータ収集しなければならないところを、Webスクレイピングで自動化することができるわけです。わー、便利そう。

PHPでWebスクレイピングをする方法

PHPでWebスクレイピングをする方法としてよくphpQueryというライブラリの名前が上がるのですが、こちらとっくの昔に開発が停止しているようなので、使わないほうがよさそうです。

というわけで今回は、PHPに標準で入っている機能のfile_get_contents関数、DOMDocumentクラス、DOMXPathクラスを使ってみます。

基本的なスクレイピングの手順

//ターゲットURLの指定
$url = 'https://example.com/';

//HTMLソースの取得
$html = file_get_contents($url);

//HTMLの解析
$dom = new DOMDocument();
@$dom->loadHTML($html);

//必要なデータを抽出
$xpath = new DOMXPath($dom);
$elements = $xpath->query('//div[@class="foo"]');

//抽出したデータを出力
foreach ($elements as $element) {
  echo $element->nodeValue . PHP_EOL;
}

HTMLソースの取得

指定したURLのHTMLソースを文字列として取得し、$html変数に格納します。

HTMLの解析

DOMDocumentはHTMLやXML文書を解析するためのクラスです。

loadHTMLメソッドを使って、先ほど取得したHTMLを読み込みます。この時、HTMLに文法ミスがあるとエラーメッセージが出力されます。この出力を非表示にするために先頭に@を付けます。

世に出回っているHTML文書というのは大抵何かしらの文法ミスを含んでいます。完璧なHTML文書なんてほとんどありません。嘘だと思うなら@を外して実行してみてください。

必要なデータを抽出

XPathクエリを使って、DOM内の特定の要素を検索します。

queryメソッドの引数部分がXPathクエリです。//div[@class="foo"]は「class属性の値がfooのdiv要素」をあらわします。なんか難しそうですね。文法はあとで解説します。

抽出したデータを出力

$elementsには複数の要素が入っている可能性があるので、foreachで回して出力します。

文字化けする場合

現在、ほとんどのWebサイトの文字エンコーディングはUTF-8ですが、いにしえのホームページではShift_JISEUC-JPが使われていることもあります。その場合、抽出したデータが文字化けするかもしれません。

文字化け対策は次のようにします。

//HTMLソースの取得
$html = file_get_contents($url);
$html = mb_encode_numericentity($html, [0x80, 0xFFFF, 0, 0xFFFF], 'Shift_JIS');

mb_encode_numericentity関数は、文字をHTML数値エンティティにエンコードします。第3引数はターゲットサイトの文字エンコーディングに合わせてください。第2引数は変換するコード領域の指定です。考えることをやめてコピペしましょう。

XPathクエリの書き方

XPathクエリを使ってお目当てのHTML要素を見つけ出すわけですが、なかなか複雑な文法です。ざっくり解説します。

階層で指定

/html/body/h1

XPathではHTMLの階層構造を/で区切って表現します。上記の例は<html>の子要素の<body>の子要素の<h1>を指します。

階層を省略

/html/body//h2

//は階層の省略をあらわします。上記の例は<html>の子要素の<body>子孫要素<h2>を指します。子孫というのは、子と孫はもちろん、ひ孫や玄孫も含みます。

//h2

上記のように書くこともできます。DOM内のすべての<h2>にマッチします。

属性値で指定

//div[@id="foo"]

要素[@属性="属性値"]という形式で、任意の属性値を持つ要素を取り出すことができます。上記の例はid属性の値がfooと一致する<div>要素を指します。完全一致です。

属性値に文字列が含まれているか

//div[contains(@class, "foo")]

contains()を使うと部分一致で検索することができます。上記の例はclass属性の値がfooを含む<div>要素を指します。

要素の文字列で指定

//div[text()="ようこそ、ゾロアスター教の世界へ"]

text()を使って要素内の文字列を検索することができます。上記の例は<div>...</div>内の文字列がようこそ、ゾロアスター教の世界へと完全一致する場合にマッチします。

部分一致ならば次のように書きます。

//div[contains(text(), "ゾロアスター教")]

n番目の要素を取得

//ul/li[2]

[]で数値を囲んでn番目の要素を取得することができます。上記の例は<ul>の子要素の上から2番目の<li>を指します。

ワイルドカード

//*[@class="foo"]

*を使って任意の要素を指定することができます。上記の例はclass属性の値がfooのすべての要素にマッチします。

属性名にワイルドカードを指定することもできます。

//div[@*="foo"]

and, or, not

論理演算子and, or, notを使うことができます。

//div[contains(@class, "foo") and contains(@class, "var")]

上記の例はclass属性の値がfoovarを含む<div>を指します。

//div[contains(@class, "foo") or contains(@class, "var")]

上記の例はclass属性の値がfooまたはvarを含む<div>を指します。

//div[not(contains(@class, "foo"))]

上記の例はclass属性の値がfooを含まない<div>を指します。

Google ChromeでXPathを取得する方法

XPath難しいよ、わかんねーよというあなたに朗報です。ブラウザを使って簡単にXPathを調べることができます。

  1. Google Chromeでターゲットサイトを開きます。
  2. XPathを取得したい要素の上で右クリックして「検証」を選択します。
  3. デベロッパツールでハイライトされている要素の上で右クリックして「コピー > XPath をコピー」を選択します。

以上でXPathがクリップボードにコピーされます。

さいごに

PHPでWebスクレイピングをする方法について解説しました。意外と簡単でしたね。

ただし、気をつけなければならないこともあります。あまりにも頻繁にスクレイピングをすると相手のサーバに過大な負荷をかけてしまいます。また、取得するデータが著作物の場合は扱い方を間違えれば著作権の侵害になるおそれがあります。

そういった点にも配慮してレッツ・スクレイピング!

でわでわ

PHPでWebスクレイピングをする方法

この記事が気に入ったら
いいね または フォローしてね!

シェアしてね

コメント

コメントする

目次