【问题标题】:How can I drop 2-3 elements from a html node and scrape the rest?如何从 html 节点中删除 2-3 个元素并抓取其余元素?
【发布时间】:2015-12-21 21:15:51
【问题描述】:

准确地说,我有一个类,比如 A,我通过 rvest 中的 html_nodes 选择它。现在A可以有很多子类和很多html标签,比如linksimg标签。我想从 A 中删除一些特定的类和标签,同时抓取其余数据。我不知道其余数据的类别。我知道我想把什么列入黑名单。

HTML(假设)。这个标签<div class="messageContent">在文档中最多重复25次,内容不同,但结构相同。

<div class="messageContent">
<article>
<blockquote class="messageText SelectQuoteContainer ugc baseHtml">
<div class="bbCodeBlock bbCodeQuote" data-author="Generic">

<aside>
<div class="attribution type">Generic said:
<a href="goto/post?id=32554#post-32754" class="AttributionLink">&uarr;</a>
</div>
<blockquote class="quoteContainer"><div class="quote">I see what you did there.</div><div class="quoteExpand">Click to expand...</div></blockquote>
</aside>

</div><img src="styles/default/xenforo/clear.png" class="mceSmilieSprite      mceSmilie9" alt=":o" title="Eek!    :o"/> Really?
<aside>
<div class="attribution type">Generic said:
<a href="goto/post?id=32554#post-32754" class="AttributionLink">&uarr;</a>
</div>
<blockquote class="quoteContainer"><div class="quote">I see what you did there.</div><div class="quoteExpand">Click to expand...</div></blockquote>
</aside>

<div class="messageTextEndMarker">&nbsp;</div>
</blockquote>
</article>
</div>

所以,我正在抓取的页面包含多个这样的类。我愿意

posts <- page %>%  html_nodes(".messageContent") 

这给了我一个包含 25 个 html 节点的列表,每个节点都包含上述 html 内容的变体。

我想删除&lt;aside&gt;&lt;/aside&gt; 标签中的所有内容(可能出现在帖子的多个位置),并通过html_text() %&gt;% as.character() 捕获html 的其余部分

我可以用 rvest 做到这一点吗?

测试@Mirosław Zalewski 的解决方案。

test<- page %>% html_node(".messageContent") %>%
          html_nodes(xpath='//*[not(ancestor::aside or name()="aside")]/text()')

这会返回页面中所有不在其中的元素。一点微调,导致我:

page %>% html_nodes(xpath='(//div[@class="messageContent"])[1]//*[not(ancestor::aside or name()="aside")]/text()') %>% html_text() %>% as.character()

迭代了 25 个类,这正是我所需要的。

【问题讨论】:

  • 请向我们提供一个可重现的示例,以便为您提供帮助。

标签: r rvest


【解决方案1】:

使用 XPath,您可以选择不是&lt;aside&gt;&lt;aside&gt; 的后代的所有节点:

page %>% html_node(".messageContent") %>%
    html_nodes(xpath='//*[not(ancestor::aside or name()="aside")]')

不幸的是,这也会匹配包含&lt;aside&gt; 的元素。如果你将它传递给html_text(),它无论如何都会返回&lt;aside&gt; 文本内容。

这可以通过在查询中添加另一个条件来克服。这种条件的一个很好的候选者是“所有文本节点”:

page %>% html_node(".messageContent") %>%
    html_nodes(xpath='//*[not(ancestor::aside or name()="aside")]/text()')

实际上,/text() 将只返回文本节点,这几乎可以让您完全跳过 html_text() 调用。但是由于许多文本节点都是可疑的(仅包含空白字符)并且此函数具有内置的 trim,因此您可以考虑调用它。

请注意,此解决方案还将跳过任何非文本内容,例如图像引用(可能包括表情)。您最初的提议也会这样做,但我不清楚您是否有意这样做。

【讨论】:

  • 你的命令给了我一个几乎所有页面元素的列表。 (1.5mb,2500 个元素)。这个命令page %&gt;% html_nodes(xpath='//article[not(ancestor::aside or name()="aside" or self::aside)]') %&gt;% html_text() %&gt;% as.character()这给了我一个包含所有帖子文本的25个列表,包括&lt;aside&gt; &amp; &lt;/aside&gt;之间的位我尝试了一些其他组合,但没有一个能够取消选择&lt;aside&gt;节点。跨度>
  • @user795028 除了&lt;aside&gt;&lt;aside&gt; 的后代之外的所有页面元素,这似乎符合您的初始要求。我不明白这里到底是什么问题 - 您可以在评论中澄清或使用更多信息编辑初始问题。如果这对您来说更容易,您可以选择所有其他元素的直接子元素&lt;article&gt;,然后遍历它们。我可以想象该函数将采用&lt;article&gt; 元素,选择不是&lt;aside&gt; (后代)的所有内容并返回所选节点的文本内容。
  • page %&gt;% html_nodes(xpath='//article/*[not(parent::aside)]')page %&gt;% html_nodes(xpath='//article/*[not(parent::blockquote[@class="quoteContainer"])]') 也没有取消选择相关节点。
  • @user795028 抱歉,在这种情况下,恐怕我无能为力了。您可以尝试编辑您的初始帖子 - 添加您处理的整个文件(如有必要,请审查)和您期望获得的确切结果。我不明白我的解决方案为何不适合您,而您的 cmets 也无法解决。
  • 对您所说的内容进行了微调,使我得到了答案。我花了一段时间才得到它,因为我以前从未使用过 xpath。那谢谢啦。 :)
猜你喜欢
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
  • 2021-11-12
  • 2021-03-25
  • 1970-01-01
  • 1970-01-01
  • 2013-08-20
  • 1970-01-01
相关资源
最近更新 更多