结合使用 Rust 库 reqwest 和 select

Using Rust libraries reqwest and select in conjunction

我正在尝试按照此处的示例进行操作: https://rust-lang-nursery.github.io/rust-cookbook/web/scraping.html,它利用 Reqwest 和 Select 来获得 html 响应,然后解析数据。

我使用的是 Reqwest 版本 0.10.4 和 Select 版本 0.4.3,这是示例中显示的版本。但是,我收到一个错误:

error[E0277]: the trait bound `reqwest::Response: std::io::Read` is not satisfied
  --> src/main.rs:19:25
   |
19 |     Document::from_read(res)?
   |                         ^^^ the trait `std::io::Read` is not implemented for `reqwest::Response`
   | 
  ::: /root/.cargo/registry/src/github.com-1ecc6299db9ec823/select-0.4.3/src/document.rs:31:25
   |
31 |     pub fn from_read<R: io::Read>(mut readable: R) -> io::Result<Document> {
   |                         -------- required by this bound in `select::document::Document::from_read`

似乎 from_read 方法接受读取类型,但 reqwest::get 方法 returns 接受不同类型。在将响应传递给 from_read 方法之前,是否必须先进行某种类型的转换?

这是例子:

#[macro_use]
extern crate error_chain;
extern crate reqwest;
extern crate select;

use select::document::Document;
use select::predicate::Name;

error_chain! {
   foreign_links {
       ReqError(reqwest::Error);
       IoError(std::io::Error);
   }
}

fn main() -> Result<()> {
    let res = reqwest::get("https://www.rust-lang.org/en-US/").await?;

    Document::from_read(res)?
        .find(Name("a"))
        .filter_map(|n| n.attr("href"))
        .for_each(|x| println!("{}", x));

    Ok(())
}

reqwest::get returns 一个 Result<Response>,然后用 ? 展开 Result,这意味着你现在有一个 Response记录的对象 here。并且由于 Web 调用可以成功发生但仍然失败(请参阅 HTTP 非 200 代码),您 应该 检查响应代码,但由于这是为了学习,我们将忽略它。你想要的是一个实现 std::io::Read 特征的结构,阅读它表明 String 实现了那个特征。回到reqwest::Response表明我们可以使用方法text()获取返回的字符串。所以你的代码现在变成

let res = reqwest::get("https://www.rust-lang.org/en-US/")
              .await?
              .text()
              .await?;

评论更新:现在的问题是Document::from_read只接受std::io::Read作为参数,而std::string::String没有实现trait,而不是使用像 stringreader 这样的板条箱,我们可以简单地使用 Document::from 作为文档实现 From<&'a str> trait.

而且,与几乎所有事情一样,有多种方法可以解决这个问题。你可以

  1. 直接使用Document::from(res)

  2. 从字符串创建文档
  3. 将字符串转换为字节切片,实现读取,并使用Document::from_read(res.as_bytes())

  4. 从中创建文档