【问题标题】:Xpath: Everything between two elements in htmlXpath:html中两个元素之间的所有内容
【发布时间】:2021-06-18 03:17:33
【问题描述】:

我正在尝试使用 xpath 来获取两个节点之间每个节点的文本,但这有点棘手。结构有点像这样:

<table class="infobox biography vcard">
<p>
  <b>Mark Hamill</b>
  <span> was born in ...</span>
  <i> in the early 1980s he...</i>
  <a href="/some/place">Luke Skywalker</a>
</p>
<div class="toc">

我需要该段落中恰好位于表格和 div 之间的所有文本,这是我的查询 xpath 到目前为止: //table[@class="infobox biography vcard"]/following-sibling::node()[following-sibling::div[@class="toc"]]/text() 它不会带来某些标签中的所有文本,我该如何实现? 注意: p 标签没有任何道具,但该文档中还有其他一些 p 标签

【问题讨论】:

  • 是否有与此相关的网址,您是否也愿意考虑使用 bs4 的 css?
  • 更新 html 代码以包含更多数据。或者至少让现有的更清晰。文本在哪里?
  • 请更新您的问题,使您的 XPath 类似于您的 html 代码(现在 html 中缺少 @class 属性),并显示预期结果。
  • 当然。该网址是一篇维基百科文章。网址是这个:en.wikipedia.org/wiki/Mark_Hamill
  • 我刚刚编辑了 html 代码并添加了一个 URL :) @Qharr

标签: html python-3.x web-scraping xpath lxml


【解决方案1】:

已编辑:

wiki-page 在表格和 div 之间有 2 个 p 元素,如下所示:

<table class="infobox biography vcard">
<!-- Content of table -->
</table>

<p>Here all kinds of mixed content</p>
<p>Here other kinds of mixed content</p>

<div class="toc">
<!-- Content of toc -->
</div>

要获取表格和 div 之间 p 中的所有文本,请使用此 XPath:

normalize-space(//p[preceding-sibling::table[@class='infobox biography vcard'] and following-sibling::div[@class='toc']])

规范化空间只是为了满足您的“预期输出将是 P 标签之间的所有文本”,但根据您的需要也可以使用

//p[preceding-sibling::table[@class='infobox biography vcard'] and following-sibling::*div[@class='toc']]//text()

如果您想完全控制从这些 p 中使用什么,您可以从像这样获取 p 开始:

//p[preceding-sibling::table[@class='infobox biography vcard'] and following-sibling::*div[@class='toc']]

并遍历这些 p 的混合内容,也可能使用 XPath 来获得您需要的内容。

【讨论】:

  • 你是如何在 JS 中运行第一个 XPath 的?我在控制台中运行它,它返回一个空字符串
  • 在 Oxygen Developer 中并使用 Saxon。你能分享一下网址,看看为什么你会得到一个空字符串吗?
  • 我找到了你没有得到任何结果的原因。这是因为表格和 div 之间有 2 个 p。我已经相应地改变了答案。
  • 我用第一个查询并且像一个魅力一样工作,我尝试了其他两个但我无法让它工作,但是它解决了我的问题,非常感谢:D
【解决方案2】:

如果您想要传记,您可以使用相邻的同级组合器使用 bs4 获取表格旁边的 2 个段落。它比 xpath 快。

import requests
from bs4 import BeautifulSoup as bs

r = requests.get('https://en.wikipedia.org/wiki/Mark_Hamill')
soup = bs(r.content, 'lxml')
print(' '.join([i.text.strip() for i in soup.select('.biography + p, .biography + p + p')]))

【讨论】:

  • 它几乎可以工作:(除了我会刮除这个之外的更多网站。其中一些没有两个段落,其中一些有更多。有没有如何使这种动态化?
  • 在网页抓取方面,没有一种适合所有人的方式。如果这是基于 wiki 的,或许可以考虑使用 python wiki api?
  • 您可以动态确定同级 p 标签的数量,但这并不意味着它们都是您想要的。
  • 我也试过了,效果很好,尽管它本身不是 XPath,但它的效果非常好。这就是为什么我给它一个赞成票而不是正确答案,即使它是正确的。
  • 谢谢。我认为您应该比 xpath 更快地找到它,但请测试一下。
猜你喜欢
  • 1970-01-01
  • 2020-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-23
  • 1970-01-01
  • 1970-01-01
  • 2012-06-07
相关资源
最近更新 更多