Beautifulsoup : .find()和.select()之间的区别。

问题描述 投票:33回答:1

当你使用 美丽汤 刮取网站的某一部分,您可以使用

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

这两者之间有什么区别吗?.find().select() (如在性能或灵活性等方面)还是它们是一样的?

python python-3.x beautifulsoup
1个回答
48
投票

总结一下大家的意见。

  • select 找到多个实例并返回一个列表。找到 找到第一个,所以他们做的事情不一样。选择一个 等于 找到.
  • 我几乎总是使用css选择器,当链接标签或使用 tag.classname如果要找一个没有类的单元素,我用的是 找到. 基本上,它归结为用例和个人偏好。
  • 至于灵活性,我想你已经知道答案了。soup.select("div[id=foo] > div > div > div[class=fee] > span > span > a") 使用多链式 findfind_all 调用。
  • bs4中css选择器的唯一问题是支持非常有限。正型 是唯一实现的伪类,而且像a[href][src]这样的链式属性也不支持,css选择器的很多其他部分也不支持。但是像 a[href=..]* , a[href^=], a[href$=] 等,我认为比起 find("a", href=re.compile(....)) 但这又是个人的喜好。

对于性能,我们可以运行一些测试,我修改了代码,从一个 在此作答 在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选择器肯定更有效率。

© www.soinside.com 2019 - 2024. All rights reserved.