エス技研

WordPress、CakePHP、PHP、baserCMSなどの Web系システムを中心に情報を提供します!


PHPのスクレイピングライブラリ「PHP Simple HTML DOM Parser」の使い方

      2020/02/08

PHPのスクレイピングライブラリ「PHP Simple HTML DOM Parser」の使い方

 

PHP Simple HTML DOM Parserに関連する解説、および、関連記事

 
PHPでスクレイピングをする際には、「PHP Simple HTML DOM Parser」というライブラリを利用すると簡単にスクレイピングをすることが出来ます。
 
この記事では「PHP Simple HTML DOM Parser」の基本的な使い方を始め、実用的な使い方、エラーの原因になるポイントなどを解説していきます。
 
 
また、「PHP スクレイピング」で検索すると「phpQuery」というライブラリの記事が大量にヒットするわけです。
しかし、「phpQuery」より「PHP Simple HTML DOM Parser」をおすすめする理由や、「PHP Simple HTML DOM Parser」の基本的な使い方についての解説を下記の記事に書いていますので、こちらも併せて読んでいただく方がいいかと思います。
PHPでスクレイピング。phpQueryとphp-simple-html-dom-parserの比較と設置方法
 
「PHP Simple HTML DOM Parser」を CakePHP3で使う場合の導入方法については下記に記事を書きました。
CakePHP3でPHP Simple HTML DOM Parserを使ってスクレイピングする方法
 
 
また、スクレイピングを行う対象のページへアクセスするときは、「file_get_contents」や「cURL」を利用します。
ですが、断然「cURL」の方をオススメする!という理由や、cURLで SSL化されたページへのアクセス、User Agentを必要とするサイトへのアクセス方法などについて、下記の記事に書いていますので、こちらも併せて読んでいただく方がいいかと思います。
PHPのcURLでAPIやWebサイトへのアクセス方法。file_get_contentsとの比較
 
 
また、この記事は、下記のオフィシャルマニュアルを参考にしています。
https://simplehtmldom.sourceforge.io/manual.htm
 
 

DOMオブジェクトを生成する方法

 
「PHP Simple HTML DOM Parser」では、まず最初に HTMLから DOMオブジェクトを生成します。
 
そして、作成した DOMオブジェクトに対して「find()」メソッドを使ってほしい項目を取得する、という流れになります。
 
 

DOMオブジェクトを生成する基本形

 
その最初の DOMオブジェクトを作成する方法は下記の 3種類あります。
 

 
 

DOMオブジェクトを生成するサンプルソース

 
URLを指定して Webサイトにアクセスし DOMオブジェクトを作成する場合は、「file_get_html()」が用意されていますが、私は cURLを使い別に HTMLソースコードを取得した上で、「str_get_html()」を使って DOMオブジェクトを生成する方法をオススメします。
 
なぜか。
指定の URLから情報が取得できなかった場合にエラー制御をするためには cURLの方がやりやすいからです。
詳しくは、「PHPのcURLでAPIやWebサイトへのアクセス方法。file_get_contentsとの比較」か「PHPでスクレイピング。phpQueryとphp-simple-html-dom-parserの比較と設置方法」を参考にしてください。
 
 
cURLを利用した場合の DOMオブジェクトの生成するサンプルソースは以下のようになります。
 

 
関数「getApiDataCurl()」の中身については、「PHPのcURLでAPIやWebサイトへのアクセス方法。file_get_contentsとの比較」か「PHPでスクレイピング。phpQueryとphp-simple-html-dom-parserの比較と設置方法」を参考にしてください。
 
 

DOMオブジェクトから find()メソッドを使ってノード(項目)を取得する方法

 

DOMオブジェクトから find()メソッドを使ってノード(項目)を取得する処理の基本系

 
DOMオブジェクトからノード(項目)を取得するときは「find()」メソッドを使います。
その使い方の基本形は下記のようになります。
 

 
 

要素の条件を指定するフィルタ

 
$html->find("div[id=foo]");」の「[id=foo]」で指定している箇所はフィルタとなっておりまして、「=」以外の条件を指定することも出来ます。
指定方法とその条件は、以下のようになります。
 
[attribute]
指定された属性を持つ要素に一致するものを取得
 
[!attribute]
指定された属性を持つ要素に一致しないものを取得
 
[attribute=value]
指定された値である属性を持つ要素を取得
 
[attribute!=value]
指定された値ではない属性を持つ要素を取得
 
[attribute^=value]
指定された値から始まる属性を持つ要素を取得
 
[attribute$=value]
指定された値で終わる属性を持つ要素を取得
 
[attribute*=value]
指定された値を含む属性を持つ要素を取得
 
 

CSSの IDセレクタ、CLASSセレクタを指定する方法

 
CSSの IDセレクタや CLASSセレクタを条件として指定する方法もあります。
 

 
 
「,(カンマ)」で区切りることで、複数条件の指定ができるようになります。
 

 
 

テキストブロックとコメントの取得

 
テキストブロックやコメントを取得するときは下記のように指定します。
 

 
$html->plaintext」は、全てのタグの plaintextを取得するものです。
$html->find("text")」とは違う結果になります。
 
 

