Wie analysieren und verarbeiten Sie HTML / XML in PHP?


Antworten:


1897

Native XML-Erweiterungen

Ich bevorzuge die Verwendung einer der nativen XML-Erweiterungen, da diese mit PHP gebündelt sind, normalerweise schneller als alle Bibliotheken von Drittanbietern sind und mir die Kontrolle geben, die ich über das Markup benötige.

DOM

Mit der DOM-Erweiterung können Sie XML-Dokumente über die DOM-API mit PHP 5 bearbeiten. Sie ist eine Implementierung des Document Object Model Core Level 3 des W3C, einer plattform- und sprachneutralen Schnittstelle, über die Programme und Skripte dynamisch zugreifen und aktualisieren können Inhalt, Struktur und Stil der Dokumente.

DOM ist in der Lage, (kaputtes) HTML aus der realen Welt zu analysieren und zu ändern und XPath-Abfragen durchzuführen . Es basiert auf libxml .

Es dauert einige Zeit, um mit DOM produktiv zu werden, aber diese Zeit lohnt sich IMO. Da DOM eine sprachunabhängige Schnittstelle ist, finden Sie Implementierungen in vielen Sprachen. Wenn Sie also Ihre Programmiersprache ändern müssen, wissen Sie wahrscheinlich bereits, wie die DOM-API dieser Sprache verwendet wird.

Ein grundlegendes Anwendungsbeispiel finden Sie unter Abrufen des href-Attributs eines A-Elements. Eine allgemeine konzeptionelle Übersicht finden Sie unter DOMDocument in PHP

Die Verwendung der DOM-Erweiterung wurde in StackOverflow ausführlich behandelt. Wenn Sie sich also für die Verwendung entscheiden, können Sie sicher sein, dass die meisten Probleme, auf die Sie stoßen, durch Suchen / Durchsuchen des Stapelüberlaufs gelöst werden können.

XMLReader

Die XMLReader-Erweiterung ist ein XML-Pull-Parser. Der Leser fungiert als Cursor, der im Dokumentstrom vorwärts geht und an jedem Knoten auf dem Weg anhält.

XMLReader basiert wie DOM auf libxml. Ich weiß nicht, wie das HTML-Parser-Modul ausgelöst werden soll. Daher ist die Verwendung von XMLReader zum Parsen von fehlerhaftem HTML möglicherweise weniger robust als die Verwendung von DOM, bei dem Sie explizit anweisen können, das HTML-Parser-Modul von libxml zu verwenden.

Ein grundlegendes Anwendungsbeispiel finden Sie unter Abrufen aller Werte von h1-Tags mithilfe von PHP

XML-Parser

Mit dieser Erweiterung können Sie XML-Parser erstellen und dann Handler für verschiedene XML-Ereignisse definieren. Jeder XML-Parser verfügt auch über einige Parameter, die Sie anpassen können.

Die XML-Parser-Bibliothek basiert ebenfalls auf libxml und implementiert einen XML-Push-Parser im SAX- Stil. Es ist möglicherweise eine bessere Wahl für die Speicherverwaltung als DOM oder SimpleXML, aber es ist schwieriger, damit zu arbeiten als mit dem von XMLReader implementierten Pull-Parser.

SimpleXml

Die SimpleXML-Erweiterung bietet ein sehr einfaches und leicht zu verwendendes Toolset zum Konvertieren von XML in ein Objekt, das mit normalen Eigenschaftswählern und Array-Iteratoren verarbeitet werden kann.

SimpleXML ist eine Option, wenn Sie wissen, dass HTML XHTML ist. Wenn Sie fehlerhaftes HTML analysieren müssen, sollten Sie SimpleXml nicht einmal in Betracht ziehen, da es erstickt.

Ein grundlegendes Anwendungsbeispiel findet Sie unter Einem einfachen Programm , um CRUD Knoten und Knotenwerte von XML - Datei , und es gibt viele weitere Beispiele in der PHP Manual .


Bibliotheken von Drittanbietern (libxml-basiert)

Wenn Sie eine Bibliothek eines Drittanbieters bevorzugen, würde ich vorschlagen, eine Bibliothek zu verwenden, die tatsächlich DOM / libxml darunter verwendet, anstatt Zeichenfolgen zu analysieren.

FluentDom - Repo

FluentDOM bietet eine jQuery-ähnliche fließende XML-Schnittstelle für das DOMDocument in PHP. Selektoren werden in XPath oder CSS geschrieben (unter Verwendung eines CSS-zu-XPath-Konverters). Aktuelle Versionen erweitern das DOM, indem sie Standardschnittstellen implementieren und Funktionen aus dem DOM Living Standard hinzufügen. FluentDOM kann Formate wie JSON, CSV, JsonML, RabbitFish und andere laden. Kann über Composer installiert werden.

HtmlPageDom

