beautifulsoup
Éléments de localisation
Recherche…
Localiser un texte après un élément dans BeautifulSoup
Imaginez que vous avez le code HTML suivant:
<div>
<label>Name:</label>
John Smith
</div>
Et vous devez localiser le texte "John Smith" après l'élément label
.
Dans ce cas, vous pouvez localiser l'élément label
par texte, puis utiliser la propriété .next_sibling
:
from bs4 import BeautifulSoup
data = """
<div>
<label>Name:</label>
John Smith
</div>
"""
soup = BeautifulSoup(data, "html.parser")
label = soup.find("label", text="Name:")
print(label.next_sibling.strip())
Imprime John Smith
.
Utilisation de sélecteurs CSS pour localiser des éléments dans BeautifulSoup
BeautifulSoup a un support limité pour les sélecteurs CSS , mais couvre les plus couramment utilisés. Utilisez la méthode select()
pour rechercher plusieurs éléments et select_one()
pour rechercher un seul élément.
Exemple de base:
from bs4 import BeautifulSoup
data = """
<ul>
<li class="item">item1</li>
<li class="item">item2</li>
<li class="item">item3</li>
</ul>
"""
soup = BeautifulSoup(data, "html.parser")
for item in soup.select("li.item"):
print(item.get_text())
Impressions:
item1
item2
item3
Localisation des commentaires
Pour localiser les commentaires dans BeautifulSoup
, utilisez l'argument text
(ou string
dans les versions récentes) vérifiant le type à Comment
:
from bs4 import BeautifulSoup
from bs4 import Comment
data = """
<html>
<body>
<div>
<!-- desired text -->
</div>
</body>
</html>
"""
soup = BeautifulSoup(data, "html.parser")
comment = soup.find(text=lambda text: isinstance(text, Comment))
print(comment)
Imprime desired text
.
Fonctions de filtrage
BeautifulSoup vous permet de filtrer les résultats en fournissant une fonction à find_all
et à des fonctions similaires. Cela peut être utile pour les filtres complexes ainsi que pour un outil de réutilisation du code.
Utilisation de base
Définir une fonction qui prend un élément comme seul argument. La fonction doit retourner True
si l'argument correspond.
def has_href(tag):
'''Returns True for tags with a href attribute'''
return bool(tag.get("href"))
soup.find_all(has_href) #find all elements with a href attribute
#equivilent using lambda:
soup.find_all(lambda tag: bool(tag.get("href")))
Un autre exemple qui trouve des balises avec une valeur href
qui ne commence pas par
Fournir des arguments supplémentaires pour filtrer les fonctions
Comme la fonction transmise à find_all
ne peut prendre qu'un seul argument, il est parfois utile de créer des "fabriques de fonctions" qui produisent des fonctions pouvant être utilisées dans find_all
. Ceci est utile pour rendre vos fonctions de recherche de tags plus flexibles.
def present_in_href(check_string):
return lambda tag: tag.get("href") and check_string in tag.get("href")
soup.find_all(present_in_href("/partial/path"))
Accès aux balises internes et à leurs attributs de la balise initialement sélectionnée
Supposons que vous ayez un html
après avoir sélectionné avec soup.find('div', class_='base class')
:
from bs4 import BeautifulSoup
soup = BeautifulSoup(SomePage, 'lxml')
html = soup.find('div', class_='base class')
print(html)
<div class="base class">
<div>Sample text 1</div>
<div>Sample text 2</div>
<div>
<a class="ordinary link" href="https://example.com">URL text</a>
</div>
</div>
<div class="Confusing class"></div>
'''
Et si vous voulez accéder à la balise <a>
href
, vous pouvez le faire de cette manière:
a_tag = html.a
link = a_tag['href']
print(link)
https://example.com
Ceci est utile lorsque vous ne pouvez pas sélectionner directement la balise <a>
car ses attrs
ne vous donnent pas d’identification unique, il existe d’autres balises <a>
jumelées dans la page analysée. Mais vous pouvez sélectionner de manière unique une balise parent contenant <a>
.
Collecter des éléments facultatifs et / ou leurs attributs à partir de séries de pages
Considérons la situation lorsque vous analysez le nombre de pages et que vous souhaitez collecter la valeur de l'élément facultatif (peut être présenté sur une page et peut être absent sur une autre) pour une page spécifique.
De plus, l'élément lui-même, par exemple, est l' élément le plus ordinaire de la page, c'est-à-dire qu'aucun attribut spécifique ne peut le localiser de manière unique. Mais vous voyez que vous pouvez sélectionner correctement son élément parent et que vous connaissez le numéro d'ordre de l'élément souhaité dans le niveau d'imbrication correspondant.
from bs4 import BeautifulSoup
soup = BeautifulSoup(SomePage, 'lxml')
html = soup.find('div', class_='base class') # Below it refers to html_1 and html_2
L'élément recherché est facultatif, donc il pourrait y avoir 2 situations pour que html
soit:
html_1 = '''
<div class="base class"> # №0
<div>Sample text 1</div> # №1
<div>Sample text 2</div> # №2
<div>!Needed text!</div> # №3
</div>
<div>Confusing div text</div> # №4
'''
html_2 = '''
<div class="base class"> # №0
<div>Sample text 1</div> # №1
<div>Sample text 2</div> # №2
</div>
<div>Confusing div text</div> # №4
'''
Si vous avez html_1
vous pouvez collecter du !Needed text!
de tag №3 de cette façon:
wanted tag = html_1.div.find_next_sibling().find_next_sibling() # this gives you whole tag №3
Il obtient initialement №1 div
, puis 2 fois passe au div
suivant au même niveau d'imbrication pour arriver à №3.
wanted_text = wanted_tag.text # extracting !Needed text!
Utilité de cette approche vient lorsque vous obtenez html_2
- approche ne vous donnera pas d'erreur, il ne donnera None
:
print(html_2.div.find_next_sibling().find_next_sibling())
None
L'utilisation de find_next_sibling()
est cruciale car elle limite la recherche d'éléments par niveau d'imbrication respectif. Si vous utilisez find_next()
balise №4 sera collectée et vous ne le souhaitez pas:
print(html_2.div.find_next().find_next())
<div>Confusing div text</div>
Vous pouvez également explorer find_previous_sibling()
et find_previous()
qui fonctionnent de manière find_previous()
opposée.
Toutes les fonctions décrites ont leurs variantes multiples pour attraper toutes les balises, pas seulement la première:
find_next_siblings()
find_previous_siblings()
find_all_next()
find_all_previous()