子孫セレクタやネストされたタグの取得

 
スペースで区切ることで子孫セレクタ、ネストされた要素を取得することが出来ます。
 

 
 
ネストされた要素は下記のように foreach()で取得することも可能です。
 

 
 

取得した要素の属性にアクセスする方法

 
前項では、DOMオブジェクトから条件に従って要素を取得する方法を解説しました。
この後では、取得した要素の中から指定した属性の値を取得する方法を解説します。
 
 

要素の属性を指定して値を取得する方法の基本形

 
要素の属性を指定して値を取得する基本形は以下になります。
 

 
 

要素のテキストの情報を取得する方法

 
指定した要素のテキスト情報を取得する方法が 3種類用意されています。
テキスト情報のみを取得するのか、タグも含めて取得するのか、などを選択することができます。
 

 
 
「plaintext」「innertext」「outertext」を指定した際の具体的な結果は以下のようになります。
 

 
 
ちなみに、「$html->find("a",0)->plaintext;」と「$html->find("a",0)->innertext;」とした場合は、両方とも同じ「リンクの例」となります。
これは、「a」タグの中には「リンクの例」しかないためです。
 
 

属性を設定、削除する方法、属性の存在の有無チェックの方法

 
属性から値を取得するだけではなく、属性に値を設定したり、削除したりすることもできます。
 

 
 

DOM拡張モジュールに定義された関数を使用して要素を取得することも可能

 
DOMオブジェクトから要素を取得する方法としては、「find()」メソッドを利用する方法を紹介しました。
 
ですが、PHP Simple HTML DOM Parserでは、DOM拡張モジュールに定義された関数を使用して要素を取得することもできます。
 
例えば、下記のように「getElementById()」で「id」の値を指定して要素を取得することもできます。
 

 
 
DOM拡張モジュールに定義された関数は多数ありますので、下記の PHPの関数レファレンスを参考にしてください。
https://www.php.net/manual/ja/book.dom.php
 
 

取得した HTMLを保存する方法

 
取得した HTMLファイルを簡単にファイルとして出力(保存)する方法も用意されています。
 

 
解説はしましたが、果たしてこの機能を使う機会はあるのだろうか?という疑問はありますね。
 
 

PHP Simple HTML DOM Parserを使うときの注意点

 
ここ以降は、マニュアルには載っていない内容ですが、実際に使ってみて気づいた点がいくつかありましたので、それをお伝えしたいと思います。
 
 

DOMオブジェクトの中身の確認には echo、printを使う

 
先のサンプルでは、取り出した値を「print_r()」を使って表示しています。
ですが、DOMオブジェクトの中身を確認したいときは、print_r()、var_dump()ではなく、echo、printを使いましょう。
 
 
具体的には、下記の記述を実行すると「Fatal error: Allowed memory size of 2097152000 bytes exhausted (tried to allocate 1046482944 bytes) in C:\xampp...」のエラーがでます。
 

 
下記の記述方法であればエラーは発生しません。
 

 
 
詳しいエラーの原因は調べていませんが、すごい勢いで CPUとメモリを消費してオーバーフローをしてしまいますので、ローカル環境以外で「print_r()」を使うのはかなり危険です。
 
 

HTMLタグの大文字、小文字は気にしなくて問題なし

 
HTMLタグは大文字、小文字のどちらで記述しても問題ない仕様になっています。(XHTMLは小文字で記述する仕様になっています。)
 
そのため、HTMLタグが大文字のサイトがあったり、小文字のサイトがあったりしますが、「$html->find("title",0)->plaintext」などで指定するタグは、大文字小文字の区別をしません。
(HTMLのソース側も、find()に指定する側も大文字、小文字の区別は行われません。)
 
そのため、大文字小文字は気にせず記述することが出来ます。
 
逆に、大文字小文字が混在したサイトで「大文字で書かれた「H2タグ」の 3つめを取得したい」といった指定をすることは出来ません。
 
 

PHP Simple HTML DOM Parserで処理できる文字数には上限がある

 
PHP Simple HTML DOM Parserには処理できる文字数に上限があるようです。
 
とあるサイトのスクレイピングをしようとアクセスしたところ、「Fatal error: Uncaught Error: Call to a member function find() on bool in ...」というエラーが発生しました。
 
エラーの内容を調査すると、「$html->find("h3",0)->plaintext」を実行している「$html」が空であることが確認できました。
そして、「$html」が空になる理由が、HTMLのソース量が大きすぎて、「str_get_html()」で処理できていないことが分かりました。
 
そのため「mb_substr()」を使用して、取得した HTMLを文字数で制限して取得してみたところ、520,000文字以下であれば処理できることが確認できました。
(環境によって「520,000文字」が異なるか否かは確認をしていません。)
 
 
より具体的には...
 
520,261文字以上ではエラーがでました。
「mb_substr」で処理をしていますので、バイト数ではなく、全角半角の区別なく文字数です。(バイト数で制限があるか否かは確認していません。)
php.ini の memory_limit を変更しても制限される文字数が変わることはありませんでした。
 
 
このエラーの難点は、エラーメッセージが「$html が空です」というものであるため、HTMLのソース量が大きいことが原因で処理できていない、ということになかなか気づかない点が挙げられます。
 
 