Wa72 \ HtmlPageDom` ist eine PHP-Bibliothek zur einfachen Bearbeitung von HTML-Dokumenten mit DomCrawler von Symfony2-Komponenten zum Durchlaufen des DOM-Baums und erweitert sie um Methoden zum Bearbeiten des DOM-Baums von HTML-Dokumenten.

phpQuery (seit Jahren nicht mehr aktualisiert)

phpQuery ist eine serverseitige, verkettbare, CSS3-selektorgesteuerte DOM-API (Document Object Model), die auf der in PHP5 geschriebenen jQuery-JavaScript-Bibliothek basiert und eine zusätzliche Befehlszeilenschnittstelle (Command Line Interface, CLI) bietet.

Siehe auch: https://github.com/electrolinux/phpquery

Zend_Dom

Zend_Dom bietet Tools zum Arbeiten mit DOM-Dokumenten und -Strukturen. Derzeit bieten wir Zend_Dom_Query an, das eine einheitliche Schnittstelle zum Abfragen von DOM-Dokumenten mit XPath- und CSS-Selektoren bietet.

QueryPath

QueryPath ist eine PHP-Bibliothek zum Bearbeiten von XML und HTML. Es funktioniert nicht nur mit lokalen Dateien, sondern auch mit Webdiensten und Datenbankressourcen. Es implementiert einen Großteil der jQuery-Schnittstelle (einschließlich CSS-Selektoren), ist jedoch stark auf die serverseitige Verwendung abgestimmt. Kann über Composer installiert werden.

fDOMDocument

fDOMDocument erweitert das Standard-DOM, um bei allen Fehlerausnahmen Ausnahmen anstelle von PHP-Warnungen oder Hinweisen zu verwenden. Sie fügen auch verschiedene benutzerdefinierte Methoden und Verknüpfungen hinzu, um die Verwendung von DOM zu vereinfachen und zu vereinfachen.

Säbel / XML

saber / xml ist eine Bibliothek, die die Klassen XMLReader und XMLWriter umschließt und erweitert, um ein einfaches Zuordnungssystem und Entwurfsmuster für "XML zu Objekt / Array" zu erstellen. Das Schreiben und Lesen von XML erfolgt in einem Durchgang und kann daher schnell sein und wenig Speicher für große XML-Dateien erfordern.

FluidXML

FluidXML ist eine PHP-Bibliothek zum Bearbeiten von XML mit einer übersichtlichen und fließenden API. Es nutzt XPath und das fließende Programmiermuster, um Spaß zu haben und effektiv zu sein.


Drittanbieter (nicht libxml-basiert)

Der Vorteil des Aufbaus auf DOM / libxml besteht darin, dass Sie sofort eine gute Leistung erzielen, da Sie auf einer nativen Erweiterung basieren. Allerdings gehen nicht alle Bibliotheken von Drittanbietern diesen Weg. Einige von ihnen sind unten aufgeführt

PHP Einfacher HTML DOM Parser

  • Mit einem in PHP5 + geschriebenen HTML-DOM-Parser können Sie HTML auf sehr einfache Weise bearbeiten!
  • Benötigen Sie PHP 5+.
  • Unterstützt ungültiges HTML.
  • Suchen Sie Tags auf einer HTML-Seite mit Selektoren wie jQuery.
  • Extrahieren Sie Inhalte aus HTML in einer einzigen Zeile.

Ich empfehle diesen Parser im Allgemeinen nicht. Die Codebasis ist schrecklich und der Parser selbst ist ziemlich langsam und speicherhungrig. Nicht alle jQuery-Selektoren (z. B. untergeordnete Selektoren ) sind möglich. Jede der libxml-basierten Bibliotheken sollte dies leicht übertreffen.

PHP Html Parser

PHPHtmlParser ist ein einfacher, flexibler HTML-Parser, mit dem Sie Tags mit einem beliebigen CSS-Selektor wie jQuery auswählen können. Das Ziel ist es, bei der Entwicklung von Tools zu helfen, die eine schnelle und einfache Möglichkeit zum Verschrotten von HTML erfordern, unabhängig davon, ob es gültig ist oder nicht! Dieses Projekt wurde ursprünglich von sunra / php-simple-html-dom-parser unterstützt, aber die Unterstützung scheint aufgehört zu haben, so dass dieses Projekt meine Anpassung seiner vorherigen Arbeit ist.

Auch hier würde ich diesen Parser nicht empfehlen. Es ist ziemlich langsam mit hoher CPU-Auslastung. Es gibt auch keine Funktion zum Löschen des Speichers für erstellte DOM-Objekte. Diese Probleme lassen sich insbesondere bei verschachtelten Schleifen skalieren. Die Dokumentation selbst ist ungenau und falsch geschrieben. Seit dem 14. April 16 gibt es keine Antworten auf Korrekturen.

Ganon

  • Ein universeller Tokenizer und HTML / XML / RSS-DOM-Parser
    • Fähigkeit, Elemente und ihre Attribute zu manipulieren
    • Unterstützt ungültiges HTML und UTF8
  • Kann erweiterte CSS3-ähnliche Abfragen für Elemente ausführen (z. B. jQuery - Namespaces unterstützt)
  • Ein HTML-Verschönerer (wie HTML Tidy)
    • Minimieren Sie CSS und Javascript
    • Attribute sortieren, Groß- und Kleinschreibung ändern, Einrückung korrigieren usw.
  • Erweiterbar
    • Analysieren von Dokumenten mithilfe von Rückrufen basierend auf dem aktuellen Zeichen / Token
    • Operationen, die in kleinere Funktionen unterteilt sind, erleichtern das Überschreiben
  • Schnell und einfach

Ich habe es nie benutzt. Ich kann nicht sagen, ob es etwas Gutes ist.


HTML 5

Sie können das oben Gesagte zum Parsen von HTML5 verwenden, es kann jedoch aufgrund des von HTML5 zugelassenen Markups zu Macken kommen . Für HTML5 möchten Sie also einen dedizierten Parser verwenden, z

html5lib

Eine Python- und PHP-Implementierung eines HTML-Parsers basierend auf der WHATWG HTML5-Spezifikation für maximale Kompatibilität mit den wichtigsten Desktop-Webbrowsern.

Nach der Fertigstellung von HTML5 werden möglicherweise mehr dedizierte Parser angezeigt. Es gibt auch einen Blogpost des W3 mit dem Titel " How-To for HTML 5 Parsing" , der einen Besuch wert ist.


Internetdienste

Wenn Sie keine Lust haben, PHP zu programmieren, können Sie auch Webdienste verwenden. Im Allgemeinen fand ich sehr wenig Nutzen für diese, aber das sind nur ich und meine Anwendungsfälle.

ScraperWiki .

Über die externe Oberfläche von ScraperWiki können Sie Daten in der Form extrahieren, die Sie für die Verwendung im Web oder in Ihren eigenen Anwendungen benötigen. Sie können auch Informationen über den Zustand eines Schabers extrahieren.


Reguläre Ausdrücke

Als letztes und am wenigsten empfohlen können Sie Daten mit regulären Ausdrücken aus HTML extrahieren . Im Allgemeinen wird davon abgeraten, reguläre Ausdrücke in HTML zu verwenden.

Die meisten Schnipsel, die Sie im Web finden, um Markups abzugleichen, sind spröde. In den meisten Fällen arbeiten sie nur für ein bestimmtes Stück HTML. Winzige Markup-Änderungen, wie das Hinzufügen von Leerzeichen irgendwo oder das Hinzufügen oder Ändern von Attributen in einem Tag, können dazu führen, dass RegEx fehlschlägt, wenn es nicht richtig geschrieben ist. Sie sollten wissen, was Sie tun, bevor Sie RegEx in HTML verwenden.

HTML-Parser kennen bereits die syntaktischen Regeln von HTML. Für jeden neuen RegEx, den Sie schreiben, müssen reguläre Ausdrücke unterrichtet werden. RegEx sind in einigen Fällen in Ordnung, aber es hängt wirklich von Ihrem Anwendungsfall ab.

Sie können zuverlässigere Parser schreiben , aber das Schreiben eines vollständigen und zuverlässigen benutzerdefinierten Parsers mit regulären Ausdrücken ist Zeitverschwendung, wenn die oben genannten Bibliotheken bereits vorhanden sind und diesbezüglich viel bessere Arbeit leisten.

Siehe auch Parsing Html The Cthulhu Way


Bücher

Wenn Sie etwas Geld ausgeben möchten, schauen Sie sich an

Ich bin nicht mit PHP Architect oder den Autoren verbunden.


10
@Naveed das hängt von deinen Bedürfnissen ab. Ich brauche keine CSS Selector-Abfragen, weshalb ich DOM ausschließlich mit XPath verwende. phpQuery soll ein jQuery-Port sein. Zend_Dom ist leicht. Sie müssen sie wirklich überprüfen, um zu sehen, welche Ihnen am besten gefällt.
Gordon

2
@ Ms2ger Meistens, aber nicht vollständig. Wie bereits oben erwähnt, können Sie die libxml-basierten Parser verwenden, aber es gibt spezielle Fälle, in denen diese ersticken. Wenn Sie maximale Kompatibilität benötigen, sind Sie mit einem dedizierten Parser besser dran. Ich ziehe es vor, die Unterscheidung beizubehalten.
Gordon

9
Ihr Argument, PHP Simple HTML DOM Parser nicht zu verwenden, scheint umstritten zu sein.
Petah

3
Ab dem 29. März 2012 unterstützt DOM HTML5 nicht, XMLReader unterstützt HTML nicht und das letzte Commit für HTML5lib für PHP erfolgt im September 2009. Was ist zum Parsen von HTML5, HTML4 und XHTML zu verwenden?
Shiplu Mokaddim

4
@Nasha Ich habe den berüchtigten Zalgo-Rant absichtlich von der obigen Liste ausgeschlossen, weil er für sich genommen nicht allzu hilfreich ist und zu einem ziemlichen Frachtkult führt, seit er geschrieben wurde. Die Leute wurden mit diesem Link niedergeschlagen, egal wie angemessen eine Regex als Lösung gewesen wäre. Für eine ausgewogene Meinung, sehen Sie bitte den Link Ich habe stattdessen enthalten und die Kommentare durch stackoverflow.com/questions/4245008/...
Gordon

322

Probieren Sie Simple HTML DOM Parser aus

  • Ein in PHP 5+ geschriebener HTML-DOM-Parser, mit dem Sie HTML auf sehr einfache Weise bearbeiten können!
  • Benötigen Sie PHP 5+.
  • Unterstützt ungültiges HTML.
  • Suchen Sie Tags auf einer HTML-Seite mit Selektoren wie jQuery.
  • Extrahieren Sie Inhalte aus HTML in einer einzigen Zeile.
  • Herunterladen


Beispiele:

So erhalten Sie HTML-Elemente:

// 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>';


So ändern Sie HTML-Elemente:

// 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;


Inhalte aus HTML extrahieren:

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


Scraping Slashdot:

// 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);

8
Nun, erstens gibt es Dinge, auf die ich mich vorbereiten muss, wie z. B. schlechte DOMs, Invlid-Code und js, die gegen die DNSBL-Engine analysiert werden. Dies wird auch verwendet, um nach schädlichen Websites / Inhalten Ausschau zu halten, auch wenn ich meine Website um ein Framework herum aufgebaut habe gebaut haben, muss es sauber, lesbar und gut strukturiert sein. SimpleDim ist großartig, aber der Code ist etwas chaotisch
RobertPitt

9
@Robert Vielleicht möchten Sie auch htmlpurifier.org nach sicherheitsrelevanten Dingen durchsuchen .
Gordon

3
Er hat einen gültigen Punkt: simpleHTMLDOM ist schwer zu erweitern, es sei denn, Sie verwenden ein Dekorationsmuster, das ich als unhandlich empfinde. Ich habe mich erschaudert , als ich nur Änderungen an den zugrunde liegenden Klassen selbst vorgenommen habe.
Erik

1
Ich habe mein HTML aufgeräumt, bevor ich es an SimpleDOM gesendet habe.
MB34

1
Ich verwende dies derzeit und führe es als Teil eines Projekts aus, um einige hundert URLs zu verarbeiten. Es wird sehr langsam und regelmäßige Timeouts bleiben bestehen. Es ist ein großartiges Anfängerskript und intuitiv einfach zu erlernen, aber für fortgeschrittenere Projekte einfach zu einfach.
luke_mclachlan

236

Verwenden Sie einfach DOMDocument-> loadHTML () und fertig. Der HTML-Parsing-Algorithmus von libxml ist recht gut und schnell und erstickt entgegen der landläufigen Meinung nicht an fehlerhaftem HTML.


19
Wahr. Und es funktioniert mit den in PHP integrierten XPath- und XSLTProcessor-Klassen, die sich hervorragend zum Extrahieren von Inhalten eignen.
Kornel

8
Für wirklich verstümmeltes HTML können Sie es jederzeit durch htmltidy ausführen, bevor Sie es an DOM übergeben. Wann immer ich Daten aus HTML kratzen muss, verwende ich immer DOM oder zumindest Simplexml.
Frank Farmer

9
Eine andere Sache beim Laden von fehlerhaftem HTML i ist, dass es ratsam sein könnte, libxml_use_internal_errors (true) aufzurufen, um Warnungen zu verhindern, die das Parsen beenden.
Husky

6
Ich habe DOMDocument verwendet, um ungefähr 1000 HTML-Quellen (in verschiedenen Sprachen, die mit verschiedenen Zeichensätzen codiert sind) ohne Probleme zu analysieren. Möglicherweise treten dabei Codierungsprobleme auf, die jedoch nicht unüberwindbar sind. Sie müssen drei Dinge wissen: 1) loadHTML verwendet den Zeichensatz des Meta-Tags, um die Codierung zu bestimmen. 2) # 2 kann zu einer falschen Codierungserkennung führen, wenn der HTML-Inhalt diese Informationen nicht enthält. 3) Falsche UTF-8-Zeichen können den Parser auslösen. Verwenden Sie in solchen Fällen eine Kombination aus mb_detect_encoding () und dem Codierungs- / Konvertierungs- / Stripping-Code für fehlerhafte UTF-8-Zeichen von Simplepie RSS Parser, um das Problem zu umgehen.
Null

1
DOM unterstützt tatsächlich XPath. Schauen Sie sich DOMXPath an .
Ryan McCue

147

Warum sollten Sie nicht und wann sollten Sie reguläre Ausdrücke verwenden?

Zunächst einmal eine häufige Fehlbezeichnung: Regexps sind nicht zum " Parsen " von HTML gedacht . Regexes können jedoch Daten " extrahieren " . Extrahieren ist das, wofür sie gemacht sind. Der Hauptnachteil der Regex-HTML-Extraktion gegenüber geeigneten SGML-Toolkits oder XML-Basisparsern ist ihr syntaktischer Aufwand und ihre unterschiedliche Zuverlässigkeit.

Bedenken Sie, dass Sie einen etwas zuverlässigen HTML-Extraktions-Regex erstellen:

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

ist viel weniger lesbar als ein einfaches phpQuery- oder QueryPath-Äquivalent:

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

Es gibt jedoch spezielle Anwendungsfälle, in denen sie helfen können.

  • Viele DOM-Traversal-Frontends zeigen keine HTML-Kommentare an <!-- , die jedoch manchmal die nützlicheren Anker für die Extraktion sind. Insbesondere Pseudo-HTML-Variationen <$var>oder SGML-Reste lassen sich mit regulären Ausdrücken leicht zähmen.
  • Oft können reguläre Ausdrücke die Nachbearbeitung sparen. HTML-Entitäten erfordern jedoch häufig eine manuelle Pflege.
  • Und schließlich für extrem einfache Aufgaben wie das Extrahieren von <img src = urls tatsächlich ein wahrscheinliches Werkzeug. Der Geschwindigkeitsvorteil gegenüber SGML / XML-Parsern kommt meist nur bei diesen sehr grundlegenden Extraktionsverfahren zum Tragen.

Manchmal ist es sogar ratsam, einen HTML-Ausschnitt mit regulären Ausdrücken vorab zu extrahieren /<!--CONTENT-->(.+?)<!--END-->/ und den Rest mit den einfacheren HTML-Parser-Frontends zu verarbeiten.

Hinweis: Ich habe tatsächlich diese App , in der ich alternativ XML-Parsing und reguläre Ausdrücke verwende. Erst letzte Woche war die PyQuery-Analyse unterbrochen, und der reguläre Ausdruck funktionierte immer noch. Ja komisch, und ich kann es nicht selbst erklären. Aber so ist es passiert.
Bitte stimmen Sie nicht über reale Überlegungen ab, nur weil sie nicht mit dem regulären Ausdruck = böses Mem übereinstimmen. Aber lasst uns das auch nicht zu sehr abstimmen. Es ist nur eine Nebenbemerkung zu diesem Thema.


20
DOMCommentkann Kommentare lesen, daher kein Grund, Regex dafür zu verwenden.
Gordon

4
Weder SGML-Toolkits noch XML-Parser eignen sich zum Parsen von echtem HTML. Dafür ist nur ein dedizierter HTML-Parser geeignet.
Alohci

12
@Alohci DOMverwendet libxml und libxml verfügt über ein separates HTML-Parser- Modul, das beim Laden von HTML verwendet wird, loadHTML()damit es sehr viel "reales" (defektes) HTML laden kann.
Gordon

6
Nun, nur ein Kommentar zu Ihrem Standpunkt der "realen Betrachtung". Sicher, es gibt nützliche Situationen für Regex beim Parsen von HTML. Und es gibt auch nützliche Situationen für die Verwendung von GOTO. Und es gibt nützliche Situationen für Variablenvariablen. Daher ist keine bestimmte Implementierung definitiv Code-Rot für die Verwendung. Aber es ist ein sehr starkes Warnzeichen. Und der durchschnittliche Entwickler ist wahrscheinlich nicht nuanciert genug, um den Unterschied zu erkennen. In der Regel sind Regex GOTO und Variable-Variables alle böse. Es gibt nicht böse Verwendungen, aber das sind die Ausnahmen (und noch dazu selten) ... (IMHO)
ircmaxell

11
@mario: Eigentlich HTML kann sein ‚richtig‘ analysiert reguläre Ausdrücke verwenden, obwohl in der Regel dauert es mehrere von ihnen einen fairen Job eine Meise zu tun. Es ist nur ein königlicher Schmerz im allgemeinen Fall. In bestimmten Fällen mit genau definierten Eingaben ist dies eher trivial. Das sind die Fälle , die Menschen sollten über die Verwendung Regexes werden. Große, alte, hungrige, schwere Parser sind wirklich das, was Sie für allgemeine Fälle benötigen, obwohl dem Gelegenheitsbenutzer nicht immer klar ist, wo er diese Grenze ziehen soll. Welcher Code einfacher und einfacher ist, gewinnt.
Tchrist

131

phpQuery und QueryPath sind sich beim Replizieren der fließenden jQuery-API sehr ähnlich. Das ist auch der Grund, warum sie zwei der einfachsten Ansätze sind, um HTML in PHP richtig zu analysieren.

Beispiele für QueryPath

Grundsätzlich erstellen Sie zunächst einen abfragbaren DOM-Baum aus einer HTML-Zeichenfolge:

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

Das resultierende Objekt enthält eine vollständige Baumdarstellung des HTML-Dokuments. Es kann mit DOM-Methoden durchlaufen werden. Der übliche Ansatz besteht jedoch darin, CSS-Selektoren wie in jQuery zu verwenden:

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

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

Meistens möchten Sie einfache #idund / .classoder DIVTag-Selektoren für verwenden ->find(). Sie können aber auch XPath- Anweisungen verwenden, die manchmal schneller sind. Auch typische jQuery-Methoden wie ->children()und und ->text()und ->attr()vereinfachen insbesondere das Extrahieren der richtigen HTML-Snippets. (Und haben bereits ihre SGML-Entitäten dekodiert.)

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

QueryPath ermöglicht auch das Einfügen neuer Tags in den Stream ( ->append) und das spätere Ausgeben und Verschönern eines aktualisierten Dokuments ( ->writeHTML). Es kann nicht nur fehlerhaftes HTML analysieren, sondern auch verschiedene XML-Dialekte (mit Namespaces) und sogar Daten aus HTML-Mikroformaten (XFN, vCard) extrahieren.

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

.

phpQuery oder QueryPath?

Im Allgemeinen eignet sich QueryPath besser für die Bearbeitung von Dokumenten. Während phpQuery auch einige Pseudo-AJAX-Methoden (nur HTTP-Anforderungen) implementiert, um jQuery ähnlicher zu werden. Es wird gesagt, dass phpQuery oft schneller als QueryPath ist (wegen weniger Gesamtfunktionen).

Weitere Informationen zu den Unterschieden finden Sie in diesem Vergleich auf der Wayback-Maschine von tagbyte.org . (Die ursprüngliche Quelle ist verschwunden, daher hier ein Link zum Internetarchiv. Ja, Sie können immer noch fehlende Seiten und Personen finden.)

Und hier ist eine umfassende Einführung in QueryPath .

Vorteile

  • Einfachheit und Zuverlässigkeit
  • Einfach zu bedienende Alternativen ->find("a img, a object, div a")
  • Richtige Datenentfernung (im Vergleich zu Grepping mit regulären Ausdrücken)

88

Simple HTML DOM ist ein großartiger Open-Source-Parser:

simplehtmldom.sourceforge

Es behandelt DOM-Elemente objektorientiert, und die neue Iteration bietet eine umfassende Abdeckung für nicht konformen Code. Es gibt auch einige großartige Funktionen, wie Sie sie in JavaScript sehen würden, wie beispielsweise die Funktion "find", die alle Instanzen von Elementen dieses Tag-Namens zurückgibt.

Ich habe dies in einer Reihe von Tools verwendet und es auf vielen verschiedenen Arten von Webseiten getestet, und ich denke, es funktioniert großartig.


61

Ein allgemeiner Ansatz, den ich hier nicht erwähnt habe, ist das Ausführen von HTML über Tidy , das so eingestellt werden kann, dass es garantiert gültiges XHTML ausspuckt. Dann können Sie jede alte XML-Bibliothek darauf verwenden.

Um Ihr spezifisches Problem zu lösen, sollten Sie sich dieses Projekt ansehen: http://fivefilters.org/content-only/ - Es handelt sich um eine modifizierte Version des Lesbarkeitsalgorithmus , mit der nur der Textinhalt (keine Überschriften) extrahiert werden soll und Fußzeilen) von einer Seite.


56

Für 1a und 2: Ich würde für die neue Symfony Componet-Klasse DOMCrawler ( DomCrawler ) stimmen . Diese Klasse ermöglicht Abfragen ähnlich wie CSS-Selektoren. Schauen Sie sich diese Präsentation für Beispiele aus der Praxis an : News-of-the-Symfony2-World .

Die Komponente ist eigenständig konzipiert und kann ohne Symfony verwendet werden.

Der einzige Nachteil ist, dass es nur mit PHP 5.3 oder neuer funktioniert.


jquery-ähnliche CSS-Abfragen sind gut gesagt, da einige Dinge in der w3c-Dokumentation fehlen, aber als zusätzliche Funktionen in jquery vorhanden sind.
Nikola Petkanski

53

Dies wird übrigens allgemein als Screen Scraping bezeichnet . Die Bibliothek, die ich dafür verwendet habe, ist Simple HTML Dom Parser .


8
Nicht unbedingt wahr ( en.wikipedia.org/wiki/Screen_scraping#Screen_scraping ). Der Hinweis ist in "Bildschirm"; Im beschriebenen Fall ist kein Bildschirm beteiligt. Zugegeben, der Begriff wurde in letzter Zeit sehr oft missbraucht.
Bobby Jack

4
Ich bin kein Screen Scraping, der Inhalt, der analysiert wird, wird vom Inhaltsanbieter gemäß meiner Vereinbarung autorisiert.
RobertPitt

41

Wir haben schon einige Crawler für unsere Bedürfnisse erstellt. Am Ende des Tages sind es normalerweise einfache reguläre Ausdrücke, die das Beste tun. Während die oben aufgeführten Bibliotheken aus dem Grund, aus dem sie erstellt wurden, gut sind, sind reguläre Ausdrücke ein sicherer Weg, wenn Sie wissen, wonach Sie suchen, da Sie auch ungültige HTML / XHTML- Strukturen verarbeiten können, die beim Laden fehlschlagen würden über die meisten Parser.



36

Dies klingt nach einer guten Aufgabenbeschreibung der W3C XPath- Technologie. Es ist einfach, Abfragen wie "Alle hrefAttribute in imgverschachtelten Tags zurückgeben " auszudrücken <foo><bar><baz> elements. Da ich kein PHP-Fan bin, kann ich Ihnen nicht sagen, in welcher Form XPath verfügbar sein könnte. Wenn Sie ein externes Programm aufrufen können, um die HTML-Datei zu verarbeiten, sollten Sie eine Befehlszeilenversion von XPath verwenden können. Eine kurze Einführung finden Sie unter http://en.wikipedia.org/wiki/XPath .


29

Alternativen von Drittanbietern zu SimpleHtmlDom, die DOM anstelle von String Parsing verwenden: phpQuery , Zend_Dom , QueryPath und FluentDom .


3
Wenn Sie meine Kommentare bereits kopieren, verknüpfen Sie sie zumindest ordnungsgemäß;) Dies sollte sein: Vorgeschlagene Alternativen von Drittanbietern zu SimpleHtmlDom , die tatsächlich DOM anstelle von String Parsing verwenden: phpQuery , Zend_Dom , QueryPath und FluentDom .
Gordon

1
Gute Antworten sind eine gute Quelle. stackoverflow.com/questions/3606792/…
danidacar

24

Ja, Sie können simple_html_dom für diesen Zweck verwenden. Ich habe jedoch ziemlich viel mit simple_html_dom gearbeitet, insbesondere beim Verschrotten von Webinhalten, und festgestellt, dass es zu anfällig ist. Es macht den grundlegenden Job, aber ich werde es sowieso nicht empfehlen.

Ich habe Curl nie für diesen Zweck verwendet, aber ich habe gelernt, dass Curl die Arbeit viel effizienter erledigen kann und viel solider ist.

Bitte überprüfen Sie diesen Link: Scraping-Websites-mit-Curl


2
curl kann erhalten die Datei, aber es wird nicht Parse - HTML für Sie. Das ist der schwierige Teil.
CHao

23

QueryPath ist gut, aber achten Sie auf den "Tracking-Status", denn wenn Sie nicht wissen , was dies bedeutet, können Sie viel Debugging-Zeit damit verschwenden, herauszufinden, was passiert ist und warum der Code nicht funktioniert.

Dies bedeutet, dass jeder Aufruf der Ergebnismenge die Ergebnismenge im Objekt ändert. Sie ist nicht verkettbar wie in jquery, wo jeder Link eine neue Menge ist. Sie haben eine einzelne Menge, die die Ergebnisse Ihrer Abfrage sind, und jeder Funktionsaufruf ändert sich dieser einzelne Satz.

Um ein jquery-ähnliches Verhalten zu erzielen, müssen Sie verzweigen, bevor Sie eine Filter- / Änderungsoperation ausführen. Dies bedeutet, dass das, was in jquery geschieht, viel genauer wiedergegeben wird.

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

$resultsEnthält jetzt die Ergebnismenge für input[name='forename']NICHT die ursprüngliche Abfrage "div p", die mich sehr gestolpert hat. Ich habe festgestellt, dass QueryPath die Filter und Funde sowie alles, was Ihre Ergebnisse ändert und im Objekt speichert, verfolgt. Sie müssen dies stattdessen tun

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

Dann $resultswird es nicht geändert und Sie können die Ergebnismenge immer wieder verwenden. Vielleicht kann jemand mit viel mehr Wissen dies ein wenig klären, aber es ist im Grunde so, wie ich es gefunden habe.


20

Advanced Html Dom ist ein einfacher HTML- DOM- Ersatz, der dieselbe Schnittstelle bietet, jedoch DOM-basiert ist, was bedeutet, dass keines der damit verbundenen Speicherprobleme auftritt.

Es bietet außerdem vollständige CSS-Unterstützung, einschließlich jQuery- Erweiterungen.


Ich habe gute Ergebnisse von Advanced Html Dom und ich denke, es sollte auf der Liste in der akzeptierten Antwort stehen. Eine wichtige Sache, die Sie jedoch wissen sollten, wenn Sie sich auf das "Ziel dieses Projekts ist es, ein DOM-basierter Drop-In-Ersatz für die einfache HTML-Dom-Bibliothek von PHP zu sein ... Wenn Sie die Datei / str_get_html verwenden, müssen Sie dies nicht tun." etwas ändern." archive.is/QtSuj#selection-933.34-933.100 ist, dass Sie möglicherweise Änderungen an Ihrem Code vornehmen müssen, um einige Inkompatibilitäten auszugleichen. Ich habe vier mir bekannte in den Github-Problemen des Projekts notiert. github.com/monkeysuffrage/advanced_html_dom/issues
ChrisJJ

Hat funktioniert ! Danke
Faisal Shani

18

Für HTML5 wurde html5 lib seit Jahren aufgegeben. Die einzige HTML5-Bibliothek, die ich mit einem aktuellen Update und Wartungsprotokollen finden kann, ist HTML5-PHP, das vor etwas mehr als einer Woche auf Beta 1.0 gebracht wurde.


17

Ich habe einen Allzweck-XML-Parser geschrieben, der problemlos mit GB-Dateien umgehen kann. Es basiert auf XMLReader und ist sehr einfach zu bedienen:

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

Hier ist das Github-Repo: XmlExtractor


17

Ich habe eine Bibliothek mit dem Namen PHPPowertools / DOM-Query erstellt , mit der Sie HTML5- und XML-Dokumente genau wie mit jQuery crawlen können.

Unter der Haube wird Symfony / DomCrawler zum Konvertieren von CSS-Selektoren in XPath- Selektoren verwendet. Es wird immer dasselbe DomDocument verwendet, auch wenn ein Objekt an ein anderes übergeben wird, um eine angemessene Leistung sicherzustellen.


Anwendungsbeispiel:

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>');

[...]

Unterstützte Methoden:


  1. Aus offensichtlichen Gründen in "Auswählen" umbenannt
  2. Umbenannt in "void", da "empty" in PHP ein reserviertes Wort ist

HINWEIS :

Die Bibliothek enthält auch einen eigenen Autoloader ohne Konfiguration für PSR-0-kompatible Bibliotheken. Das enthaltene Beispiel sollte ohne zusätzliche Konfiguration sofort funktionieren. Alternativ können Sie es mit Composer verwenden.


Sieht aus wie das richtige Tool für den Job, wird aber in PHP 5.6.23 in Worpress nicht für mich geladen. Irgendwelche zusätzlichen Anweisungen, wie man es richtig einfügt?. Enthält es mit: define ("BASE_PATH", dirname ( FILE )); define ("LIBRARY_PATH", BASE_PATH. DIRECTORY_SEPARATOR. 'lib / vendor'); erfordern LIBRARY_PATH. DIRECTORY_SEPARATOR. 'Loader.php'; Loader :: init (Array (LIBRARY_PATH, USER_PATH)); in functions.php
Lithiumlab

15

Sie können versuchen, HTML Tidy zu verwenden, um "defektes" HTML zu bereinigen und das HTML in XHTML zu konvertieren, das Sie dann mit einem XML-Parser analysieren können.





11

Es gibt viele Möglichkeiten, HTML / XML-DOM zu verarbeiten, von denen die meisten bereits erwähnt wurden. Daher werde ich nicht versuchen, diese selbst aufzulisten.

Ich möchte nur hinzufügen, dass ich persönlich die DOM-Erweiterung bevorzuge und warum:

  • iit nutzt den Leistungsvorteil des zugrunde liegenden C-Codes optimal aus
  • Es ist OO PHP (und erlaubt mir, es zu unterordnen)
  • Es ist ein ziemlich niedriges Niveau (was es mir ermöglicht, es als nicht aufgeblähte Grundlage für fortgeschritteneres Verhalten zu verwenden).
  • Es bietet Zugriff auf jeden Teil des DOM (im Gegensatz zu z. B. SimpleXml, bei dem einige der weniger bekannten XML-Funktionen ignoriert werden).
  • Es hat eine Syntax für das DOM-Crawlen, die der in nativem Javascript verwendeten Syntax ähnelt.

Und obwohl ich die Möglichkeit vermisse, CSS-Selektoren für zu verwenden DOMDocument, gibt es eine ziemlich einfache und bequeme Möglichkeit, diese Funktion hinzuzufügen: Unterklassen DOMDocumentund Hinzufügen von JS-ähnlichen Methoden querySelectorAllund querySelectorMethoden zu Ihrer Unterklasse.

Zum Parsen der Selektoren empfehle ich die Verwendung der sehr minimalistischen CssSelector-Komponente aus dem Symfony-Framework . Diese Komponente übersetzt nur CSS-Selektoren in XPath-Selektoren, die dann in a eingespeist werden könnenDOMXpath eingegeben werden können, um die entsprechende Knotenliste abzurufen.

Sie können diese (noch sehr niedrige) Unterklasse dann als Grundlage für höhere Klassen verwenden, die z. Analysieren Sie ganz bestimmte XML-Typen oder fügen Sie mehr jQuery-ähnliches Verhalten hinzu.

Der folgende Code stammt direkt aus meiner DOM-Query-Bibliothek und verwendet die von mir beschriebene Technik.

Für das HTML-Parsen:

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);
                }
            }
        }
    }

    [...]
}

Siehe auch Parsen von XML-Dokumenten mit CSS-Selektoren von Fabien Potencier, dem Erfinder von Symfony, zu seiner Entscheidung, die CssSelector-Komponente für Symfony zu erstellen, und zu deren Verwendung.


9

Mit FluidXML können Sie XML mit XPath- und CSS-Selektoren abfragen und iterieren .

$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


7

JSON und Array aus XML in drei Zeilen:

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

Ta da!


7

Es gibt mehrere Gründe, HTML nicht durch reguläre Ausdrücke zu analysieren. Wenn Sie jedoch die vollständige Kontrolle darüber haben, welcher HTML-Code generiert wird, können Sie einen einfachen regulären Ausdruck verwenden.

Oben ist es eine Funktion, die HTML nach regulären Ausdrücken analysiert. Beachten Sie, dass diese Funktion sehr sensibel ist und erfordert, dass der HTML-Code bestimmte Regeln einhält, aber in vielen Szenarien sehr gut funktioniert. Wenn Sie einen einfachen Parser möchten und keine Bibliotheken installieren möchten, probieren Sie Folgendes aus:

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/")));

2

Ich habe eine Bibliothek namens HTML5DOMDocument erstellt, die unter https://github.com/ivopetkov/html5-dom-document-php frei verfügbar ist

Es unterstützt auch Abfrageselektoren, von denen ich denke, dass sie in Ihrem Fall äußerst hilfreich sind. Hier ist ein Beispielcode:

$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;

0

Wenn Sie mit jQuery Selector vertraut sind, können Sie ScarletsQuery für PHP verwenden

<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);

Diese Bibliothek benötigt normalerweise weniger als 1 Sekunde, um Offline-HTML zu verarbeiten.
Es akzeptiert auch ungültiges HTML oder fehlende Anführungszeichen für Tag-Attribute.


0

Die beste Methode zum Parsen von 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;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.