[勝手に解答] Q. xml文書を取り出して、解析したい

2022年12月24日

PHP 勝手に解答

eyecatch プログラムお悩み相談サイト、Teratailの1ヶ月以上未回答の質問に、ブログで勝手に解答してしまうお馴染みシリーズです。 今回は、「xml文書を取り出して、解析したい」という質問に対して、この記事を書いている時点でコメントすらついていなかったので、色々と解析をしてみたいと思います。

質問内容

元サイト : https://teratail.com/questions/ivmye44l9uae72 URL先の文字列解析をできるプログラムを作成しようと考えています。下記のようにコードを作成したのですが、文字列の取り出し方が分からなくて困っています。 $array['head']['title'];とすると、headタグ内のtitleタグに入っている文字列を取り出してくるのはわかるのですが、bodyタグ内の文字列の取り出し方が分かりません。文字列の取り出しを試みようとしているURL先のページソースのリンク先を添付しています。わかる方、何卒宜しくお願い致します。 リンク内容 <?php $search_url = $_GET["url"]; $html = file_get_contents($search_url); $domDocument = new DOMDocument(); $domDocument->loadHTML($html); $xmlString = $domDocument->saveXML(); $xmlObject = simplexml_load_string($xmlString); //var_dump($xmlObject); $array = json_encode($xmlObject,JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT); echo $array; echo "<br>"; $array = json_decode(json_encode($xmlObject), true); echo $array['head']['title']; /* foreach($array['head']['meta'] as $key){ echo $key; echo '<br>'; } */ echo "<br>"; echo $array['body']['div']; ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <?php echo "<br>"?> <?php echo $search_url;?> </body> </html>
ちなみに、このソースコードを手元の環境で実行すると・・・ ※localhost/test.phpとして実行
Warning: Undefined array key "url" in /var/www/html/test.php on line 3 Deprecated: file_get_contents(): Passing null to parameter #1 ($filename) of type string is deprecated in /var/www/html/test.php on line 5 Fatal error: Uncaught ValueError: Path cannot be empty in /var/www/html/test.php:5 Stack trace: #0 /var/www/html/test.php(5): file_get_contents('') #1 {main} thrown in /var/www/html/test.php on line 5
このようなエラー画面になります。 恐らく、指定のリンクURLを次のようにクエリにつける事でHTMLが取得できるので、ソコも含めて詳細を見てみます。 test.php?url=https://www.javadrive.jp/php/ とりあえず、色々と問題があるので、それぞれ一つずつ解説して行きたいと思いますね。

この質問に関する問題点

1. xmlではなくてhtml

質問の冒頭から間違っているので、回答者が気分屋&深く考えたくないユーザーを抱え込んでいるこの質問サイトでは誰からも見向きもされなかったようです。 質問者に直接聞いているわけではないのですが、質問文章を読むと、サイトの解析をしたいっぽいことが書いてあるので、恐らく間違いないでしょう。

2. 質問文が分かりにくい

プログラミング言語を習得したければ、ちゃんと日本語も習得して、相手にちゃんと伝わる文章を書けるという状態にならないといけません。 ※もっと深く言うと、あまり言われることは無いですが、コミュニケーション能力が、プログラミング能力では大きく重要という事です。 今回の質問について、自分であれば、次のように記載します。
「HTMLをPHPで解析したい」 PHPで任意のURLにアクセスして、そのサイトのHTML内のtitleタグの値は取得できましたが、bodyタグ内のそれぞれの要素の取り出し方が分かりません。
こんな感じでシンプルに伝わると思います。

3. 実行サンプルと結果についての記載が無い

phpのソースコードを乗せて、できればデモサイトを作って公開して、そこにエラーを表示してくれるのが一番伝わりやすいのですが、 それぞれのローカル環境などで実行してもらうことを考えると、次のような参考アクセスを書いておく必要があります。
http://localhost/test.php?url=http://example.com/
これで、今回のプログラムでどのように表示されているか(こちらの環境ではエラーが出てますが・・・)も、書いておくと見た人は大体どこに問題があるかひと目で分かる場合が多いです。

4. プログラムにコメントを付けておくとよりGood

