Larisa KoshkinaによるPixabayからの画像
目次
ちょっと気が向いてPHPでスクレイピングのやり方を調べたので、メモとしてここにまとめます。
この記事では基礎のみをシンプルにまとめているので、すぐに応用できるかと思います。
スクレイピングについて以下のサイトを参考にさせていただきました。
https://qiita.com/rllllho/items/cb1187cec0fb17fc650a
OS:Windows11 / WSL(Ubuntu20.04)
php:v7.4.33
以下の1行で対象のページのHTMLをまるまる取得できます。
file_get_contents("[対象ページのURL]");
試しにBootstrapのページのHTMLを取得して、表示させてみます。
<?php
$html = file_get_contents("https://getbootstrap.jp/");
echo $html;
こんな感じで表示されました。
レイアウトは崩れていても、HTML要素を取得できています。
しかし、これだけでは必要な要素のみ取得することはできません。
では実際にスクレイピングをやってみます。
取得する要素の指定方法は若干難しいので、この後にご説明します。
表示については、下のコードにあるように、ループとインデックス番号で指定して表示する方法だけ知っていればどうにかなるんじゃないかと思っています。
<?php
//↓↓ ------スクレイピングの準備------ ↓↓
$dom = new DOMDocument('1.0', 'TUF-8');
$html = file_get_contents('https://getbootstrap.jp/'); //⇐取得するページのURLに変える
$html = mb_convert_encoding($html, "HTML-ENTITIES", auto);
@$dom->loadHTML($html);
$xpath = new DOMXpath($dom);
//↑↑ ------スクレイピングの準備------ ↑↑
//対象ページのh2要素を取得 ※取得した値は配列になっています。
$elements = $xpath->query("//h2"); //⇐ここについては後程説明します。
//ループで取得した全要素を表示してみる。
foreach($elements as $node){
echo "<p>", $node->nodeValue, '</p>';
}
echo '<br><br>'; //⇐これは表示を見やすくしているだけなので気にしないでください。。
//インデックス番号で指定して表示してみる。
echo $elements[0]->nodeValue;
下の赤字の部分のことをロケーションパスを言うそうなのですが、この部分の書き方について以下でご説明します。
$xpath->query(“[この部分]“)
このシンプルな書き方だけで、だいぶ自由に要素を取得できます。
■直下(子要素のみ):/
例)$xpath->query("//footer/ul/li");
■より下(子孫要素全て)://
例)$xpath->query("//footer//li");
■属性で指定して要素を取得:@属性='[値]’
$xpath->query("//footer//div[@class='row']");
■任意文字列で要素を取得:contains
例)classに'wrapper'を持つdiv要素を取得
$xpath->query("//footer/div[contains(@class, 'wrapper')]");
例)「<div>品番</div>」のように'品番'を含むdivを取得する
$xpath->query("//footer/div[contains(text(), '品番']");
例)任意文字を含むJavaScriptを取得する
$xpath->query("//script[contains(test(), 'stoch']");
■n番目の要素を取得:position
例)3番目のli要素を取得する ※省略形:li[position()=3 ⇒ li[3]
$xpath->query("//footer/li[position()=3]");
例)2番目以降のli要素を取得する。
$xpath->query("//footer/li[position()>1]");
■任意要素の任意の属性を取得:/@[属性]
例)a要素のhref属性の値を取得する
$xpath->query("//footer//a/@href");
■要素内のテキストを取得:text()
例)p要素のテキストを取得する
$xpath->query("//footer//p/text()");
■式の否定:not
例)$xpath->query("//footer/img[not(contains(@src, 'main'))]/@src");
■または:or
例)$xpath->query("//footer//a[contains(@href, 'https') or contains(@href, '/home')]");
■かつ:and
例)$xpath->query("//footer//a[contains(@href, 'https') and contains(@class, 'btn')]");
上で記載した「ロケーションパスのシンプルな書き方」は以下で記載する「詳細な書き方」の省略形です。
ロケーションパスを詳細に書くと、以下のように構成されます。
軸::ノードテスト[式]
記述例)$xpath->query("/descendant-or-self::footer/child::div[contains(@class,'wrapper')]");
赤字で書いてある「軸」が増えただけですね。
軸の主なものを以下の表にまとめます。
軸 | 内容 |
self | ノード自身 |
child | ノードの子ノード |
parent | ノードの親ノード |
ancestor | ノードの祖先ノード(親も含む) |
descendant | ノードの子孫ノード |
ancestor-or-self | ノード自身とその祖先ノードの集合 |
descendant-or-self | ノード自身とその子孫ノードの集合 |
precending-sibling | 同じ階層にあり、かつ前に出てくる兄弟ノード |
following-sibling | 同じ階層にあり、かつ後に出てくる兄弟ノード |