Come analizzi ed elabori HTML / XML in PHP?


Risposte:


1897

Estensioni XML native

Preferisco usare una delle estensioni XML native poiché vengono fornite in bundle con PHP, di solito sono più veloci di tutte le librerie di terze parti e mi danno tutto il controllo di cui ho bisogno sul markup.

DOM

L'estensione DOM consente di operare su documenti XML tramite l'API DOM con PHP 5. È un'implementazione del Document Object Model Core Level 3 del W3C, un'interfaccia indipendente dalla piattaforma e dal linguaggio che consente a programmi e script di accedere e aggiornare dinamicamente il contenuto, la struttura e lo stile dei documenti.

DOM è in grado di analizzare e modificare HTML del mondo reale (non funzionante) e può eseguire query XPath . Si basa su libxml .

Ci vuole un po 'di tempo per diventare produttivi con DOM, ma quel tempo vale la pena IMO. Poiché DOM è un'interfaccia indipendente dalla lingua, troverai implementazioni in molte lingue, quindi se hai bisogno di cambiare il tuo linguaggio di programmazione, è probabile che tu sappia già come usare l'API DOM di quella lingua.

Un esempio di utilizzo di base può essere trovato in Afferrare l'attributo href di un elemento A e una panoramica concettuale generale è disponibile su DOMDocument in php

Come utilizzare l'estensione DOM è stato ampiamente trattato su StackOverflow , quindi se si sceglie di utilizzarlo, si può essere certi che la maggior parte dei problemi riscontrati possano essere risolti cercando / sfogliando Stack Overflow.

XMLReader

L'estensione XMLReader è un parser pull XML. Il lettore agisce come un cursore andando avanti nel flusso di documenti e fermandosi su ciascun nodo lungo la strada.

XMLReader, come DOM, si basa su libxml. Non sono a conoscenza di come attivare il modulo parser HTML, quindi è probabile che l'utilizzo di XMLReader per l'analisi del codice HTML non funzionante sia meno efficace rispetto all'utilizzo del DOM in cui è possibile dirgli esplicitamente di utilizzare il modulo parser HTML di libxml.

Un esempio di utilizzo di base si trova nell'ottenere tutti i valori dai tag h1 usando php

Parser XML

Questa estensione consente di creare parser XML e quindi definire gestori per diversi eventi XML. Ogni parser XML ha anche alcuni parametri che è possibile regolare.

La libreria XML Parser si basa anche su libxml e implementa un parser push XML in stile SAX . Potrebbe essere una scelta migliore per la gestione della memoria rispetto a DOM o SimpleXML, ma sarà più difficile da lavorare rispetto al pull parser implementato da XMLReader.

SimpleXML

L'estensione SimpleXML fornisce un set di strumenti molto semplice e facilmente utilizzabile per convertire XML in un oggetto che può essere elaborato con normali selettori di proprietà e iteratori di array.

SimpleXML è un'opzione quando sai che l'HTML è XHTML valido. Se hai bisogno di analizzare il codice HTML non funzionante, non prendere nemmeno in considerazione SimpleXml perché si strozzerà.

Un esempio di utilizzo di base è disponibile in Un semplice programma per il nodo CRUD e i valori dei nodi del file XML e ci sono molti altri esempi nel Manuale PHP .


Librerie di terze parti (basate su libxml)

Se preferisci usare una lib di terze parti, suggerirei di usare una lib che in realtà usa DOM / libxml al di sotto invece dell'analisi delle stringhe.

FluentDom - Repo

FluentDOM fornisce un'interfaccia XML fluida simile a jQuery per DOMDocument in PHP. I selettori sono scritti in XPath o CSS (usando un convertitore da CSS a XPath). Le versioni attuali estendono il DOM implementando interfacce standard e aggiungono funzionalità dal DOM Living Standard. FluentDOM può caricare formati come JSON, CSV, JsonML, RabbitFish e altri. Può essere installato tramite Composer.

HtmlPageDom

