我们可以在 BeautifulSoup 中使用 XPath 吗?

我使用 BeautifulSoup 来获取一个 URL,我使用以下代码来查找类为 'empformbody'td标记:

import urllib
import urllib2
from BeautifulSoup import BeautifulSoup


url =  "http://www.example.com/servlet/av/ResultTemplate=AVResult.html"
req = urllib2.Request(url)
response = urllib2.urlopen(req)
the_page = response.read()
soup = BeautifulSoup(the_page)


soup.findAll('td',attrs={'class':'empformbody'})

现在在上面的代码中,我们可以使用 findAll来获取与它们相关的标记和信息,但是我想使用 XPath。可以在 BeautifulSoup 中使用 XPath 吗?如果可能的话,请给我示例代码。

271202 次浏览

我搜索了他们的 医生,似乎没有 XPath 选项。

另外,正如您在 SO 上的一个类似问题上看到的 给你一样,OP 要求将 XPath 转换为 BeautifulSoup,因此我的结论是——不,没有可用的 XPath 解析。

不,BeautifulSoup 本身不支持 XPath 表达式。

另一个库 Lxml是的支持 XPath 1.0。它有一个 BeautifulSoup 兼容模式,可以像 Soup 那样尝试解析破碎的 HTML。然而,默认 lxml HTML 解析器在解析破碎的 HTML 方面做得一样好,而且我相信它更快。

将文档解析为 lxml 树之后,可以使用 .xpath()方法搜索元素。

try:
# Python 2
from urllib2 import urlopen
except ImportError:
from urllib.request import urlopen
from lxml import etree


url =  "http://www.example.com/servlet/av/ResultTemplate=AVResult.html"
response = urlopen(url)
htmlparser = etree.HTMLParser()
tree = etree.parse(response, htmlparser)
tree.xpath(xpathselector)

还有一个具有附加功能的 专用 lxml.html()模块

请注意,在上面的示例中,我将 response对象直接传递给 lxml,因为让解析器直接从流中读取响应比首先将响应读入大字符串更有效。要对 requests库执行相同的操作,需要设置 stream=True并传入 response.raw对象 在启用透明传输解压缩之后:

import lxml.html
import requests


url =  "http://www.example.com/servlet/av/ResultTemplate=AVResult.html"
response = requests.get(url, stream=True)
response.raw.decode_content = True
tree = lxml.html.parse(response.raw)

您可能感兴趣的是 支持 CSS 选择器; CSSSelector类将 CSS 语句转换为 XPath 表达式,使您的 td.empformbody搜索变得更加容易:

from lxml.cssselect import CSSSelector


td_empformbody = CSSSelector('td.empformbody')
for elem in td_empformbody(tree):
# Do something with these table cells.

绕了一圈: 美丽汤本身 是的有非常完整的 CSS 选择器支持:

for cell in soup.select('table#foobar td.empformbody'):
# Do something with these table cells.

我可以确认 Beautiful Soup 中没有 XPath 支持。

BeautifulSoup 有一个名为 下一个的函数,该函数来自当前元素指向的子元素,因此:

father.findNext('div',{'class':'class_value'}).findNext('div',{'id':'id_value'}).findAll('a')

上面的代码可以模仿下面的 xpath:

div[class=class_value]/div[id=id_value]

正如其他人所说,BeautifulSoup 不支持 xpath。从 xpath 获取内容可能有很多种方法,包括使用 Selenium。然而,这里有一个可以在 Python2或3中使用的解决方案:

from lxml import html
import requests


page = requests.get('http://econpy.pythonanywhere.com/ex/001.html')
tree = html.fromstring(page.content)
#This will create a list of buyers:
buyers = tree.xpath('//div[@title="buyer-name"]/text()')
#This will create a list of prices
prices = tree.xpath('//span[@class="item-price"]/text()')


print('Buyers: ', buyers)
print('Prices: ', prices)

我用 这个作为参考。

这是一个相当老的线程,但是现在有一个解决方案,当时可能还没有在 BeautifulSoup 中。

这是我所做的一个例子。我使用“ request”模块读取 RSS 提要,并在一个名为“ RSS _ text”的变量中获取其文本内容。这样,我就可以在 BeautifulSoup 中运行它,搜索 xpath/rss/channel/title,并检索其内容。它并不完全是 XPath 的全部优点(通配符、多路径等) ,但是如果您只有一个想要定位的基本路径,那么它就可以工作。

from bs4 import BeautifulSoup
rss_obj = BeautifulSoup(rss_text, 'xml')
cls.title = rss_obj.rss.channel.title.get_text()

当您使用 lxml 时,一切都很简单:

tree = lxml.html.fromstring(html)
i_need_element = tree.xpath('//a[@class="shared-components"]/@href')

但是当使用 BeautifulSoup BS4时,一切都太简单了:

  • 首先删除“//”和“@”
  • 在“ =”之前加第二个星号

试试这个魔术:

soup = BeautifulSoup(html, "lxml")
i_need_element = soup.select ('a[class*="shared-components"]')

如您所见,这不支持子标记,所以我删除了“/@href”部分

也许您可以尝试不使用 XPath 执行以下操作

from simplified_scrapy.simplified_doc import SimplifiedDoc
html = '''
<html>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
'''
# What XPath can do, so can it
doc = SimplifiedDoc(html)
# The result is the same as doc.getElementByTag('body').getElementByTag('div').getElementByTag('h1').text
print (doc.body.div.h1.text)
print (doc.div.h1.text)
print (doc.h1.text) # Shorter paths will be faster
print (doc.div.getChildren())
print (doc.div.getChildren('p'))
from lxml import etree
from bs4 import BeautifulSoup
soup = BeautifulSoup(open('path of your localfile.html'),'html.parser')
dom = etree.HTML(str(soup))
print dom.xpath('//*[@id="BGINP01_S1"]/section/div/font/text()')

上面使用了 Soup 对象和 lxml 的组合,可以使用 xpath 提取值

使用 soup.find(class_='myclass')