大量の HTMLソースを持つページに対処するサンプルソース・その1

 
大量の HTMLソースを持つページの情報を取得する必要がある場合の具体的な対処方法のサンプルソースとしては以下のようになります。
 

 
HTMLファイルの最初の方はグローバルメニューや検索条件を入力するエリアで、下の方に検索結果一覧が表示される、というサイトなどを想定しています。
そのため、検索結果が表示される HTMLの下の方だけ取得できればいい、といった場合はこの方法が簡単なのではないか、と思います。
 
「mb_substr」を用いて、最後から「520,000文字」を取得しています。
 
サンプルのヤフーのサイトは「520,000文字」もありませんが。
 
 
また、関数「getApiDataCurl()」は、オリジナルの関数です。詳細は「PHPのcURLでAPIやWebサイトへのアクセス方法。file_get_contentsとの比較」か「PHPでスクレイピング。phpQueryとphp-simple-html-dom-parserの比較と設置方法」を確認してください。
 
 

大量の HTMLソースを持つページに対処するサンプルソース・その2

 
前項では「mb_substr」を用いてざっくり後半部分!という感じで取得する処理でした。
 
その2では、例えば「<h2>一覧表示</h2>」移行の行を対象として取得する、といった具体的な目印がある場合の対応方法です。
 
下記のように「foreach()」で上から 1行ずつチェックして必要な部分を取得する方法もあるかとも思います。
 

 
 
長くなりましたが、以上になります。

 - PHP・Smarty・ECCUBE

GoogleAdwords

GoogleAdwords

最後までお読みいただきましてありがとうございます。
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!

Message

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

下記の空欄を埋めてください。 * Time limit is exhausted. Please reload CAPTCHA.

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

※入力いただいたコメントは管理者の承認後に掲載されます。

  関連記事

CentOS6、7のPHPを5.3から5.6、7.0、7.1にバージョンアップする手順の解説
CentOS6、7のPHPを5.3から5.6、7.0、7.1にバージョンアップする手順の解説

CentOS6系、7系のPHPバージョンを5.3から5.6、7.0、7.1にアップする作業手順と解説。yum updateコマンドを使い作業時間は約10分。コマンドの解説や引数の意味なども解説しているので役に立つはず。

QRコード(二次元バーコード)作成サービスを公開
QRコード(二次元バーコード)作成サービスを公開

QRコード(二次元バーコード)を生成するサービス。QRコードにする文字列を入力するだけで QRコードが簡単に作れる。オプションとして、画像サイズ、余白サイズ、エラー訂正レベルがある。

指定した数で文字列を丸める関数substr、mb_substr、mb_strimwidthの違い
指定した数で文字列を丸める(n文字目で…にする)関数substr、mb_substr、mb_strimwidthの違い

文字列を指定された数で抜き出すPHPの関数、substr、mb_substr、mb_strimwidthについての解説。似た関数だが引数の指定方法が違ったり、文字数がバイト数か文字数かも違ったり、注意が必要だ。

PHPのソースで見慣れない記号が出てきた・アロー演算子(->)、ダブルアロー演算子(=>)

PHPのプログラムソースには見慣れない記号が出てきます。その意味や調べ方です。

複数銘柄を指定して株価チャートを一覧するツール公開

入力銘柄の5日間、3か月間、6か月間、1年間、2年間の株価チャートを一覧表示しますのでチャートで売買判断をするのに最適です。

配列の値をテキスト表示する際に「、」でつなげるときの処理方法の一例
配列の値をテキスト表示する際に「、」でつなげるときの処理方法の一例

配列の値を「、」でつないで出力する際、単純にforeachで繰り返し処理をすると「イヌ、サル、キジ、」となるが文字列最後の「、」を出力しない方法を3つ解説している。

PHPのcURLでAPIやWebサイトへのアクセス方法。file_get_contentsとの比較
PHPのcURLでAPIやWebサイトへのアクセス方法。file_get_contentsとの比較

PHPからWebサイトにアクセスしてHTMLを取得、APIにアクセスして情報を取得する場合は、cURLがオススメ。file_get_contentsでも可能だがエラー制御に難がありトラブルのもとになる。

Phpmailerでスパム回避!Gmail等のSMTPを経由するPHPのメールフォーム解説

お問い合わせ等のメールフォームから送ったメールがスパム扱いされる!その対策としてライブラリ「Phpmailer」を使う方法を解説。関数化していますのでコピペでOK。

PHPで正規表現の検証には preg_match_allが便利

PHPで正規表現の検証には preg_match_allが便利です。その便利さの使い方の解説です。

路線・駅検索のために緯度経度からPHPで簡易的に距離を計算する処理解説
路線・駅検索のために緯度経度からPHPで2点間の距離を計算する処理解説

路線・駅検索の仕組みの構築は大変。それを簡易に実装するために緯度経度を元に距離計算をする仕組みを考案。まずは2点間の距離を計算する仕組みを解説し、距離計算にまつわる関連技術も紹介。