web-dev-qa-db-fra.com

Beautifulsoup: existe-t-il une différence entre .find () et .select () - python 3.xx

J'ai une question simple:

lorsque vous utilisez BeautifulSoup pour gratter une certaine partie d'un site Web, vous pouvez utiliser data.find(), data.findAll() ou data.select().

Maintenant, la question est. Existe-t-il une différence significative entre les méthodes .find() et .select()? (par exemple en termes de performances ou de flexibilité, ou ...)

ou sont-ils les mêmes?

Sincères amitiés

23
Dieter

Pour résumer les commentaires:

  • select trouve plusieurs instances et renvoie une liste, find trouve la première, donc ils ne font pas la même chose. select_one serait l'équivalent de find .
  • J'utilise presque toujours des sélecteurs css lors du chaînage de balises ou en utilisant tag.classname , si je recherche un seul élément sans classe j'utilise trouver . Il s'agit essentiellement du cas d'utilisation et des préférences personnelles.
  • En ce qui concerne la flexibilité, je pense que vous connaissez la réponse, soup.select("div[id=foo] > div > div > div[class=fee] > span > span > a") serait assez moche en utilisant plusieurs appels chaînés find/find_all .
  • Le seul problème avec les sélecteurs css dans bs4 est le support très limité, le nième type est la seule pseudo-classe implémentée et les attributs de chaînage comme un [ href] [src] n'est pas non plus pris en charge comme le sont de nombreuses autres parties des sélecteurs css. Mais des choses comme a [href = ..] *, a [href ^ =] , a [href $ =] etc. sont je pense beaucoup mieux que find("a", href=re.compile(....)) mais encore une fois c'est personnel préférence.

Pour les performances, nous pouvons exécuter des tests, j'ai modifié le code à partir d'un réponse ici fonctionnant sur plus de 800 fichiers html extraits de ici , il n'est pas exhaustif mais devrait donner un indice sur la lisibilité de certaines options et les performances:

Les fonctions modifiées sont:

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")

Maintenant pour les horaires:

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

Comme je l'ai dit pas exhaustif, mais je pense que nous pouvons dire en toute sécurité que les sélecteurs css sont certainement plus efficaces.

34
Padraic Cunningham