2009-03-14 7 views
6

Stavo rispondendo ad alcune domande del quiz per un'intervista, e la domanda riguardava come avrei fatto lo screen scraping. Cioè, prelevare il contenuto da una pagina Web, partendo dal presupposto che non si dispone di un modo meglio strutturato per interrogare direttamente le informazioni (ad esempio un servizio Web).Raschia schermo: espressioni regolari o espressioni XQuery?

La mia soluzione era utilizzare un'espressione XQuery. L'espressione era abbastanza lunga perché il contenuto di cui avevo bisogno era abbastanza profondo nella gerarchia HTML. Ho dovuto cercare tra gli antenati in modo corretto prima di trovare un elemento con un attributo id. Ad esempio, raschiando una pagina di Amazon.com per Dimensioni del prodotto è simile al seguente:

//a[@id="productDetails"] 
/following-sibling::table 
//h2[contains(child::text(), "Product Details")] 
/following-sibling::div 
//li 
/b[contains(child::text(), "Product Dimensions:")] 
/following-sibling::text() 

Questa è un'espressione piuttosto brutta, ma è per questo che Amazon offre un API servizio web. Ad ogni modo, è solo un esempio. La domanda non riguardava Amazon, riguarda lo scraping dello schermo.

All'intervistatore non è piaciuta la mia soluzione. Ha pensato che fosse fragile, perché una modifica al design della pagina di Amazon potrebbe richiedere la riscrittura dell'espressione XQuery. Il debug di un'espressione XQuery che non corrisponde a nulla nella pagina a cui viene applicata è difficile.

io non sono d'accordo con le sue dichiarazioni, ma non pensavo che la sua soluzione era alcun miglioramento: ha pensato che è meglio usare un'espressione regolare , e la ricerca di contenuti e markup vicino al peso di spedizione. Ad esempio, utilizzando Perl:

$html =~ m{<li>\s*<b>\s*Product Dimensions:\s*</b>\s*(.*?)</li>}s; 

mio contro-argomentazione era che questo è anche suscettibile di Amazon cambiare il loro codice HTML. Potrebbero compitare i tag HTML in maiuscolo (<LI>) o aggiungere attributi CSS o modificare a <span> o modificare l'etichetta "Dimensioni prodotto:" in "Dimensioni:" o molti altri tipi di modifiche. Il mio punto era che le espressioni regolari non risolvono le debolezze che ha chiamato nella mia soluzione XQuery.

Inoltre, le espressioni regolari possono trovare falsi positivi, a meno che non si aggiunga un contesto sufficiente all'espressione. Può anche abbinare involontariamente il contenuto che si trova all'interno di un commento, o una stringa di attributo o una sezione CDATA.

La mia domanda è: quale tecnologia utilizzate per eseguire lo screen scraping? Perché hai scelto quella soluzione? C'è qualche motivo convincente per usarne uno? O non usare mai l'altro? C'è una terza scelta oltre a quelle che ho mostrato sopra?

PS: si supponga per il ragionamento che non vi sia alcuna API del servizio Web o altro modo più diretto per acquisire il contenuto desiderato.

risposta

3

Vorrei usare un'espressione regolare, per le ragioni che il manager ha dato, pochi (più portabile, più facile da seguire per i programmatori esterni, ecc.).

tuo argomento contatore non coglie il punto che la sua soluzione era fragile, per quanto riguarda i locali modifiche mentre il vostro è fragile per quanto riguarda globali modifiche. Qualunque cosa rompa la sua volontà probabilmente spezzerà la tua, ma non il contrario.

Infine, è molto più semplice creare slop/flex nella sua soluzione (se, ad esempio, si devono affrontare più variazioni minori nell'input).

4

Vorrei usare un'espressione regolare, ma solo perché la maggior parte delle pagine HTML non sono XML validi, quindi non faresti mai funzionare XQUERY.

Non conosco XQuery, ma mi sembra un'espressione XPATH. Se è così, sembra un po 'costoso con così tanti "//" operatori in esso.

+0

Questa è la ragione principale per evitare il web scraping basato su XML. Nessun processore XML è indulgente come un browser. La pagina deve solo rompere una regola di well-formedness per rendere XQuery completamente inutile. – harpo

1

In realtà trovo le espressioni di ricerca CSS più facili da leggere rispetto a entrambe. Probabilmente esiste almeno una libreria nella lingua di tua scelta che analizzerà una pagina e ti permetterà di scrivere direttive CSS per localizzare elementi particolari. Se c'è un gancio di classe o ID appropriato nelle vicinanze, l'espressione è piuttosto banale. Altrimenti, prendi gli elementi che sembrano appropriati e itera attraverso di essi per trovare quelli che ti servono.

Per quanto fragile, beh, sono tutti fragili. Lo screen-scraping è, per definizione, dipendente dall'autore di quella pagina che non modifica drasticamente il layout. Vai con una soluzione che è leggibile e può essere facilmente modificata in seguito.

1

Una soluzione non fragile per screen-scraping? Buona fortuna all'intervistatore per questo: solo perché le espressioni regolari buttano via un sacco di contesto non significa che siano meno fragili: solo che sono fragili in altri modi. La fragilità potrebbe anche non essere un inconveniente: se qualcosa cambia nella pagina Web di origine, si sta spesso meglio se la soluzione solleva un allarme, piuttosto che cercare di compensare in modo intelligente (e imprevedibile). Come hai notato. Queste cose dipendono sempre dalle tue ipotesi: in questo caso, su ciò che costituisce un probabile cambiamento.

Sono piuttosto affezionato allo HTML agility pack: si ottiene la tolleranza di pagine Web non XHTML combinate con la potenza espressiva di XPath.

2

Prova JTidy o BeautifulSoup funziona correttamente per me. certamente // L'experssione XPATH è piuttosto costosa da demolire.

1

Le espressioni regolari sono molto veloci e funzionano con documenti non XML. Questi sono davvero ottimi punti contro XQuery. Tuttavia penso che l'utilizzo di un certo convertitore di XHTML come XQuery ordinata e forse un po 'più semplice, come solo l'ultima parte dalla tua:

//b[contains(child::text(), "Product Dimensions:")]/following-sibling::text() 

è una buona alternativa.

saluti,

Rafal Rusin

1

a lavorare su pagine html, è meglio usare HtmlAgilityPack (e con alcuni codici LINQ). È un ottimo modo per analizzare tutti gli elementi e/o fare una ricerca diretta con XPath. A mio parere, è più preciso di RegEx e più facile da programmare. Ero un po 'riluttante a usarlo in precedenza, ma è molto facile da aggiungere al tuo progetto e penso sia lo standard de factor per lavorare con html. http://htmlagilitypack.codeplex.com/

Buona fortuna!

+0

Grazie, sì, HTML Agility Pack è stato suggerito in un'altra risposta da Pontus Gagge. Mi chiedo che cosa usi internamente l'HTML Agility Pack: XPath, espressioni regolari o qualche altra analisi DOM personalizzata o qualcos'altro. –

+1

Con HtmlAgilityPack, è possibile attraversare l'intero DOM tramite DocumentNode.ChildNodes. Ad esempio: per ogni voTag in voMyHTML.DocumentNode.ChildNodes oppure è possibile ingrandire in un unico nodo con voMyHTML.DocumentNode.SelectSingleNode (vsXPath) o si può anche usare LINQ: voElements = (Da voTag In voMyHTML.DocumentNode.ChildNodes Dove voTag.GetAttributeValue ("classe") = "myClass" Seleziona voTag) –