使用hyper和html5ever在流中解析HTML页面内容

Exp*_*lls 11 rust hyper html5ever

我正在尝试解析HTTP请求的HTML响应.我正在使用hyper来处理请求,使用html5ever进行解析.HTML将非常大,我不需要完全解析它 - 我只需要从标签中识别一些数据,所以我更愿意流式传输它.从概念上讲,我想做的事情如下:

# bash
curl url | read_dom

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

到目前为止我想出的是:

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()));
}
Run Code Online (Sandbox Code Playgroud)

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

说明parse_document要使用的文档,from_utf8或者from_bytes输入是否以字节为单位(即它).

看来我需要从响应中创建一个接收器,但这就是我被困住的地方.我也不清楚如何创建事件来监听标签启动,这是我感兴趣的.

我看过这个html5ever的例子似乎做了我想做的事情并且走了DOM,但是我不能让这个例子本身运行 - 要么它已经过时了,要么卷须/ html5ever太新了.这似乎也解析了整个HTML而不是流,但我不确定.

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

Sim*_*pin 8

很抱歉缺少html5ever和tendril的类似教程的文档...

除非您100%确定您的内容是UTF-8,否则请使用from_bytes而不是from_utf8.它们返回一些实现的东西,TendrilSink允许您以递增方式(或不提供)提供输入.

std::io::Read::read_to_end方法需要a &mut Vec<u8>,因此无法使用TendrilSink.

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

为避免手动执行此操作,还TendrilSink::read_from需要采用的方法&mut R where R: std::io::Read.自hyper::client::Response实现以来Read,您可以使用:

parse_document(RcDom::default(), Default::default()).from_bytes().read_from(&mut res)
Run Code Online (Sandbox Code Playgroud)

超越你的问题,RcDom是非常小的,并且大部分存在是为了测试html5ever.我推荐使用Kuchiki.它具有更多功能(用于树遍历,CSS选择器匹配,......),包括可选的Hyper支持.

在你的Cargo.toml:

[dependencies]
kuchiki = {version = "0.3.1", features = ["hyper"]}
Run Code Online (Sandbox Code Playgroud)

在你的代码中:

let document = kuchiki::parse_html().from_http(res).unwrap();
Run Code Online (Sandbox Code Playgroud)