PHPでHTMLから特定の文字列を抽出する

テキストから特定の文字列を抽出する処理で、正規表現を使って泥臭く解析していましたが、想定した抽出ができなかったため、正規表現を使わずにPHPのみでHTMLから文字列を抽出することにしました。有識者から教えてもらったソースコードを記載しています。

抽出対象の文言

<p>私は<span class="strawberry">とちおとめ</span>を食べました。</p>
<p>私は<span class="grape strawberry">シャインマスカットととちおとめ</span>を食べました。</p>

抽出結果

とちおとめ
シャインマスカットととちおとめ

ソースコード

$str=<<<eof
<p>私は<span class="strawberry">とちおとめ</span>を食べました。</p>
<p>私は<span class="grape strawberry">シャインマスカットととちおとめ</span>を食べました。</p>
eof;
$content = mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8');
$dom = new DOMDocument();
$dom->loadHTML($content);
$xpath = new DOMXPath($dom);
$vals=array_map(function($x){
  return $x->nodeValue;
},iterator_to_array($xpath->query('//span[contains(@class,"strawberry")]')));
print_r($vals);

解説

mb_convert_encoding

HTML エンティティに変換します。HTML エンティティとは、特殊文字を文字コードに変換すること(エンコード) を言います。HTMLにそのまま書いてもブラウザ上で正しく表示されない文字を表示させたいときに、それぞれの文字をエンティティと呼ばれるコード表記にすることで正しく表示することができます。改行をHTMLエンティティ化すると、&#010; と変換されます。

DOMDocument

HTML ドキュメントあるいは XML ドキュメント全体を表し、 ドキュメントツリーのルートとなります。

PHP公式マニュアル https://www.php.net/manual/ja/class.domdocument.php

HTMLやXMLを自由に操作するための仕組みです。DOM とは、Document Object Modelの略で HTML や XML 文書を取り扱うためのAPIを指します。DOMでは、HTMLやXMLを「ノード」と呼ばれる階層的な構造として識別し、扱いたいノードを特定して操作できるようにする仕組みを提供しています。DOMDocumentを使うことで、指定したIDやClassから要素を抽出できます。

DOMXPath

XDOMXPathはXML文章中の要素、属性値などを指定するための言語です。XPathではXML文章をツリーとして捉えることで、要素や属性の位置を指定できます。HTMLもXMLの一種とみなすことができるため、XPathを使ってHTML文章中の要素を指定できます。

array_map

PHPの配列のすべての要素に対して同じ処理を一括で適用します。array_map(コールバック関数, 配列)のように指定します。コールバック関数は、別の関数の引数として渡す関数のことをいいます

array_map(function($x)

このように数名を指定せずに関数を作成できるようにする仕組みを「無名関数」といいます。処理用の関数を引数として直に書きます。「無名関数」なので関数名がありません。

nodeValue

ノードから値を取り出す時に使用します。

iterator_to_array

イテレータを配列にコピーする関数です。イテレータとは、配列のようなものですが、添字を使った各要素へのアクセス ($foo[0] とか $foo[‘key’] とか) は含みません。ツリー構造のような不規則な多次元配列を出力できます。利用者にリストの内部構造を隠したまま、それぞれの要素にアクセスできます。

//span[contains(@class,”strawberry”))]

//を用いて途中までのパスを省略しています。このXPathは、classにstrawberryを含むspan要素を取得するという意味です。

“strawberry”の箇所に変数を使う場合は以下のように記載します。

('//span[contains(@class, "' . $hoge .'")]')

コメント

タイトルとURLをコピーしました