Wa72 \ HtmlPageDom` è una libreria PHP per una facile manipolazione di documenti HTML che utilizzano DomCrawler dai componenti di Symfony2 per attraversare l'albero DOM e lo estende aggiungendo metodi per manipolare l'albero DOM dei documenti HTML.

phpQuery (non aggiornato per anni)

phpQuery è un'API Document Object Model (DOM) basata sul selettore CSS3 lato server, concatenabile, basata sulla libreria JavaScript jQuery scritta in PHP5 e fornisce CLI (Command Line Interface) aggiuntiva.

Vedi anche: https://github.com/electrolinux/phpquery

Zend_Dom

Zend_Dom fornisce strumenti per lavorare con documenti e strutture DOM. Al momento, offriamo Zend_Dom_Query, che fornisce un'interfaccia unificata per l'interrogazione di documenti DOM utilizzando selettori XPath e CSS.

percorso query

QueryPath è una libreria PHP per manipolare XML e HTML. È progettato per funzionare non solo con file locali, ma anche con servizi Web e risorse di database. Implementa gran parte dell'interfaccia jQuery (inclusi i selettori in stile CSS), ma è fortemente ottimizzata per l'uso sul lato server. Può essere installato tramite Composer.

fDOMDocument

fDOMDocument estende il DOM standard per utilizzare le eccezioni in tutte le occasioni di errori anziché avvisi o avvisi PHP. Aggiungono inoltre vari metodi personalizzati e scorciatoie per comodità e per semplificare l'utilizzo di DOM.

saber / xml

sabre / xml è una libreria che avvolge ed estende le classi XMLReader e XMLWriter per creare un sistema di mappatura e un modello di progettazione semplici da "xml a object / array". Scrivere e leggere XML è single-pass e può quindi essere veloce e richiedere poca memoria su file XML di grandi dimensioni.

FluidXML

FluidXML è una libreria PHP per manipolare XML con un'API concisa e fluida. Sfrutta XPath e il modello di programmazione fluente per essere divertente ed efficace.


Di terze parti (non basato su libxml)

Il vantaggio di basarsi su DOM / libxml è che si ottengono buone prestazioni immediatamente perché si è basati su un'estensione nativa. Tuttavia, non tutte le librerie di terze parti seguono questa strada. Alcuni di essi elencati di seguito

PHP Parser DOM HTML semplice

  • Un parser DOM HTML scritto in PHP5 + ti consente di manipolare HTML in modo molto semplice!
  • Richiedi PHP 5+.
  • Supporta HTML non valido.
  • Trova i tag in una pagina HTML con selettori proprio come jQuery.
  • Estrai i contenuti dall'HTML in un'unica riga.

In genere non consiglio questo parser. La base di codice è orribile e lo stesso parser è piuttosto lento e la memoria ha fame. Non tutti i selettori jQuery (come i selettori figlio ) sono possibili. Qualsiasi libreria basata su libxml dovrebbe superare facilmente questo valore.

PHP Html Parser

PHPHtmlParser è un parser html semplice, flessibile che ti permette di selezionare i tag usando qualsiasi selettore css, come jQuery. L'obiettivo è quello di assistere allo sviluppo di strumenti che richiedono un modo rapido e semplice per eliminare l'html, che sia valido o no! Questo progetto è stato originale supportato da sunra / php-simple-html-dom-parser ma il supporto sembra essersi fermato, quindi questo progetto è il mio adattamento del suo lavoro precedente.

Ancora una volta, non consiglierei questo parser. È piuttosto lento con un elevato utilizzo della CPU. Non esiste inoltre alcuna funzione per cancellare la memoria degli oggetti DOM creati. Questi problemi si adattano in particolare ai loop nidificati. La documentazione stessa è inesatta e errata, senza risposte alle correzioni dal 14 aprile 16.

Ganon

  • Un tokenizer universale e parser DOM HTML / XML / RSS
    • Capacità di manipolare elementi e loro attributi
    • Supporta HTML e UTF8 non validi
  • Può eseguire query avanzate simili a CSS3 su elementi (come jQuery - spazi dei nomi supportati)
  • Un estetista HTML (come HTML Tidy)
    • Minimizza CSS e Javascript
    • Ordina gli attributi, cambia il carattere, il rientro corretto, ecc.
  • Estensibile
    • Analisi dei documenti utilizzando callback basati sul carattere / token corrente
    • Operazioni separate in funzioni più piccole per una facile sostituzione
  • Facile e veloce

Non l'ho mai usato. Non so dire se va bene.


HTML 5

Puoi utilizzare quanto sopra per analizzare HTML5, ma possono esserci delle stranezze a causa del markup che HTML5 consente. Quindi per HTML5 vuoi prendere in considerazione l'uso di un parser dedicato, come

html5lib

Implementazioni Python e PHP di un parser HTML basato sulla specifica HTML5 WHATWG per la massima compatibilità con i principali browser Web desktop.

Potremmo vedere più parser dedicati una volta finalizzato HTML5. C'è anche un post sul blog di W3 intitolato How-To per l'analisi HTML 5 che vale la pena dare un'occhiata.


Servizi web

Se non hai voglia di programmare PHP, puoi anche utilizzare i servizi Web. In generale, ho trovato pochissima utilità per questi, ma sono solo io e i miei casi d'uso.

ScraperWiki .

L'interfaccia esterna di ScraperWiki ti consente di estrarre i dati nella forma che desideri utilizzare sul Web o nelle tue applicazioni. Puoi anche estrarre informazioni sullo stato di qualsiasi raschietto.


Espressioni regolari

Ultimo e meno consigliato , è possibile estrarre dati da HTML con espressioni regolari . In generale l'uso delle espressioni regolari su HTML è scoraggiato.

La maggior parte dei frammenti che troverai sul Web per abbinare il markup sono fragili. Nella maggior parte dei casi funzionano solo per un pezzo HTML molto particolare. Piccole modifiche al markup, come l'aggiunta di spazi bianchi da qualche parte, o l'aggiunta o la modifica di attributi in un tag, possono far fallire RegEx quando non è scritto correttamente. Dovresti sapere cosa stai facendo prima di utilizzare RegEx su HTML.

I parser HTML conoscono già le regole sintattiche dell'HTML. Le espressioni regolari devono essere insegnate per ogni nuovo RegEx che scrivi. RegEx va bene in alcuni casi, ma dipende davvero dal tuo caso d'uso.

È possibile scrivere parser più affidabili , ma scrivere un parser personalizzato completo e affidabile con espressioni regolari è una perdita di tempo quando le librerie di cui sopra esistono già e fanno un lavoro molto migliore su questo.

Vedi anche Parsing Html The Cthulhu Way


Libri

Se vuoi spendere dei soldi, dai un'occhiata

Non sono affiliato con PHP Architect o gli autori.


10
@Naveed dipende dalle tue esigenze. Non ho bisogno di query CSS Selector, motivo per cui utilizzo esclusivamente DOM con XPath. phpQuery mira ad essere una porta jQuery. Zend_Dom è leggero. Devi davvero controllarli per vedere quale ti piace di più.
Gordon,

2
@ Ms2ger Principalmente, ma non completamente. Come già accennato in precedenza, è possibile utilizzare i parser basati su libxml ma ci sono casi speciali in cui questi si strozzeranno. Se hai bisogno della massima compatibilità, stai meglio con un parser dedicato. Preferisco mantenere la distinzione.
Gordon,

9
Il tuo punto di non usare PHP Simple HTML DOM Parser sembra controverso.
Petah,

3
A partire dal 29 marzo 2012, DOM non supporta html5, XMLReader non supporta HTML e l'ultimo commit su html5lib per PHP è stato effettuato a settembre 2009. Cosa utilizzare per analizzare HTML5, HTML4 e XHTML?
Shiplu Mokaddim,

4
@Nasha Ho deliberatamente escluso il famigerato rant Zalgo dall'elenco sopra perché non è troppo utile da solo e porta a un certo culto del carico da quando è stato scritto. Le persone furono schiaffeggiate con quel legame, non importa quanto appropriata sarebbe stata una regex come soluzione. Per un'opinione più equilibrata, consulta invece il link che ho incluso e consulta i commenti su stackoverflow.com/questions/4245008/…
Gordon,

322

Prova il parser DOM HTML semplice

  • Un parser DOM HTML scritto in PHP 5+ che ti consente di manipolare HTML in modo molto semplice!
  • Richiedi PHP 5+.
  • Supporta HTML non valido.
  • Trova i tag in una pagina HTML con selettori proprio come jQuery.
  • Estrai i contenuti dall'HTML in un'unica riga.
  • Scarica


Esempi:

Come ottenere elementi 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>';


Come modificare gli elementi 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;


Estrai contenuto da HTML:

// 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
Bene, in primo luogo ci sono cose che devo preparare come DOM difettosi, codice Invlid, anche analisi js contro motore DNSBL, questo sarà anche usato per cercare siti / contenuti dannosi, anche quando ho costruito il mio sito attorno a un framework i hanno costruito deve essere pulito, leggibile e ben strutturato. SimpleDim è eccezionale ma il codice è leggermente disordinato
RobertPitt,

9
@Robert potresti anche voler controllare htmlpurifier.org per le cose relative alla sicurezza.
Gordon,

3
Ha un punto valido: simpleHTMLDOM è difficile da estendere, a meno che tu non usi un motivo decorativo, che trovo ingombrante. Mi sono trovato rabbrividendo solo apportando modifiche alle classi sottostanti stesse.
Erik,

1
Quello che ho fatto è stato eseguire il mio HTML attraverso l'ordine prima di inviarlo a SimpleDOM.
MB34,

1
Attualmente sto usando questo, eseguendolo come parte di un progetto per elaborare alcune centinaia di URL. Sta diventando molto lento e persistono dei timeout regolari. È un ottimo script per principianti e intuitivamente semplice da imparare, ma troppo semplice per progetti più avanzati.
luke_mclachlan

236

Basta usare DOMDocument-> loadHTML () e finirlo . L'algoritmo di analisi HTML di libxml è abbastanza buono e veloce, e contrariamente alla credenza popolare, non soffoca sull'HTML malformato.


19
Vero. E funziona con le classi di processori XPath e XSLTP incorporate di PHP, perfette per l'estrazione di contenuti.
Kornel,

8
Per un HTML veramente distorto, puoi sempre eseguirlo tramite htmltidy prima di passare a DOM. Ogni volta che devo estrarre i dati dall'HTML, utilizzo sempre DOM, o almeno simplexml.
Frank Farmer,

9
Un'altra cosa con il caricamento di HTML i non valido è che potrebbe essere saggio chiamare libxml_use_internal_errors (true) per evitare avvisi che smetteranno di analizzare.
Husky,

6
Ho usato DOMDocument per analizzare circa 1000 fonti HTML (in varie lingue codificate con diversi set di caratteri) senza problemi. Potresti incorrere in problemi di codifica con questo, ma non sono insormontabili. Devi sapere 3 cose: 1) loadHTML usa il set di caratteri del meta tag per determinare la codifica 2) # 2 può portare a un rilevamento errato della codifica se il contenuto html non include queste informazioni 3) caratteri UTF-8 errati possono far scattare il parser. In tali casi, utilizzare una combinazione di mb_detect_encoding () e Simplepie RSS Parser per codificare / convertire / rimuovere il codice caratteri UTF-8 errato per soluzioni alternative.
Zero,

1
DOM supporta effettivamente XPath, dai un'occhiata a DOMXPath .
Ryan McCue,

147

Perché non dovresti e quando dovresti usare le espressioni regolari?

Prima di tutto, un nome improprio comune: Regexps non serve per " analizzare " l' HTML. Regexes può tuttavia " estrarre " i dati. L'estrazione è ciò per cui sono fatti. Il principale svantaggio dell'estrazione di regex HTML su corretti toolkit SGML o parser XML di base è il loro sforzo sintattico e la loro affidabilità variabile.

Considera che creare una regex di estrazione HTML in qualche modo affidabile:

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

è molto meno leggibile di un semplice phpQuery o equivalente di QueryPath:

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

Vi sono tuttavia casi d'uso specifici in cui possono aiutare.

  • Molti frontend traversal DOM non rivelano commenti HTML <!--, che tuttavia a volte sono gli ancoraggi più utili per l'estrazione. In particolare, le variazioni pseudo-HTML <$var>o i residui SGML sono facili da domare con regexps.
  • Spesso le espressioni regolari possono salvare la post-elaborazione. Tuttavia, le entità HTML spesso richiedono la custodia manuale.
  • E infine, per compiti estremamente semplici come l'estrazione di <img src = urls, sono in realtà uno strumento probabile. Il vantaggio della velocità rispetto ai parser SGML / XML viene per lo più solo per queste procedure di estrazione di base.

A volte è anche consigliabile pre-estrarre uno snippet di HTML usando espressioni regolari /<!--CONTENT-->(.+?)<!--END-->/ed elaborare il resto usando i frontend del parser HTML più semplici.

Nota: in realtà ho questa app , in cui utilizzo alternativamente analisi XML ed espressioni regolari. Proprio la scorsa settimana il parsing di PyQuery si è rotto e il regex ha funzionato ancora. Sì strano, e non posso spiegarlo da solo. Ma così è successo.
Quindi per favore non votare verso il basso le considerazioni del mondo reale, solo perché non corrisponde al meme regex = evil. Ma non votiamo troppo. È solo un sidenote per questo argomento.


20
DOMCommentpuò leggere commenti, quindi nessun motivo per usare Regex per questo.
Gordon,

4
Né i toolkit SGML né i parser XML sono adatti per l'analisi dell'HTML del mondo reale. Per questo, è appropriato solo un parser HTML dedicato.
Alohci,

12
@Alohci DOMusi libxml e libxml ha un parser HTML separato modulo che sarà utilizzato durante il caricamento HTML con loadHTML()in modo che possa molto carico "del mondo reale" (leggi rotto) HTML.
Gordon,

6
Bene, solo un commento sul tuo punto di vista "considerazione del mondo reale". Certo, ci sono situazioni utili per Regex durante l'analisi dell'HTML. E ci sono anche situazioni utili per l'uso di GOTO. E ci sono situazioni utili per variabili variabili. Quindi nessuna implementazione particolare è definitivamente cod-rot per usarlo. Ma è un segnale di avvertimento MOLTO forte. E lo sviluppatore medio non è probabilmente abbastanza sfumato per dire la differenza. Quindi, come regola generale, Regex GOTO e Variable-Variables sono tutti cattivi. Ci sono usi non malvagi, ma queste sono le eccezioni (e rare in questo) ... (IMHO)
ircmaxell,

11
@mario: In realtà, l'HTML può essere analizzato 'correttamente' usando regex, anche se di solito ci vogliono molti di loro per fare un buon lavoro. È solo un dolore reale nel caso generale. In casi specifici con input ben definiti, è quasi banale. Questi sono i casi in cui le persone dovrebbero usare le regex. I vecchi grandi parser affamati pesanti sono davvero ciò di cui hai bisogno per i casi generali, anche se non è sempre chiaro all'utente casuale dove tracciare quella linea. Qualunque codice sia più semplice e più facile, vince.
tchrist,

131

phpQuery e QueryPath sono estremamente simili nel replicare l'API jQuery fluente. Questo è anche il motivo per cui sono due degli approcci più semplici per analizzare correttamente HTML in PHP.

Esempi per QueryPath

Fondamentalmente devi prima creare un albero DOM interrogabile da una stringa HTML:

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

L'oggetto risultante contiene una rappresentazione ad albero completa del documento HTML. Può essere attraversato usando i metodi DOM. Ma l'approccio comune è usare selettori CSS come in jQuery:

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

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

Principalmente si desidera utilizzare selettori semplici #ide .classo DIVtag per ->find(). Ma puoi anche usare le istruzioni XPath , che a volte sono più veloci. Anche i tipici metodi jQuery come ->children()e ->text()soprattutto ->attr()semplificano l'estrazione dei giusti frammenti HTML. (E hanno già decodificato le loro entità SGML.)

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

QueryPath consente inoltre di iniettare nuovi tag nello stream ( ->append), quindi di generare e preimpostare un documento aggiornato ( ->writeHTML). Non solo può analizzare HTML non valido, ma anche vari dialetti XML (con spazi dei nomi) e persino estrarre dati da microformati HTML (XFN, vCard).

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

.

phpQuery o QueryPath?

Generalmente QueryPath è più adatto alla manipolazione di documenti. Mentre phpQuery implementa anche alcuni metodi pseudo AJAX (solo richieste HTTP) per assomigliare più da vicino a jQuery. Si dice che phpQuery sia spesso più veloce di QueryPath (a causa di un minor numero di funzionalità complessive).

Per ulteriori informazioni sulle differenze, consultare questo confronto sulla macchina di ritorno da tagbyte.org . (La fonte originale è scomparsa, quindi ecco un link all'archivio Internet. Sì, è ancora possibile individuare pagine mancanti, persone.)

Ed ecco un'introduzione completa a QueryPath .

vantaggi

  • Semplicità e affidabilità
  • Alternative semplici da usare ->find("a img, a object, div a")
  • Corretta eliminazione dei dati (rispetto al grepping di espressioni regolari)

88

Simple HTML DOM è un ottimo parser open-source:

simplehtmldom.sourceforge

Tratta gli elementi DOM in modo orientato agli oggetti e la nuova iterazione ha molta copertura per il codice non conforme. Ci sono anche alcune fantastiche funzioni come quelle che vedresti in JavaScript, come la funzione "trova", che restituirà tutte le istanze di elementi con quel nome di tag.

Ho usato questo in una serie di strumenti, testandolo su molti diversi tipi di pagine Web e penso che funzioni alla grande.


61

Un approccio generale che non ho visto menzionato qui è quello di eseguire HTML attraverso Tidy , che può essere impostato per sputare XHTML valido garantito. Quindi è possibile utilizzare qualsiasi vecchia libreria XML su di essa.

Ma per il tuo problema specifico, dovresti dare un'occhiata a questo progetto: http://fivefilters.org/content-only/ - è una versione modificata dell'algoritmo di leggibilità , che è progettata per estrarre solo il contenuto testuale (non le intestazioni e piè di pagina) da una pagina.


56

Per 1a e 2: voterei per la nuova classe del componente Symfony DOMCrawler ( DomCrawler ). Questa classe consente query simili ai selettori CSS. Dai un'occhiata a questa presentazione per esempi reali: news-of-the-symfony2-world .

Il componente è progettato per funzionare autonomamente e può essere utilizzato senza Symfony.

L'unico inconveniente è che funzionerà solo con PHP 5.3 o versioni successive.


Le query CSS jquery-like sono ben dette, perché ci sono alcune cose che mancano nella documentazione di w3c, ma sono presenti come funzionalità extra in jquery.
Nikola Petkanski,

53

Questo è comunemente indicato come raschiatura dello schermo , tra l'altro. La libreria che ho usato per questo è Simple HTML Dom Parser .


8
Non strettamente vero ( en.wikipedia.org/wiki/Screen_scraping#Screen_scraping ). L'indizio è in "schermo"; nel caso descritto, non è coinvolto alcuno schermo. Anche se, certo, il termine ha subito moltissimi abusi recenti.
Bobby Jack,

4
Non sto raschiando lo schermo, il contenuto che verrà analizzato sarà autorizzato dal fornitore del contenuto in base al mio accordo.
RobertPitt,

41

Abbiamo già creato alcuni crawler per le nostre esigenze. Alla fine della giornata, sono le semplici espressioni regolari a fare la cosa migliore. Mentre le librerie elencate sopra sono buone per il motivo per cui sono state create, se sai cosa stai cercando, le espressioni regolari sono un modo più sicuro di procedere, poiché puoi gestire anche strutture HTML / XHTML non valide , che fallirebbero se caricate tramite la maggior parte dei parser.



36

Sembra una buona descrizione dell'attività della tecnologia XPath W3C . È facile esprimere query come "restituisce tutti gli hrefattributi nei imgtag nidificati <foo><bar><baz> elements". Non essendo un appassionato di PHP, non posso dirti in quale forma XPath potrebbe essere disponibile. Se è possibile chiamare un programma esterno per elaborare il file HTML, è possibile utilizzare una versione della riga di comando di XPath. Per una rapida introduzione, consultare http://en.wikipedia.org/wiki/XPath .


29

Alternative di terze parti a SimpleHtmlDom che utilizzano DOM anziché String Parsing: phpQuery , Zend_Dom , QueryPath e FluentDom .


3
Se copi già i miei commenti, almeno collegali correttamente;) Dovrebbero essere: Alternative suggerite di terze parti a SimpleHtmlDom che effettivamente utilizzano DOM invece di String Parsing: phpQuery , Zend_Dom , QueryPath e FluentDom .
Gordon,

1
Le buone risposte sono un'ottima fonte. stackoverflow.com/questions/3606792/...
danidacar

24

Sì, puoi utilizzare simple_html_dom allo scopo. Tuttavia ho lavorato parecchio con simple_html_dom, in particolare per la demolizione del web e l'ho trovato troppo vulnerabile. Fa il lavoro di base ma non lo consiglio comunque.

Non ho mai usato il ricciolo per lo scopo, ma quello che ho imparato è che il ricciolo può fare il lavoro in modo molto più efficiente ed è molto più solido.

Si prega di dare un'occhiata a questo link: scraping-website-with-curl


2
curl può ottenere il file, ma non analizzerà HTML per te. Questa è la parte difficile.
cHao,

23

QueryPath è buono, ma fai attenzione allo "stato di tracciamento" perché se non ti rendi conto di cosa significhi, può significare che perdi molto tempo nel debug cercando di scoprire cosa è successo e perché il codice non funziona.

Ciò significa che ogni chiamata sul set di risultati modifica il set di risultati nell'oggetto, non è concatenabile come in jquery in cui ogni collegamento è un nuovo set, hai un singolo set che è i risultati della tua query e ogni chiamata di funzione modifica quel singolo set.

al fine di ottenere un comportamento simile a jquery, è necessario ramificarsi prima di eseguire un'operazione di filtro / modifica simile, ciò significa che rispecchierà molto più da vicino ciò che accade in jquery.

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

$resultsora contiene il set di risultati per input[name='forename']NON la query originale "div p"che mi ha fatto innescare molto, quello che ho scoperto è che QueryPath tiene traccia dei filtri e trova e tutto ciò che modifica i risultati e li memorizza nell'oggetto. devi invece farlo

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

quindi $resultsnon verrà modificato e puoi riutilizzare il set di risultati ancora e ancora, forse qualcuno con molta più conoscenza può chiarire un po 'questo, ma fondamentalmente è così da quello che ho trovato.


20

Advanced Html Dom è una semplice sostituzione DOM HTML che offre la stessa interfaccia, ma è basata su DOM, il che significa che non si verificano problemi di memoria associati.

Ha anche il pieno supporto CSS, comprese le estensioni jQuery .


Ho ottenuto buoni risultati da Advanced Html Dom e penso che dovrebbe essere nell'elenco nella risposta accettata. Una cosa importante da sapere però per chiunque si affidi al suo "L'obiettivo di questo progetto è quello di essere un sostituto drop-in basato su DOM per la semplice libreria dom html di PHP ... Se usi file / str_get_html non hai bisogno di cambia qualcosa ". archive.is/QtSuj#selection-933.34-933.100 è che potrebbe essere necessario apportare modifiche al codice per compensare alcune incompatibilità. Ho notato quattro noti a me nei problemi github del progetto. github.com/monkeysuffrage/advanced_html_dom/issues
ChrisJJ

Lavorato ! Grazie
Faisal Shani il

18

Per HTML5 , la libreria html5 è stata abbandonata da anni. L'unica libreria HTML5 che posso trovare con un recente aggiornamento e record di manutenzione è html5-php che è stato appena portato in beta 1.0 poco più di una settimana fa.


17

Ho scritto un parser XML generico che può facilmente gestire file GB. È basato su XMLReader ed è molto facile da usare:

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

Ecco il repository github: XmlExtractor


17

Ho creato una libreria chiamata PHPPowertools / DOM-Query , che ti permette di scansionare documenti HTML5 e XML proprio come fai con jQuery.

Sotto il cofano, utilizza symfony / DomCrawler per la conversione dei selettori CSS in selettori XPath . Utilizza sempre lo stesso DomDocument, anche quando passa un oggetto a un altro, per garantire prestazioni decenti.


Esempio di utilizzo:

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

[...]

Metodi supportati:


  1. Rinominato 'select', per ovvi motivi
  2. Rinominato "vuoto", poiché "vuoto" è una parola riservata in PHP

NOTA :

La libreria include anche un proprio caricatore automatico a configurazione zero per librerie compatibili con PSR-0. L'esempio incluso dovrebbe funzionare immediatamente senza alcuna configurazione aggiuntiva. In alternativa, puoi usarlo con il compositore.


Sembra lo strumento giusto per il lavoro ma non si sta caricando per me in PHP 5.6.23 in Worpress. Eventuali indicazioni aggiuntive su come includerlo correttamente ?. Incluso con: define ("BASE_PATH", dirname ( FILE )); define ("LIBRARY_PATH", BASE_PATH. DIRECTORY_SEPARATOR. 'lib / vendor'); richiede LIBRARY_PATH. DIRECTORY_SEPARATOR. 'Loader.php'; Loader :: init (array (LIBRARY_PATH, USER_PATH)); in
Functions.php

15

Potresti provare a usare qualcosa come HTML Tidy per ripulire qualsiasi HTML "rotto" e convertire l'HTML in XHTML, che puoi quindi analizzare con un parser XML.


15

Un'altra opzione che puoi provare è QueryPath . È ispirato a jQuery, ma sul server in PHP e utilizzato in Drupal .


12

XML_HTMLSaxè piuttosto stabile, anche se non è più mantenuto. Un'altra opzione potrebbe essere quella di reindirizzare l'HTML tramite Html Tidy e quindi analizzarlo con strumenti XML standard.


11

Il framework Symfony ha bundle che possono analizzare l'HTML e puoi usare lo stile CSS per selezionare i DOM invece di usare XPath .


11

Esistono molti modi per elaborare DOM HTML / XML di cui la maggior parte è già stata menzionata. Quindi, non tenterò di elencarli da solo.

Voglio semplicemente aggiungere che personalmente preferisco usare l'estensione DOM e perché:

  • iit fa un uso ottimale del vantaggio prestazionale del codice C sottostante
  • è OO PHP (e mi permette di sottoclassarlo)
  • è piuttosto basso livello (che mi permette di usarlo come base non gonfia per un comportamento più avanzato)
  • fornisce l'accesso a ogni parte del DOM (a differenza, ad esempio, di SimpleXml, che ignora alcune delle funzionalità XML meno conosciute)
  • ha una sintassi utilizzata per il crawling DOM simile alla sintassi utilizzata nel Javascript nativo.

E mentre mi manca la possibilità di utilizzare i selettori CSS per DOMDocument, esiste un modo piuttosto semplice e conveniente per aggiungere questa funzione: sottoclasse DOMDocumente aggiunta di JS querySelectorAlle querySelectormetodi alla sottoclasse.

Per l'analisi dei selettori, consiglio di usare il componente CssSelector molto minimalista dal framework Symfony . Questo componente traduce semplicemente i selettori CSS in selettori XPath, che possono quindi essere inseriti in a DOMXpathper recuperare la lista dei nomi corrispondente.

È quindi possibile utilizzare questa sottoclasse (di livello ancora molto basso) come base per classi di livello superiore, destinate ad es. analizzare tipi di XML molto specifici o aggiungere un comportamento più simile a jQuery.

Il codice qui sotto esce direttamente dalla mia libreria DOM-Query e usa la tecnica che ho descritto.

Per l'analisi 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);
                }
            }
        }
    }

    [...]
}

Vedi anche Analisi di documenti XML con selettori CSS da parte del creatore di Symfony Fabien Potencier sulla sua decisione di creare il componente CssSelector per Symfony e su come usarlo.


9

Con FluidXML è possibile eseguire query e iterare XML utilizzando i selettori XPath e 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


7

JSON e array da XML in tre righe:

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

Ta da!


7

Esistono diversi motivi per non analizzare HTML mediante l'espressione regolare. Ma se hai il controllo totale su ciò che verrà generato HTML, puoi farlo con una semplice espressione regolare.

Sopra è una funzione che analizza HTML mediante espressione regolare. Nota che questa funzione è molto sensibile e richiede che l'HTML rispetti determinate regole, ma funziona molto bene in molti scenari. Se vuoi un parser semplice e non vuoi installare librerie, prova questo:

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

Ho creato una libreria chiamata HTML5DOMDocument che è disponibile gratuitamente su https://github.com/ivopetkov/html5-dom-document-php

Supporta anche i selettori di query che ritengo estremamente utili nel tuo caso. Ecco un esempio di codice:

$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

Se hai familiarità con il selettore jQuery, puoi utilizzare ScarletsQuery per PHP

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

Questa libreria richiede in genere meno di 1 secondo per elaborare l'html offline.
Accetta anche HTML non valido o citazione mancante sugli attributi dei tag.


0

Il metodo migliore per analizzare 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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.