Как получить внутренний текст элементов с помощью ящика-скребка? - PullRequest
0 голосов
/ 04 августа 2020

Я использую библиотеку scraper для анализа документа HTML и нахожу узел с ID foo.

Я хотел бы использовать этот узел для дальнейших операций. В этом примере я пытаюсь связаться с некоторыми вложенными дочерними элементами с классом inner и получить innerText этих дочерних элементов.

use scraper::{Html, Selector};

fn main() {
    let html = String::from(
        r#"
      <html>
        <head>
          <title>Test</title>
        </head>
        <body>
          <div id="foo"><div></div><div><div></div><div class="inner"><span>x<div>yo</div></span></div></div></div>
        </body>
      </html>
    "#,
    );

    let parsed_html = Html::parse_document(&html);
    let fragment = parsed_html
        .select(&Selector::parse("body").unwrap())
        .next()
        .unwrap();
    let foo = fragment
        .select(&Selector::parse("div#foo").unwrap())
        .next()
        .unwrap();

    let text = foo
        .children()
        .nth(1)
        .unwrap()
        .children()
        .nth(1)
        .unwrap()
        .children()
        .map(|child| child.value())
        .collect::<Vec<_>>();

    println!("{:?}", text);
}

my Cargo.toml file:

[package]
name = "scraper"
version = "0.1.0"
authors = ["foo@bar"]
edition = "2018"

[dependencies]
scraper = "0.12.0"

Вывод rustup show:

Default host: x86_64-apple-darwin
rustup home:  /Users/foobar/.rustup

stable-x86_64-apple-darwin (directory override for '/Users/foobar')
rustc 1.43.1 (8d69840ab 2020-05-04)

Консоль выводит [Element(<span>)], который является результатом функции сопоставления, в которой я вызываю метод value для элемента.

Результат, которого я ожидаю, будет xyo.

Есть ли у scraper crate какие-то методы, которые могут извлекать текст, как я хочу, или мне придется создавать какую-то рекурсивную функцию?

Я знаю, что этот код подвержен ошибкам, и я буду использовать оператор match для обработки случаев, когда определенные узлы отсутствуют в документах. Пока я сосредоточен только на том, как получить свойство innerText на дочерних узлах.

1 Ответ

1 голос
/ 05 августа 2020

scraper имеет метод для извлечения текста: ElementRef::text.

Способ добиться того, что вы ищете, из вызовов .children():

...
.children()
.filter_map(|child| ElementRef::wrap(child))
.flat_map(|el| el.text())
.collect::<Vec<_>>(); // Or `.collect::<String>()` if you want xyo concatenated

Однако, учитывая ваш пример, я чувствую, что вы можете использовать селектор, чтобы напрямую получить ElementRef, который соответствует вашей цели, вместо того, чтобы выполнять работу с большим количеством .children() s:

let inner: String = parsed_html
    .select(&Selector::parse("body div#foo:nth-child(1):nth-child(1)").unwrap()) // or "body div#foo div.inner"
    .flat_map(|el| el.text())
    .collect();

Это будет похоже на то, что указано в scraper документации .

...