せっかくプログラムを載せているのに、そのプログラムがどういう意図で書かれているかがこれだけでは、読み取るのが難しいですよね。 熟練者の人であれば、プログラム行間を読み取って想像することは出来るんですが、人に答え手もらおうというおもてなしの精神があるかどうかは、この辺のソースを見ると確実に理解できてしまいます。 よく言われている、「自分のやりたいことを相手にやってもらうだけの、投げっぱなしの質問」と受け取られても仕方がないかもしれません。 質問に関する姿勢や文章などについては、この辺を理解して出来るようになると自ずと不思議なことにプログラミングスキルも合わせて向上していくでしょう。(間違いない)

解決編

それでは、実際にこの質問者の人の答え手もらいたい内容を(半分想像して)答えてみたいと思います。 質問には、「bodyタグ内の文字列の取り出し方」というだけで、具体的にこの値が取得したいというのが書かれていないので、この辺は想像するしかありません。 たぶん(間違いなく)スクレイピングをしたいのではないかと思うので、ページ内にある目次のリンク一覧(下の画像の箇所)を取得してみたいと思います。 <?php $search_url = $_GET["url"]; $html = file_get_contents($search_url); $domDocument = new DOMDocument(); $domDocument->loadHTML($html); $xmlString = $domDocument->saveXML(); $xmlObject = simplexml_load_string($xmlString); print_r($xmlObject->body->div[1]->div[0]->div[2]); SimpleXMLElement Object ( [@attributes] => Array ( [id] => catemokuji ) [div] => Array ( [0] => SimpleXMLElement Object ( [@attributes] => Array ( [class] => catebox ) [ol] => SimpleXMLElement Object ( [li] => Array ( [0] => SimpleXMLElement Object ( [a] => PHPインストールと初期設定 ) [1] => SimpleXMLElement Object ( [a] => PHPプログラムの基本事項 ) [2] => SimpleXMLElement Object ( [a] => 文字列 ) [3] => SimpleXMLElement Object ( [a] => 数値と四則演算 ) [4] => SimpleXMLElement Object ( [a] => 変数 ) [5] => SimpleXMLElement Object ( [a] => 条件分岐 ) [6] => SimpleXMLElement Object ( [a] => 繰り返し処理 ) [7] => SimpleXMLElement Object ( [a] => 配列 ) [8] => SimpleXMLElement Object ( [a] => 関数 ) [9] => SimpleXMLElement Object ( [a] => クラスとは何か ) [10] => SimpleXMLElement Object ( [a] => クラスの定義 ) ) ) ) [1] => SimpleXMLElement Object ( [@attributes] => Array ( [class] => catebox ) [ol] => SimpleXMLElement Object ( [@attributes] => Array ( [start] => 12 ) [li] => Array ( [0] => SimpleXMLElement Object ( [a] => ユーザー認証 ) [1] => SimpleXMLElement Object ( [a] => クッキーの利用 ) [2] => SimpleXMLElement Object ( [a] => セッション管理 ) [3] => SimpleXMLElement Object ( [a] => MySQLへの接続 ) [4] => SimpleXMLElement Object ( [a] => PostgreSQLへの接続 ) [5] => SimpleXMLElement Object ( [a] => SQLiteへの接続 ) [6] => SimpleXMLElement Object ( [a] => PDOの利用 ) [7] => SimpleXMLElement Object ( [a] => メール使用のための環境設定 ) [8] => SimpleXMLElement Object ( [a] => メール送信 ) [9] => SimpleXMLElement Object ( [a] => PHPサンプルプログラム ) ) ) ) ) ) DOM構造を配列として形成されているので、 $array['body']['div'] ではなく、 $array['body']['div'][0] という風に配列番号をしてする必要があるんですね。 他にも、attributeを指定するDOM操作やxml特有のxpathなど、色々なアプローチ方法があるので、 phpのリファレンスサイトを読んでアプローチ方法をたくさん習得していくといいでしょう。

phpリファレンスサイト

php:simplexml_load_string

あとがき

この質問をした人がこの記事を読んでもらえるように、質問サイトの方に、このブログのURLを書き込んでおきました。 役に立ってもらえると幸いです。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。