【问题标题】:Beautifulsoup : Difference between .find() and .select()Beautifulsoup:.find() 和 .select() 之间的区别
【发布时间】:2016-06-25 12:09:28
【问题描述】:

当你使用BeautifulSoup抓取网站的某个部分时,你可以使用

  • soup.find()soup.findAll()
  • soup.select()

.find().select() 方法之间有区别吗? (例如在性能或灵活性等方面)或者它们是否相同?

【问题讨论】:

  • select() 接受 CSS 选择器,find() 不接受
  • 但我不太明白它们之间的区别。因为对我来说,他们可以做同样的事情。我想知道区别。 (实际上,我对 .select() 有一点偏好)
  • @PadraicCunningham 你在 cmets 中有很好的分数。你为什么不把它们总结成一个答案呢?
  • 请不要再使用findAll(),因为它不符合 Python 的命名约定。有一个find_all() 方法。

标签: python python-3.x beautifulsoup


【解决方案1】:

总结一下cmets:

  • select 找到多个实例并返回一个列表,find 找到第一个,所以它们不会做同样的事情。 select_one 相当于 find
  • 在链接标签或使用 tag.classname 时,我几乎总是使用 css 选择器,如果要查找没有类的单个元素,我使用 find。本质上,这取决于用例和个人偏好。
  • 就灵活性而言,我想你知道答案,soup.select("div[id=foo] > div > div > div[class=fee] > span > span > a") 使用多个链式 find/find_all 调用看起来会很丑。
  • bs4 中 css 选择器的唯一问题是支持非常有限,nth-of-type 是唯一实现的伪类,并且像 a[href][src] 这样的链接属性也不是与 css 选择器的许多其他部分一样受支持。但是像 a[href=..]* , a[href^=]a[href$=] 等等......我认为比find("a", href=re.compile(....)) 好得多,但这又是个人喜好。

为了提高性能,我们可以运行一些测试,我修改了 answer here 的代码,该代码运行在从 here 获取的 800 多个 html 文件上,虽然并不详尽,但应该为某些选项的可读性提供线索,并且表现:

修改后的功能有:

from bs4 import BeautifulSoup
from glob import iglob


def parse_find(soup):
    author = soup.find("h4", class_="h12 talk-link__speaker").text
    title = soup.find("h4", class_="h9 m5").text
    date = soup.find("span", class_="meta__val").text.strip()
    soup.find("footer",class_="footer").find_previous("data", {
        "class": "talk-transcript__para__time"}).text.split(":")
    soup.find_all("span",class_="talk-transcript__fragment")



def parse_select(soup):
    author = soup.select_one("h4.h12.talk-link__speaker").text
    title = soup.select_one("h4.h9.m5").text
    date = soup.select_one("span.meta__val").text.strip()
    soup.select_one("footer.footer").find_previous("data", {
        "class": "talk-transcript__para__time"}).text
    soup.select("span.talk-transcript__fragment")


def  test(patt, func):
    for html in iglob(patt):
        with open(html) as f:
            func(BeautifulSoup(f, "lxml")

现在是时间安排:

In [7]: from testing import test, parse_find, parse_select

In [8]: timeit test("./talks/*.html",parse_find)
1 loops, best of 3: 51.9 s per loop

In [9]: timeit test("./talks/*.html",parse_select)
1 loops, best of 3: 32.7 s per loop

就像我说的并不详尽,但我认为我们可以肯定地说 css 选择器肯定更有效。

【讨论】:

  • 我使用 select 来检索 dt 类名的实例。它没有给我所有的结果,而是最终给出了 10 个实例。是否有要更改的默认值?
  • @LakshmiNarayanan,您确定 html 没有损坏或没有以某种方式动态添加吗?
  • 我必须发出向下滚动命令才能完全加载 html。虽然页面已加载,但 html 没有。感谢您的回复!
  • find…() 方法不需要 class_= 或只有 "class" 键的字典,因为如果有与第二个参数一样的字符串,那就是类值。
  • css 选择器很棒,即使BeautifulSoup 的范围有限
猜你喜欢
  • 2015-08-19
  • 2015-10-03
  • 2013-07-07
  • 2014-10-09
  • 1970-01-01
  • 1970-01-01
  • 2015-09-10
  • 1970-01-01
  • 2019-08-07
相关资源
最近更新 更多