PHPで利用するXPathメモ
PHPでクローラー作成やスクレイピングする際に、XPathの記述をよく忘れるのでメモします。
XPathについては、他の言語でも大体似たような記述です。
XPath
- HTMLソースをXPathに変換
function toXPath($source) { $result = new DOMDocument; @$result->loadHTML($source); return new DOMXPath($result); }
適当なクラスに組み込んで利用します。
特定の文字列を持っているノードを取得
- targetという文字列が含まれるdiv
//div[contains(text(), 'target')]
- class属性が
target target2
のdiv
//div[@class='target target2']
- name属性にtargetという文字列が含まれるノード
//*[contains(@name, 'target')]
and、or、not
- href属性に https:// を含み、targe属性が_blankのa
//a[contains(@href, 'https://') and @target='_blank']
- href属性か、src属性に http:// を含むノード
//*[contains(@href, 'http://') or contains(@src, 'http://')]
- href属性に https:// を含まないa
//a[not(contains(@href, 'http://'))]
N番目のノードを取得
- tableタグ内の2番目のtd
//table//td[position()=2]
- tableタグ内の2番目以降のtd
//table//td[position()>2]
- tableタグ内の最後のtd
//table//td[position()=last()]
ノードの階層から指定して取得
- h3の後ろにある1つ目のtable
//h3/following-sibling::table[1]
- tableの前にある1つ目のh3
//table/preceding-sibling::h3[1]
- targetという文字列が含まれるtdの親tr
# 該当のtrのみ //td[contains(text(), 'target')]/parent::tr # 該当のtrの兄弟も取得 //td[contains(text(), 'target')]/../../tr
存在するか
- class属性にpriceを含むノードが存在するか
function hasClassNamePrice($xpath) { return $xpath->query("//*[contains(@class, 'price')]")['length'] ? true : false; }
該当タグ内のテキストや、属性を出力
- targetという文字列が含まれる1番目のdivのテキストを出力
echo $xpath->query("//div[contains(text(), 'target')]")->item(0)->textContent;
- targetという文字列が含まれる2番目のdivのclass属性を出力
echo $xpath->query("//div[contains(text(), 'target')]")->item(1)->getAttribute('class'); // もしくは echo $xpath->query("//div[contains(text(), 'target')]/@class")->item(1)->textContent;
HTMLに変換する
function XPathToHTML($node) { $result = ''; $children = $node->childNodes; foreach ($children as $value) { $result .= $node->ownerDocument->saveHTML($value); } return $result; }