web-scraping - 如何使用html5ever解析页面并找到所有链接?

标签 web-scraping rust html5ever

我想用html5ever解析字符串格式的HTML,并找到此HTML中的所有链接。我知道How do I parse a page with html5ever, modify the DOM, and serialize it?,但是RcDom不再存在。

最佳答案

您必须创建一个实现TokenSink的结构,然后创建一个新的Tokenizer,其中您的结构是sink。使用Tokenizer::feed()解析时,它将通过TokenSink传递所有 token 。

该代码改编自html5ever examples,因此它是Apache/MIT许可的。 html5ever是为浏览器构建的复杂库,它显示-API似乎旨在容纳UTF-8以外的编码。

此代码仅从stdin解析。如果您想按原样使用它,请像curl一样传递curl https://stackoverflow.com/questions/59461279/how-do-i-parse-a-page-with-html5ever-and-find-all-the-links | cargo run
当我这样做时,我得到的输出像

link to: #
link to: https://stackoverflow.com
link to: #
link to: /teams/customers
...

extern crate html5ever;

use std::default::Default;
use std::io;

use html5ever::tendril::*;
use html5ever::tokenizer::BufferQueue;
use html5ever::tokenizer::{StartTag, TagToken};
use html5ever::tokenizer::{Token, TokenSink, TokenSinkResult, Tokenizer, TokenizerOpts,};
use html5ever::interface::QualName;
use html5ever::{ns, namespace_url, LocalName};

#[derive(Copy, Clone)]
struct TokenPrinter {}

impl TokenSink for TokenPrinter {
    type Handle = ();

    fn process_token(&mut self, token: Token, _line_number: u64) -> TokenSinkResult<()> {
        let link_name = QualName::new(
            None,
            ns!(),
            LocalName::from("href"),
        );
        match token {
            TagToken(tag) => {
                if tag.kind == StartTag && tag.name.to_string()=="a" {
                    let attrs = tag.attrs;
                    for attr in attrs {
                        if attr.name == link_name {
                            println!("link to: {}", attr.value);
                        }
                    }
                }
            },
            _ => {
            },
        }
        TokenSinkResult::Continue
    }
}

fn main() {
    let sink = TokenPrinter {};
    let mut chunk = ByteTendril::new();
    io::stdin().read_to_tendril(&mut chunk).unwrap();
    let mut input = BufferQueue::new();
    input.push_back(chunk.try_reinterpret::<fmt::UTF8>().unwrap());

    let mut tok = Tokenizer::new(
        sink,
        TokenizerOpts::default(),
    );
    let _ = tok.feed(&mut input);
    assert!(input.is_empty());
    tok.end();
}

关于web-scraping - 如何使用html5ever解析页面并找到所有链接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59461279/

相关文章:

generics - 是否可以在特征上使用通用函数?

rust - 如何将 Tendril<UTF8> 转换为 &str 或字符串?

html - 如何使用 Kuchiki 获取 HTML 文档的所有文本(除了 script/style/noscript 标签)?

python - 加速 BeautifulSoup

rust - 由于生命周期/借用错误,文本文件解析函数无法编译

rust - 如何明确说明关联类型应该是什么?

java - 将多个网页的抓取数据合并到单个页面中

javascript - 如何使用 cheerio 从网页中的换行符中抓取内容

python-3.x - 为什么我无法抓取此 HTML 的 'data-src' 属性内的所有内容