web-dev-qa-db-ja.com

PHPでHTML / XMLをどのように解析し処理しますか?

どのようにしてHTML/XMLを解析し、そこから情報を抽出することができますか?

2028
RobertPitt

ネイティブXML拡張

PHPにバンドルされているので、私は native XML extensions のうちの1つを使用することを好みます。通常、すべてのサードパーティ製のライブラリよりも高速で、マークアップを制御できます。

DOM

DOM拡張機能を使用すると、PHPを使用してDOM APIを介してXML文書を操作できます。5.これは、W3CのDocument Object Model Core Level 3の実装です。文書の内容、構造、およびスタイルに動的にアクセスして更新するためのスクリプト。

DOMは、実世界の(壊れた)HTMLを解析および修正することができ、 XPathクエリ を実行できます。これは libxml に基づいています。

DOMの生産性を上げるには少し時間がかかりますが、その時間はIMOの価値があります。 DOMは言語にとらわれないインターフェースなので、多くの言語で実装されています。そのため、プログラミング言語を変更する必要がある場合は、その言語のDOM APIの使い方をすでに知っている可能性があります。

基本的な使用例は A要素のhref属性をつかむ で見つけることができます、そして一般的な概念的概要は phpのDOMDocument で見つけることができます。

DOMエクステンションの使い方はStackOverflowで広範囲にカバーされています ですので、あなたがそれを使うことを選んだ場合、あなたが遭遇する問題の大部分はStack Overflowを検索/ブラウズすることによって解決できると確信できます。

XMLReader

XMLReader拡張機能はXMLプルパーサーです。リーダーはドキュメントストリーム上を進むカーソルとして機能し、途中で各ノードで停止します。

DOMのようなXMLReaderはlibxmlに基づいています。私はHTML Parserモジュールを起動する方法を知らないので、壊れたHTMLを解析するためにXMLReaderを使用することは、libxmlのHTML Parserモジュールを使用するよう明示的に指示することができるDOMを使用するよりも頑強でないかもしれません。

基本的な使用例は phpを使ってh1タグからすべての値を取得 で見つけることができます。

XMLパーサー

この拡張機能を使用すると、XMLパーサーを作成してから、さまざまなXMLイベントのハンドラを定義できます。各XMLパーサーには、調整可能ないくつかのパラメーターもあります。

XMLパーサーライブラリもlibxmlに基づいており、 SAX スタイルのXMLプッシュパーサーを実装しています。 DOMやSimpleXMLよりもメモリ管理の方が適しているかもしれませんが、XMLReaderによって実装されているプルパーサよりも作業が難しいでしょう。

SimpleXml

SimpleXMLエクステンションは、XMLを通常のプロパティセレクタと配列イテレータで処理できるオブジェクトに変換するための非常にシンプルで使いやすいツールセットを提供します。

HTMLが有効なXHTMLであることがわかっている場合は、SimpleXMLを選択できます。壊れたHTMLを解析する必要がある場合は、SimpleXmlについても検討しないでください。

基本的な使用例は xmlファイルのノードとノード値をCRUDにする簡単なプログラム で見つけることができ、 PHPマニュアルにたくさんの追加の例があります があります。


サードパーティライブラリ(libxmlベース)

サードパーティのライブラリを使用したい場合は、文字列解析の代わりに実際にその下に DOM / libxml を使用するライブラリを使用することをお勧めします。

FluentDom - レポ

FluentDOMは、PHPのDOMDocumentにjQuery風の流暢なXMLインターフェースを提供します。セレクターはXPathまたはCSS(CSSからXPathへのコンバーターを使用)で書かれています。現在のバージョンは、DOM実装標準インターフェースを拡張し、DOM Living Standardの機能を追加します。 FluentDOMはJSON、CSV、JsonML、RabbitFishなどの形式をロードできます。 Composerを介してインストールすることができます。

HtmlPageDom

