139

我正在使用 BeautifulSoup 来抓取一个 URL,并且我有以下代码,以查找td其类为的标签'empformbody'

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。是否可以将 XPath 与 BeautifulSoup 一起使用?如果可能,请提供我的示例代码。

4

10 回答 10

206

不,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.

来个完整的循环:BeautifulSoup 本身确实有非常完整的CSS 选择器支持

for cell in soup.select('table#foobar td.empformbody'):
    # Do something with these table cells.
于 2012-07-13T07:31:41.127 回答
171

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

于 2012-07-13T11:44:45.663 回答
55

正如其他人所说,BeautifulSoup 没有 xpath 支持。可能有很多方法可以从 xpath 中获取内容,包括使用 Selenium。但是,这里有一个适用于 Python 2 或 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)

我用这个作为参考。

于 2017-01-06T21:38:07.587 回答
19

BeautifulSoup 有一个名为findNext的函数,来自当前元素导向的子元素,所以:

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

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

div[class=class_value]/div[id=id_value]
于 2014-07-09T13:11:19.327 回答
16
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 提取值

于 2020-05-06T18:24:39.923 回答
4

当您使用 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”部分

于 2018-08-18T10:15:26.120 回答
3

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

此外,正如您在此处看到的关于 SO 的类似问题,OP 要求将 XPath 转换为 BeautifulSoup,所以我的结论是 - 不,没有可用的 XPath 解析。

于 2012-07-13T07:30:25.333 回答
1

也许您可以在没有 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'))
于 2019-12-06T08:44:12.967 回答
0

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

这是我所做的一个例子。我使用“请求”模块来读取 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()
于 2017-12-15T08:35:00.883 回答
-1

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

于 2021-03-01T00:26:44.680 回答