PHPでDOMDocumentを使ってスクレイピング

(1/1)
Webサイトから情報を抽出することをスクレイピング(scraping)と呼ぶ。いままで紹介してきたPHPプログラムでは、正規表現などを使ってスクレイピングを行ってきた。
PHPバージョン5以上では、HTMLやXMLドキュメントをオブジェクトとして扱うことができる DOMDocumentクラスが用意されている。
そこで今回は、DOMDocumentクラスを使ってスクレイピングを行ってみることにする。

(2021年5月8日)PHP8対応,リファラ・チェック改良

サンプル・プログラムの実行例

PHPでDOMDocumentを使ってスクレイピング

目次

サンプル・プログラム

圧縮ファイルの内容
DOMscraping.phpサンプル・プログラム本体。

解説:DOMDocumentの使い方

0075: // クラス ===========================================================
0076: /**
0077:  * スクレイピング・クラス
0078: */
0079: class myscraping {
0080:     private $dom;        //DOMDocument
0081:     private $xpath;      //DOMXPath
0082:     private $error;      //エラーフラグ
0083: 
0084: /**
0085:  * コンストラクタ
0086:  * @param string $url取得対象URL
0087:  * @returnなし
0088: */
0089: function __construct($url) {
0090:     $this->error = FALSE;
0091:     $html = @file_get_contents($url);
0092:     if ($html == FALSE || $html == '') {
0093:         $this->error = TRUE;
0094:     } else {
0095:         $this->dom = new DOMDocument();
0096:         @$this->dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'auto'));
0097:         $this->xpath = new DOMXPath($this->dom);
0098:     }
0099: }

PHPでクラスを使ってテキストの読みやすさを調べる」で簡単なクラスの作り方を紹介したが、今回は、スクレイピングを行うユーザー定義クラス myscraping を用意し、その中で最初に呼ばれるメソッド「コンストラクタ」を使って DOMDocumentクラス を用意することにする。
まず、myscraping クラス内で使用する変数 $dom, $xpath, $error を宣言する。

コンストラクタは、__construct によって定義する。引数は、クラスを呼び出した時の引数である。ここでは取得対象のURLを引数とする。戻り値はない。

次に DOMDocumentクラスの使い方だが、DOMDocument でオブジェクトを生成したら、DOMDocument::loadHTML を使って文字列からHTMLを読み込む。

ここで、文字コードに注意しなければならない。
DOMDocument::loadHTML は、HTML文書に記載されている文字コードセットを解釈しないようで、UTF-8などの日本語文字が文字化けを起こす。そこで、DOMDocument::loadHTML に渡す前に、関数  mb_convert_encoding  を使って HTML-ENTITIES にエンコードしてやる。こうすることで、日本語文字などは16進数に変換されるので、文字化けを起こすことはなくなる。

解説:DOMDocumentの使い方

0101: /**
0102:  * デストラクタ
0103:  * @returnなし
0104: */
0105: function __destruct() {
0106:     unset($this->dom);
0107:     unset($this->xpath);
0108: }

クラスを解放する時にコールされるデストラクタを、念のために用意しておく。デストラクタは __destruct によって定義する。

クラス内のエラー処理だが、HTML文書の読み込みに失敗したらエラーフラグ $errorTRUE にするようにしている。これを iserror メソッドを使って取得する。

解説:DOMXPathの使い方

0118: /**
0119:  * XPath式の評価
0120:  * @param string $e XPath式
0121:  * @return string 評価結果/FALSE:評価失敗
0122: */
0123: function evalXPath($e) {
0124:     return $this->error ? FALSE : $this->xpath->evaluate("string({$e})");
0125: }

0127: /**
0128:  * titleを取得
0129:  * @return titleの内容
0130: */
0131: function getTitle() {
0132:     return $this->evalXPath('//title');
0133: }

0135: /**
0136:  * titleを取得
0137:  * @return titleの内容
0138: */
0139: function getDescription() {
0140:     return $this->evalXPath('//meta[@name="description"]/@content');
0141: }

読み込んだHTML文書を検索する方法はいくつかあるが、ここでは、ノードから検索する [XPath式]を用いることにする。
PHPでは、DOMXPath クラスを使う。コンストラクタで、DOMXPath でオブジェクトを生成するところまでは実行している。
次に、DOMXPath::evaluate を使ってXPath式の評価(検索)をしていく。そのためのメソッド evalXPath を用意した。

titleタグの内容を取り出すメソッド getTitle と、'meta name="description" content=' の内容を取り出すメソッド getDescription を用意した。

XPath式の書き方だが、'/' は階層を示す。
titleタグは 'html→head' の階層にあるので、'//title' と表記する。これにDOMXPath::evaluateを適用すると、titleタグの内容を取得できる。
'meta name="description" content=' をXPath式で表すと、'//meta[@name="description"]/@content' となる。XPath式で、条件は [...] に記載する。属性からノードを選択する場合には、名前の前に '@' を付ける。

XPath式の書き方は「XPath」(システムエンジニアのスキルアップ)が詳しい。

解説:バージョンチェック

0178: /**
0179:  * PHP5以上かどうか検査する
0180:  * @return bool TRUE:PHP5以上/FALSE:PHP5未満
0181: */
0182: function isphp5over() {
0183:     $version = explode('.', phpversion());
0184: 
0185:     return $version[0] >= 5 ? TRUE : FALSE;
0186: }

DOMDocumentクラスはPHPバージョン5以上でないと動作しないので、PHPのバージョン・チェックを行うユーザー関数 isphp5over を用意した。

参考サイト

(この項おわり)
header