BeautifulSoup 提取节点的 XPATH 或 CSS 路径

Posted

技术标签:

【中文标题】BeautifulSoup 提取节点的 XPATH 或 CSS 路径【英文标题】:BeautifulSoup extract XPATH or CSS Path of node 【发布时间】:2014-11-16 03:32:05 【问题描述】:

我想从 html 中提取一些数据,然后能够在客户端突出显示提取的元素,而无需修改源 html。 XPath 或 CSS Path 看起来很适合这个。 是否可以直接从 BeautifulSoup 中提取 XPATH 或 CSS 路径? 现在我使用目标元素的标记,然后使用 lxml lib 来提取 xpath,这对性能非常不利。我知道BSXPath.py——它不适用于BS4。 由于复杂性,重写所有内容以使用本机 lxml 库的解决方案是不可接受的。

import bs4
import cStringIO
import random
from lxml import etree


def get_xpath(soup, element):
  _id = random.getrandbits(32)
  for e in soup():
    if e == element:
      e['data-xpath'] = _id
      break
  else:
    raise LookupError('Cannot find  in '.format(element, soup))
  content = unicode(soup)
  doc = etree.parse(cStringIO.StringIO(content), etree.HTMLParser())
  element = doc.xpath('//*[@data-xpath=""]'.format(_id))
  assert len(element) == 1
  element = element[0]
  xpath = doc.getpath(element)
  return xpath

soup = bs4.BeautifulSoup('<div id=i>hello, <b id=i test=t>world!</b></div>')
xpath = get_xpath(soup, soup.div.b)
assert '//html/bodydiv/b' == xpath

【问题讨论】:

简短回答:不,没有现有的方法。您必须自己构建它。 【参考方案1】:

提取简单的 CSS/XPath 实际上很容易。这与 lxml 库提供的相同。

def get_element(node):
  # for XPATH we have to count only for nodes with same type!
  length = len(list(node.previous_siblings)) + 1
  if (length) > 1:
    return '%s:nth-child(%s)' % (node.name, length)
  else:
    return node.name

def get_css_path(node):
  path = [get_element(node)]
  for parent in node.parents:
    if parent.name == 'body':
      break
    path.insert(0, get_element(parent))
  return ' > '.join(path)

soup = bs4.BeautifulSoup('<div></div><div><strong><i>bla</i></strong></div>')
assert get_css_path(soup.i) == 'div:nth-child(2) > strong > i'

【讨论】:

谢谢!我对此进行了改编,用于从文档根到节点(包括 HTML cmets)提取 XPath 表达式,并使用 lxml 的 XPath 解析器进行了测试。也许有人觉得它有用:gist.github.com/gruentee/203e4ba3791581070df9a4b1e6c55549【参考方案2】:

恐怕图书馆还不能做到这一点。您可以通过 css 路径获取它们... SORTA... 但是,它有点令人费解,您在其中命名每个元素和类,例如:

soup.find("htmlelement", class_="theclass")

如果您希望更具体地了解您抓取的内容,您也可以使用 id 来代替类或同时使用两者。

你可以修改它以继续前进:

soup.find("htmlelement", class_="theclass").find("htmlelement2", class_="theclass2") 

以此类推。

还有一些方法可以通过调用内置的“next”函数来导航:

find_next("td", class_="main").find_next("td", class_="main").next.next

【讨论】:

以上是关于BeautifulSoup 提取节点的 XPATH 或 CSS 路径的主要内容,如果未能解决你的问题,请参考以下文章

Python中xPath技术和BeautifulSoup的使用

Python中xPath技术和BeautifulSoup的使用

python爬虫之html解析Beautifulsoup和Xpath

爬虫进阶数据提取-lxml模块(万能操作)

xpath语法

数据的查找和提取[2]——xpath解析库的使用