2016-02-26 11 views
8

Sto tentando di analizzare la risposta HTML di una richiesta HTTP. Sto usando hyper per le richieste e html5ever per l'analisi. L'HTML sarà abbastanza grande e non ho bisogno di analizzarlo completamente - ho solo bisogno di identificare alcuni dati dai tag quindi preferirei trasmetterli in streaming. Concettualmente voglio fare qualcosa di simile:Analisi del contenuto di una pagina HTML in uno stream con hyper e html5ever

# bash 
curl url | read_dom 

/* javascript */ 
http.get(url).pipe(parser); 
parser.on("tag", /* check tag name, attributes, and act */) 

Quello che ho elaborato finora è:

extern crate hyper; 
extern crate html5ever; 

use std::default::Default 
use hyper::Client; 
use html5ever::parse_document; 
use html5ever::rcdom::{RcDom}; 

fn main() { 
    let client = Client::new(); 

    let res = client.post(WEBPAGE) 
     .header(ContentType::form_url_encoded()) 
     .body(BODY) 
     .send() 
     .unwrap(); 

    res.read_to_end(parse_document(RcDom::default(), 
     Default::default().from_utf8().unwrap())); 
} 

Sembra read_to_end è il metodo che voglio chiamare sulla risposta di leggere i byte , ma non è chiaro come inserirlo nel lettore di documenti HTML ... se è possibile.

The documentation for parse_document dice di utilizzare from_utf8 o from_bytes se l'ingresso è in byte (che è).

Sembra che ho bisogno di creare un sink dalla risposta, ma questo è dove sono bloccato. Non è chiaro per me come posso creare eventi per ascoltare l'inizio del tag, che è quello che mi interessa.

Ho guardato allo this example of html5ever che sembra fare quello che voglio e cammina sul DOM, ma non posso ottenere questo esempio per eseguire - o è obsoleto o tendril/html 5ever è troppo nuovo. Questo sembra anche analizzare l'HTML nel suo insieme piuttosto che come un flusso, ma non ne sono sicuro.

È possibile fare ciò che voglio fare con l'implementazione corrente di queste librerie?

risposta

7

Ci scusiamo per la mancanza di documentazione esercitazione simile per html5ever e viticcio ...

A meno che non si è sicuri al 100% il contenuto è in UTF-8, usare from_bytes piuttosto che from_utf8. Restituiscono qualcosa che implementa TendrilSink che consente di fornire l'input in modo incrementale (o meno).

Il metodo std::io::Read::read_to_end prende uno &mut Vec<u8>, quindi non funziona con TendrilSink.

Al livello più basso, è possibile chiamare il metodo TendrilSink::process una volta per chunk &[u8] e quindi chiamare TendrilSink::finish.

Per evitare di farlo manualmente, c'è anche il metodo TendrilSink::read_from che prende &mut R where R: std::io::Read. Dal momento che hyper::client::Response implementa Read, è possibile utilizzare:

parse_document(RcDom::default(), Default::default()).from_bytes().read_from(&mut res) 

Per andare oltre la vostra domanda, RcDom è molto minimale ed esiste principalmente per testare html5ever. Raccomando invece di usare Kuchiki. Ha più funzioni (per l'attraversamento di alberi, la corrispondenza del selettore CSS, ...) incluso il supporto opzionale di Hyper.

Nel vostro Cargo.toml:

[dependencies] 
kuchiki = {version = "0.3.1", features = ["hyper"]} 

Nel codice:

let document = kuchiki::parse_html().from_http(res).unwrap(); 
+0

Can mi colleghi più informat a proposito di Kuchiki piace come implementare l'attraversamento di alberi e in particolare come utilizzare eventi come "tag aperti" per ispezionare tag/contenuti di testo? Questo è quello che devo fare. –

+0

Sembra che la [documentazione] (https://simonsapin.github.io/kuchiki/kuchiki/struct.Node.html) sia bacata, ci sono altri metodi che non vengono visualizzati qui. Ad esempio, i nodi hanno metodi come '.descendants()' e '.inclusive_descendants()' che restituiscono iteratori di nodi. Non sono sicuro di cosa intendi con "tag aperto". Kuchiki non è basato sugli eventi, si ottiene una struttura dei dati dell'albero una volta che l'analisi è stata eseguita. –

+0

Grazie. Peccato se deve analizzare l'intero documento in una sola volta. Voglio qualcosa come [htmlparser2 per il nodo] (https://github.com/fb55/htmlparser2) dove posso reindirizzare un flusso di html al parser e rispondere a 'onstarttag', ecc. –

-3

tenta di aggiungere questo:

let mut result: Vec<u8> = Vec::new(); 

res.read_to_end(&mut result); 

let parse_result = parse_document(RcDom::default(), Default::default()) 
    . //read parameters 
    .unwrap(); 

parametri Accordint alla documentazione cassa ...

+0

Dove usi il 'risultato' con il parser? –

+0

Immagino che nel parametro come '.read_from (& mut result.lock())' come descritto nella documentazione che hai collegato ... –

Problemi correlati