2016-02-26 94 views
8

我试图解析HTTP请求的HTML响应。我使用hyper作为解析请求,使用html5ever作为解析。 HTML将会非常大,我不需要完全解析它 - 我只需要识别来自标记的一些数据,所以我宁愿将它流化。从概念上讲我想要做的事,如:用hyper和html5ever解析HTML页面内容

# bash 
curl url | read_dom 

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

我想出到目前为止是:

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

好像read_to_end是我想在响应调用读取的字节数的方法,但是我不清楚如何将它传递给HTML文档阅读器......如果这是可能的话。

The documentation for parse_document说使用from_utf8from_bytes如果输入是字节(它是)。

看来我需要从响应中创建一个接收器,但这是我卡住的地方。我也不清楚如何创建活动来听取我感兴趣的标签开始。

我看过this example of html5ever这似乎是做我想要的东西,并走过DOM,但我不能让这个例子本身运行 - 无论是过时还是卷发/ html5ever都太新了。这似乎也将HTML整体解析为一个流,但我不确定。

是否有可能做我想对目前这些库的实现做什么?

回答

7

对不起,缺乏html5ever和卷须教程类的文档......

除非你是100%肯定你的内容是UTF-8,使用from_bytes而非from_utf8。他们返回实现TendrilSink的东西,它允许您递增(或不)输入。

std::io::Read::read_to_end方法需要&mut Vec<u8>,所以它不适用于TendrilSink

在最低级别,可以按&[u8]块调用TendrilSink::process方法一次,然后调用TendrilSink::finish

为了避免手动执行此操作,还有需要&mut R where R: std::io::ReadTendrilSink::read_from方法。由于hyper::client::Response实现Read,你可以使用:

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

要超越你的问题,RcDom是很小的,为了测试html5ever大多存在。我建议使用Kuchiki。它具有更多特性(用于树遍历,CSS选择器匹配...),包括可选的Hyper支持。

在你Cargo.toml

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

在您的代码:

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

灿你链接我更多的信息关于Kuchiki如何实现遍历树,特别是如何使用诸如“开放标记”事件来检查标记/文本内容?这是我需要做的。 –

+0

它看起来像[文档](https://simonsapin.github.io/kuchiki/kuchiki/struct.Node.html)是越野车,有更多的方法,没有出现在那里。例如,节点有类似'.descendants()'和'.inclusive_descendants()'的方法来返回节点的迭代器。我不确定你的意思是“开放标签”。 Kuchiki不是基于事件的,一旦解析完成,你会得到一个树数据结构。 –

+0

谢谢。太糟糕了,如果它必须一次解析整个文档。我想要[htmlparser2 for node](https://github.com/fb55/htmlparser2),在这里我可以将一个html流传递给解析器并响应'onstarttag'等。 –

-3

尝试添加此:

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

参数accordint到箱子的文件...

+0

你在哪里使用解析器的结果? –

+0

我猜像像'.read_from(&mut result.lock())'这样的paramiter,就像你链接的文档中所描述的那样... –