Wa72\HtmlPageDom`は、HTMLドキュメントを簡単に操作するためのPHPライブラリです。DOMツリーをトラバースするには DomCrawler from Symfony2 components が必要です。 HTMLドキュメント.

phpQuery (何年も更新されていません)

phpQueryは、PHP 5で記述されたjQuery JavaScriptライブラリをベースにしたサーバーサイドのチェーン可能なCSS3セレクター駆動のDOM(Document Object Model)APIであり、追加のコマンドラインインターフェース(CLI)を提供します。

また見なさい: https://github.com/electrolinux/phpquery

Zend_Dom

Zend_DomはDOMの文書や構造を扱うためのツールを提供します。現在、私たちはZend_Dom_Queryを提供しています。これはXPathとCSSの両方のセレクターを利用してDOMドキュメントを問い合わせるための統一されたインターフェースを提供します。

QueryPath

QueryPathはXMLとHTMLを操作するためのPHPライブラリです。ローカルファイルだけでなく、Webサービスやデータベースリソースでも動作するように設計されています。それは(CSSスタイルのセレクターを含む)jQueryインターフェースの多くを実装していますが、サーバーサイドでの使用に合わせて大きく調整されています。 Composerを介してインストールすることができます。

fDOMDocument

fDOMDocumentは標準のDOMを拡張して、PHP警告や通知の代わりに、エラーが発生した場合は常に例外を使用するようにします。また、利便性とDOMの使用を簡単にするために、さまざまなカスタムメソッドとショートカットも追加しています。

saber/xml

saber/xmlは、XMLReaderクラスとXMLWriterクラスをラップおよび拡張して、単純な「xmlからオブジェクト/配列へ」のマッピングシステムとデザインパターンを作成するライブラリです。 XMLの読み書きはシングルパスであるため、高速で、大きなXMLファイルではメモリが少なくて済みます。

FluidXML

FluidXMLは簡潔で流暢なAPIでXMLを操作するためのPHPライブラリです。 XPathと流暢なプログラミングパターンを活用して、楽しく効果的にします。


サードパーティ(libxmlベースではありません)

DOM/libxmlを基盤とする利点は、ネイティブ拡張に基づいているため、すぐに優れたパフォーマンスが得られることです。ただし、すべてのサードパーティ製ライブラリがこのルートを下回るわけではありません。以下にリストされているそれらのいくつか

PHP単純なHTML DOMパーサー

  • PHP 5+で書かれたHTML DOMパーサーを使えば、とても簡単にHTMLを操作できます。
  • PHP 5+が必要です。
  • 無効なHTMLをサポートします。
  • JQueryのようにセレクタを使ってHTMLページ上のタグを見つけます。
  • 1行でHTMLからコンテンツを抽出します。

私は一般的にこのパーサーをお勧めしません。コードベースは恐ろしく、パーサー自体はかなり遅く、メモリを大量に消費します。すべてのjQueryセレクタ( 子セレクタ など)が使用できるわけではありません。どのlibxmlベースのライブラリも、これを容易に上回るはずです。

PHP HTMLパーサー

PHPHtmlParserは、jQueryのようにCSSセレクタを使ってタグを選択することを可能にするシンプルで柔軟なHTMLパーサです。目標は、有効かどうかにかかわらず、HTMLをスクラップするための迅速で簡単な方法を必要とするツールの開発を支援することです。このプロジェクトは、もともとsunra/php-simple-html-dom-parserによってサポートされていましたが、サポートは中止されたようですので、このプロジェクトは私の以前の仕事の適応です。

繰り返しますが、このパーサーはお勧めしません。 CPU使用率が高いと、かなり遅くなります。作成したDOMオブジェクトのメモリをクリアする機能もありません。これらの問題は特に入れ子になったループで拡大します。ドキュメント自体は不正確でスペルミスがあり、4月14日以降の修正に対する回答はありません。

ガノン

  • ユニバーサルトークナイザとHTML/XML/RSS DOMパーサ
    • 要素とその属性を操作する機能
    • 無効なHTMLとUTF8をサポート
  • 要素に対して高度なCSS3のようなクエリを実行できます(jQueryのように - 名前空間をサポートします)。
  • HTML美人(HTML Tidyのような)
    • CSSとJavascriptを縮小する
    • 属性のソート、大文字と小文字の変更、インデントの修正など.
  • 拡張可能
    • 現在の文字/トークンに基づくコールバックを使用して文書を解析する
    • オーバーライドを容易にするために、小さな関数に分けられた操作
  • 早くて簡単

絶対に使わないでください。それがいいかどうかわからない。


HTML 5

HTML5の構文解析には上記のものを使用できますが、HTML5で許可されているマークアップのために 癖がある場合もあります を使用してください。そのため、HTML 5では、次のように専用のパーサーを使用することを検討します。

html5lib

主要なデスクトップWebブラウザとの最大限の互換性のための、WHATWG HTML 5仕様に基づくHTMLパーサーのPythonおよびPHP実装。

HTML5が完成したら、もっと専用のパーサを見るかもしれません。チェックアウトする価値がある html 5解析のためのハウツー というタイトルのW3のブログ投稿もあります。


ウェブサービス

PHPをプログラミングしたくない場合は、Webサービスも使用できます。一般的に、私はこれらのための非常に小さい実用性を見つけました、しかしそれは私と私のユースケースだけです。

ScraperWiki

ScraperWikiの外部インタフェースを使用すると、Web上または自分のアプリケーションで使用したい形式でデータを抽出できます。スクレーパーの状態に関する情報を抽出することもできます。


正規表現

最後に最も推奨されない正規表現 を使用してHTMLからデータを抽出できます。一般に、HTMLで正規表現を使用することはお勧めできません。

マークアップを一致させるためにWeb上で見つけるスニペットのほとんどは壊れやすいものです。ほとんどの場合、それらは非常に特定のHTML部分に対してのみ機能しています。どこかに空白を追加したり、タグ内の属性を追加または変更したりするなどの小さなマークアップの変更は、正しく記述されていないとRegExが失敗する可能性があります。 HTMLでRegExを使用する前に、自分が何をしているのかを知っておく必要があります。

HTMLパーサーはすでにHTMLの構文規則を知っています。正規表現はあなたが書くそれぞれの新しいRegExに対して教えられなければなりません。 RegExは場合によっては問題ありませんが、実際にはあなたのユースケースに依存します。

あなたは より信頼性の高いパーサーを書くことができます ですが、正規表現を使って完全で信頼性のあるカスタムパーサーを書くのは時間の無駄ですこれで仕事。

Parsing Html The Cthulhu Way も参照してください。


お金をかけたい場合は、

私はPHP Architectまたは作家と提携していません。

1831
Gordon

試してみてください シンプルHTML DOMパーサー

  • PHP 5+で書かれたHTML DOMパーサーで、とても簡単にHTMLを操作できます。
  • PHP 5+が必要です。
  • 無効なHTMLをサポートします。
  • JQueryのようにセレクタを使ってHTMLページ上のタグを見つけます。
  • 1行でHTMLからコンテンツを抽出します。
  • ダウンロード


例:

HTML要素を取得する方法:

// Create DOM from URL or file
$html = file_get_html('http://www.example.com/');

// Find all images
foreach($html->find('img') as $element)
       echo $element->src . '<br>';

// Find all links
foreach($html->find('a') as $element)
       echo $element->href . '<br>';


HTML要素を変更する方法:

// Create DOM from string
$html = str_get_html('<div id="hello">Hello</div><div id="world">World</div>');

$html->find('div', 1)->class = 'bar';

$html->find('div[id=hello]', 0)->innertext = 'foo';

echo $html;


HTMLからコンテンツを抽出する:

// Dump contents (without tags) from HTML
echo file_get_html('http://www.google.com/')->plaintext;


スラッシュドットを削る:

// Create DOM from URL
$html = file_get_html('http://slashdot.org/');

// Find all article blocks
foreach($html->find('div.article') as $article) {
    $item['title']     = $article->find('div.title', 0)->plaintext;
    $item['intro']    = $article->find('div.intro', 0)->plaintext;
    $item['details'] = $article->find('div.details', 0)->plaintext;
    $articles[] = $item;
}

print_r($articles);
317
Naveed

DOMDocument-> loadHTML() を使うだけで完了です。 libxmlのHTML解析アルゴリズムは非常に優れていて高速であり、一般的な考えに反して、不正なHTMLには影響しません。

231
Edward Z. Yang

なぜあなたはいけないのか、あなたが正規表現を使うべきなのか?

まず最初に、よくある誤称:正規表現は "解析"のためのものではありません。ただし、正規表現は ""データを抽出できます。抽出はそれらが目的としているものです。適切なSGMLツールキットやベースラインXMLパーサーを超える正規表現HTML抽出の主な欠点は、それらの構文上の努力とさまざまな信頼性です。

多少信頼できるHTML抽出の正規表現を作ることを考えてください。

<a\s+class="?playbutton\d?[^>]+id="(\d+)".+?    <a\s+class="[\w\s]*title
[\w\s]*"[^>]+href="(http://[^">]+)"[^>]*>([^<>]+)</a>.+?

これは、単純なphpQueryやQueryPathと同等のものよりも読みにくくなっています。

$div->find(".stationcool a")->attr("title");

しかしそれらが助けることができる特定のユースケースがあります。

  • 多くのDOMトラバースフロントエンドはHTMLコメント<!--を明らかにしていません、しかしそれは時々抽出のためのより役に立つアンカーです。特に擬似HTMLのバリエーション<$var>やSGMLの剰余は、正規表現で簡単に操作できます。
  • 多くの場合、正規表現は後処理を節約することができます。しかしながら、HTMLエンティティはしばしば手動の世話を必要とします。
  • そして最後に、<img src = urlsを抽出するようなe非常に単純なタスクの場合、それらは実際には有望なツールです。 SGML/XMLパーサーを上回るスピードの優位性は、これらの非常に基本的な抽出手順のために発揮されることがほとんどです。

時々、正規表現/<!--CONTENT-->(.+?)<!--END-->/を使ってHTMLの断片を事前に抽出し、残りをより単純なHTMLパーサフロントエンドを使って処理することさえ賢明です。

注:実際にはこの アプリ を使用しています。ここでは、XML構文解析と正規表現を代わりに使用します。先週、PyQueryの解析が中断され、正規表現はまだ機能していました。はい、奇妙な、そして私はそれを自分で説明することはできません。しかし、それは起こりました。
したがって、正規表現と邪悪な組み合わせに一致しないという理由だけで、実際の考慮事項を投票しないでください。 しかし、あまり投票しないようにしましょう。これはこのトピックの単なる補足です。

143
mario

phpQueryQueryPath は、流暢なjQuery APIの複製において非常に似ています。これが、PHPで正しくparse HTMLを処理する最も簡単な方法の2つである理由でもあります。

QueryPathの例

基本的には、最初にHTML文字列からクエリ可能なDOMツリーを作成します。

 $qp = qp("<html><body><h1>title</h1>..."); // or give filename or URL

結果のオブジェクトには、HTML文書の完全なツリー表現が含まれています。 DOMメソッドを使用して移動できます。しかし一般的なアプローチはjQueryのようにCSSセレクターを使うことです:

 $qp->find("div.classname")->children()->...;

 foreach ($qp->find("p img") as $img) {
     print qp($img)->attr("src");
 }

ほとんどの場合、->find()には単純な#idおよび.classまたはDIVタグセレクタを使用します。しかし、 XPath ステートメントを使うこともできます。また、->children()->text()、特に->attr()のような典型的なjQueryメソッドは、正しいHTMLスニペットを簡単に抽出することができます。 (そしてすでにSGMLエンティティをデコードしています。)

 $qp->xpath("//div/p[1]");  // get first paragraph in a div

QueryPathでは、ストリームに新しいタグを挿入し(->append)、後で更新されたドキュメントを出力してきれいにすること(->writeHTML)もできます。不正なHTMLだけでなく、さまざまなXMLの方言(名前空間付き)も解析でき、さらにHTMLのマイクロフォーマット(XFN、vCard)からデータを抽出することもできます。

 $qp->find("a[target=_blank]")->toggleClass("usability-blunder");

phpQueryまたはQueryPath?

一般に、QueryPathはドキュメントの操作に適しています。 phpQueryはjQueryにもっとよく似た擬似AJAXメソッド(単にHTTPリクエスト)も実装しています。 phpQueryはQueryPathよりも高速であることが多いと言われています(全体的な機能が少ないため)。

違いの詳細については、 tagbyte.orgのwayback machineとの比較 を参照してください。 (元の情報源がなくなったので、ここにインターネットのアーカイブリンクがあります。はい、あなたはまだ不足しているページ、人々を見つけることができます。)

そしてこれが 包括的なQueryPath入門 です。

利点

  • シンプルさと信頼性
  • 使い方が簡単->find("a img, a object, div a")
  • 適切なデータのエスケープ解除(正規表現のグリッピングと比較して)
129
mario

シンプルなHTML DOMは素晴らしいオープンソースのパーサです。

simplehtmldom.sourceforge

DOM要素をオブジェクト指向の方法で扱います。新しい反復は、準拠していないコードを幅広くカバーしています。そのタグ名の要素のすべてのインスタンスを返す「find」関数など、JavaScriptに見られるような優れた関数もいくつかあります。

これをさまざまなツールで使用し、さまざまな種類のWebページでテストしたところ、うまく機能したと思います。

88
Robert Elwell

ここでは説明していませんが、一般的な方法の1つとして、 Tidy を使用してHTMLを実行する方法があります。それからあなたはそれに古いXMLライブラリを使用することができます。

しかし、あなたの特定の問題には、あなたはこのプロジェクトを見てみるべきです: http://fivefilters.org/content-only/ - それは修正されたものです 読みやすさ アルゴリズムのバージョン。ページからテキストの内容(ヘッダーやフッターではない)だけを抽出するように設計されています。

59
Eli

1aと2の場合:新しいSymfony ComponetクラスのDOMCrawler( DomCrawler )に投票します。このクラスはCSSセレクタと同様のクエリを許可します。このプレゼンテーションで実際の例を見てみましょう: symfony2-news

コンポーネントはスタンドアロンで動作するように設計されており、Symfonyがなくても使用できます。

唯一の欠点は、PHP 5.3以降でのみ機能することです。

55
Timo

ちなみに、これは一般にスクリーンスクレイピングと呼ばれています。私がこれに使用したライブラリは Simple HTML Dom Parser です。

52
Joel Verhagen

私たちは以前に自分のニーズに合わせてかなりの数のクローラを作成しました。一日の終わりには、通常は単純な正規表現が最善を尽くします。上に挙げたライブラリはそれらが作成された理由では有効ですが、探しているものがわかっている場合は無効な HTMLも処理できるので、正規表現を使用するのがより安全な方法です。 / XHTML 構造体。ほとんどのパーサーでロードすると失敗します。

41
jancha

私は PHP Simple HTML DOM Parser をお勧めします。

それは本当に素敵な機能を持っています。

foreach($html->find('img') as $element)
       echo $element->src . '<br>';
38
Greg

これは、W3C XPath テクノロジの優れたタスク説明のようです。 「すべてのhref属性を<foo><bar><baz> elementsにネストされているimgタグに戻す」のような照会を表現するのは簡単です。 PHPバフではないので、XPathがどのような形式で利用可能になるかはわかりません。 HTMLファイルを処理するために外部プログラムを呼び出すことができる場合は、XPathのコマンドラインバージョンを使用できるはずです。簡単な紹介については、 http://ja.wikipedia.org/wiki/XPath を参照してください。

36
Jens

文字列解析の代わりにDOMを使用するSimpleHtmlDomの他の代用品: phpQueryZend_DomQueryPath 、および FluentDom

29
danidacar

はい、あなたは目的のためにsimple_html_domを使うことができます。しかしながら、私はsimple_html_domを使って、特にウェブのスクラップのためにかなり多くの仕事をしました、そしてそれがあまりにも脆弱であることがわかりました。それは基本的な仕事をしますが、私はとにかくそれをお勧めしません。

私はカールをその目的のために使ったことは一度もありませんでしたが、私が学んだことはカールが仕事をはるかに効率的にすることができて、はるかに堅実であるということです。

このリンクをチェックしてください。 scraping-website-with-curl

24
Rafay

QueryPathは良いですが、意味がわからない場合は「状態の追跡」の原因に注意してください。これは多くのデバッグを無駄にすることを意味します。何が起こったのか、なぜコードが機能しないのかを調べようとする時間。

つまり、結果セットを呼び出すたびにオブジェクト内の結果セットが変更されます。各リンクが新しいセットであるjqueryのように連鎖することはできません。クエリからの結果である単一セットがあり、各関数呼び出しは変更されます。そのシングルセット。

jqueryのような振る舞いをさせるためには、filter/modifyのような操作をする前に分岐する必要があります。つまり、jqueryで起こることをより厳密に反映します。

$results = qp("div p");
$forename = $results->find("input[name='forename']");

$resultsinput[name='forename']の結果セットが含まれるようになりました。これは元々の"div p"ではありませんでしたが、QueryPathはフィルタを追跡して検索し、結果を修正してオブジェクトに保存するすべてのもの。代わりにこれをする必要があります

$forename = $results->branch()->find("input[name='forname']")

そうすれば$resultsは修正されず、結果セットを何度も何度も再利用することができます。おそらく、もっと多くの知識を持っている人は少しこれを片付けることができますが、基本的には私が見つけたもののようです。

23

Advanced Html Dom は単純なHTML DOM に代わるものです。同じインターフェイスですが、DOMベースです。つまり、関連するメモリの問題は発生しません。

また、 jQuery 拡張機能など、CSSを完全にサポートしています。

19
pguardiario

HTML5 については、html5 libは何年もの間放棄されてきました。私が最近のアップデートとメンテナンス記録で見つけることができる唯一のHTML5ライブラリは、 html5-php だけです。

18
Reid Johnson

私は簡単にGBファイルを扱うことができる汎用のXMLパーサーを書きました。これはXMLReaderに基づいており、非常に使いやすいです。

$source = new XmlExtractor("path/to/tag", "/path/to/file.xml");
foreach ($source as $tag) {
    echo $tag->field1;
    echo $tag->field2->subfield1;
}

これがgithubリポジトリです: XmlExtractor

17
Paul Warelis

私は PHPPowertools/DOM-Query という名前のライブラリを作成しました。

内部では、CSSセレクターの XPath への変換に symfony/DomCrawler を使用します。セレクター。適切なパフォーマンスを確保するために、あるオブジェクトを別のオブジェクトに渡す場合でも、常に同じDomDocumentを使用します。


使用例

namespace PowerTools;

// Get file content
$htmlcode = file_get_contents('https://github.com');

// Define your DOMCrawler based on file string
$H = new DOM_Query($htmlcode);

// Define your DOMCrawler based on an existing DOM_Query instance
$H = new DOM_Query($H->select('body'));

// Passing a string (CSS selector)
$s = $H->select('div.foo');

// Passing an element object (DOM Element)
$s = $H->select($documentBody);

// Passing a DOM Query object
$s = $H->select( $H->select('p + p'));

// Select the body tag
$body = $H->select('body');

// Combine different classes as one selector to get all site blocks
$siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer');

// Nest your methods just like you would with jQuery
$siteblocks->select('button')->add('span')->addClass('icon icon-printer');

// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) {
    return $i . " - " . $val->attr('class');
});

// Append the following HTML to all site blocks
$siteblocks->append('<div class="site-center"></div>');

// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');

// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see'));

// Use a lambda function to set the attributes of all site blocks
$siteblocks->attr('data-val', function( $i, $val) {
    return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
});

// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();

// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class');

// Wrap the site's footer within two nex selectors
$sitefooter->wrap('<section><div class="footer-wrapper"></div></section>');

[...]

サポートされているメソッド:


  1. 明らかな理由で、名前を 'select'に変更しました
  2. 'empty'はPHPで予約されているため、 'void'に改名されました。

注意 :

このライブラリには、PSR-0互換ライブラリ用の独自のゼロ設定オートローダも含まれています。含まれている例は追加設定なしで箱から出して動作するはずです。あるいは、composerと一緒に使用することもできます。

17
John Slegers

あなたは HTML Tidy のような何か "壊れた" HTMLをクリーンアップしてからHTMLをXHTMLに変換することを試みることができます。そしてそれをXMLパーサーで解析することができます。

15
CesarB

もう1つ試してみることができるのは、 QueryPath です。これはjQueryの影響を受けていますが、サーバー上のPHP内で使用され、 Drupal で使用されています。

15

XML_HTMLSax は、もう保守されていなくてもかなり安定しています。もう1つの選択肢は、HTMLを Html Tidy でパイプ処理してから、標準のXMLツールで解析することです。

12
troelskn

Symfony フレームワークにはHTMLを解析できるバンドルがあり、代わりにCSSスタイルを使用して DOMs を選択できます。 XPath を使用した例.

11
Tuong Le

HTML/XML DOMを処理する方法はたくさんありますが、そのほとんどが既に言及されています。したがって、私はそれらを自分でリストアップしようとはしません。

私は私が個人的にDOM拡張機能を使うことを好むという理由を付け加えたいだけです。

  • 基礎となるCコードのパフォーマンス上の利点を最大限に活用する
  • それはOO PHPです(そして私はそれをサブクラス化することができます)
  • かなり低いレベルです(これにより、より高度な動作を実現するための根拠のない基盤として使用することができます)。
  • dOMのすべての部分へのアクセスを提供します(たとえば、SimpleXmlは、あまり知られていないXML機能の一部を無視します)。
  • dOMクロールに使用される構文はネイティブのJavascriptで使用される構文と似ています。

DOMDocumentにCSSセレクターを使用することができませんが、この機能を追加するためのかなり簡単で便利な方法があります。DOMDocumentをサブクラス化し、JSのようなquerySelectorAllおよびquerySelectorメソッドをサブクラスに追加する方法です。

セレクターを解析するために、 Symfonyフレームワーク の非常にミニマルな CssSelectorコンポーネント を使用することをお勧めします。このコンポーネントはCSSセレクターをXPathセレクターに変換するだけで、それを対応するNodelistを取得するためにDOMXpathに渡すことができます。

そうすれば、この(まだ非常に低レベルの)サブクラスをより高水準のクラスの基礎として使用できます。非常に特殊なタイプのXMLを解析するか、jQueryに似た動作を追加してください。

以下のコードは、私の DOM-Queryライブラリ をそのまま使用し、私が説明した手法を使用しています。

HTML解析の場合

namespace PowerTools;

use \Symfony\Component\CssSelector\CssSelector as CssSelector;

class DOM_Document extends \DOMDocument {
    public function __construct($data = false, $doctype = 'html', $encoding = 'UTF-8', $version = '1.0') {
        parent::__construct($version, $encoding);
        if ($doctype && $doctype === 'html') {
            @$this->loadHTML($data);
        } else {
            @$this->loadXML($data);
        }
    }

    public function querySelectorAll($selector, $contextnode = null) {
        if (isset($this->doctype->name) && $this->doctype->name == 'html') {
            CssSelector::enableHtmlExtension();
        } else {
            CssSelector::disableHtmlExtension();
        }
        $xpath = new \DOMXpath($this);
        return $xpath->query(CssSelector::toXPath($selector, 'descendant::'), $contextnode);
    }

    [...]

    public function loadHTMLFile($filename, $options = 0) {
        $this->loadHTML(file_get_contents($filename), $options);
    }

    public function loadHTML($source, $options = 0) {
        if ($source && $source != '') {
            $data = trim($source);
            $html5 = new HTML5(array('targetDocument' => $this, 'disableHtmlNsInDom' => true));
            $data_start = mb_substr($data, 0, 10);
            if (strpos($data_start, '<!DOCTYPE ') === 0 || strpos($data_start, '<html>') === 0) {
                $html5->loadHTML($data);
            } else {
                @$this->loadHTML('<!DOCTYPE html><html><head><meta charset="' . $encoding . '" /></head><body></body></html>');
                $t = $html5->loadHTMLFragment($data);
                $docbody = $this->getElementsByTagName('body')->item(0);
                while ($t->hasChildNodes()) {
                    $docbody->appendChild($t->firstChild);
                }
            }
        }
    }

    [...]
}

Symfony用のCssSelectorコンポーネントを作成するという決定とその使用方法については、Symfonyの作成者Fabien Potencierによる CSSセレクターによるXML文書の解析 も参照してください。

11
John Slegers

FluidXML を使用すると、 XPath を使用してXMLを照会および反復できます。そして CSSセレクター

$doc = fluidxml('<html>...</html>');

$title = $doc->query('//head/title')[0]->nodeValue;

$doc->query('//body/p', 'div.active', '#bgId')
        ->each(function($i, $node) {
            // $node is a DOMNode.
            $tag   = $node->nodeName;
            $text  = $node->nodeValue;
            $class = $node->getAttribute('class');
        });

https://github.com/servo-php/fluidxml

9
Daniele Orlando

JSONとXMLからの3行の配列:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

タダ!

7
Antonio Max

HTMLを正規表現で解析しない理由はいくつかあります。しかし、どのHTMLが生成されるのかを完全に制御できれば、単純な正規表現でそれを実行できます。

上記はHTMLを正規表現で解析する関数です。この関数は非常に機密性が高く、HTMLが特定の規則に従うことを要求しますが、多くのシナリオで非常にうまく機能します。単純なパーサーが必要でライブラリをインストールしたくない場合は、これを試してみてください。

function array_combine_($keys, $values) {
    $result = array();
    foreach ($keys as $i => $k) {
        $result[$k][] = $values[$i];
    }
    array_walk($result, create_function('&$v', '$v = (count($v) == 1)? array_pop($v): $v;'));

    return $result;
}

function extract_data($str) {
    return (is_array($str))
        ? array_map('extract_data', $str)
        : ((!preg_match_all('#<([A-Za-z0-9_]*)[^>]*>(.*?)</\1>#s', $str, $matches))
            ? $str
            : array_map(('extract_data'), array_combine_($matches[1], $matches[2])));
}

print_r(extract_data(file_get_contents("http://www.google.com/")));
7
Daniel Loureiro

HTML5DOMDocumentというライブラリを作成しました。このライブラリは、 https://github.com/ivopetkov/html5-dom-document-php から無料で入手できます。

クエリセレクタもサポートしているので、あなたの場合は非常に役に立つでしょう。これがいくつかのコード例です:

$dom = new IvoPetkov\HTML5DOMDocument();
$dom->loadHTML('<!DOCTYPE html><html><body><h1>Hello</h1><div class="content">This is some text</div></body></html>');
echo $dom->querySelector('h1')->innerHTML;
2
Ivo Petkov

JQueryセレクタに慣れているのであれば、PHP用に ScarletsQuery を使用できます。

<pre><?php
include "ScarletsQuery.php";

// Load the HTML content and parse it
$html = file_get_contents('https://www.lipsum.com');
$dom = Scarlets\Library\MarkupLanguage::parseText($html);

// Select meta tag on the HTML header
$description = $dom->selector('head meta[name="description"]')[0];

// Get 'content' attribute value from meta tag
print_r($description->attr('content'));

$description = $dom->selector('#Content p');

// Get element array
print_r($description->view);

このライブラリは通常オフラインのHTMLを処理するのに1秒もかかりません。
無効なHTMLやタグ属性の引用符の欠落も受け入れます。

0
StefansArya

XMLを解析するための最良の方法:

$xml='http://www.example.com/rss.xml';
$rss = simplexml_load_string($xml);
$i = 0;
foreach ($rss->channel->item as $feedItem) {
$i++;
echo $title=$feedItem->title;
echo '<br>';
echo $link=$feedItem->link;
echo '<br>';
if($feedItem->description !='') {$des=$feedItem->description;} else {$des='';}
echo $des;
echo '<br>';
if($i>5) break;
}
0
user8031209