Beautifulsoup: Есть ли разница между .find() и .select() - python 3.xx

У меня простой вопрос:

Когда вы используете BeautifulSoup для очистки определенной части веб-сайта, вы можете использовать data.find(), data.findAll() или data.select().

Теперь вопрос в том. Есть ли существенная разница между .find() и .select()? (например, в производительности или гибкости, или...)

или они просто одинаковые?

С уважением

Ответ 1

Подводя итог комментариям:

  • select находит несколько экземпляров и возвращает список, find находит первый, поэтому они не делают то же самое. select_one будет эквивалентом find.
  • Я почти всегда использую селектора css при цепочке тегов или с использованием tag.classname, если вы ищете один элемент без класса, который я использую find. По сути, это сводится к прецеденту и личным предпочтениям.
  • Что касается гибкости, я думаю, что вы знаете ответ, soup.select("div[id=foo] > div > div > div[class=fee] > span > span > a") выглядел бы довольно уродливо, используя множественные вызовы find/find_all.
  • Единственная проблема с селекторами css в bs4 - очень ограниченная поддержка, nth-of-type - это единственный псевдо-класс, реализованный и привязывающий атрибуты, такие как [href] [src], также не поддерживается, как и многие другие части css селекторы. Но такие вещи, как [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 определенно более эффективны.