beautifulsoup
Lokalizowanie elementów
Szukaj…
Znajdź tekst po elemencie w BeautifulSoup
Wyobraź sobie, że masz następujący kod HTML:
<div>
<label>Name:</label>
John Smith
</div>
Musisz zlokalizować tekst „John Smith” za elementem label
.
W takim przypadku możesz zlokalizować element label
według tekstu, a następnie użyć właściwości .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())
Drukuje John Smith
.
Używanie selektorów CSS do lokalizowania elementów w BeautifulSoup
BeautifulSoup ma ograniczone wsparcie dla selektorów CSS , ale obejmuje najczęściej używane. Użyj metody select()
, aby znaleźć wiele elementów, a select_one()
aby znaleźć pojedynczy element.
Podstawowy przykład:
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())
Wydruki:
item1
item2
item3
Lokalizowanie komentarzy
Aby zlokalizować komentarze w BeautifulSoup
, użyj argumentu text
(lub string
w najnowszych wersjach), sprawdzając typ 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)
Drukuje desired text
.
Funkcje filtrów
BeautifulSoup pozwala filtrować wyniki, udostępniając funkcję find_all
i podobne funkcje. Może to być przydatne w przypadku złożonych filtrów, a także jako narzędzie do ponownego wykorzystania kodu.
Podstawowe użycie
Zdefiniuj funkcję, która przyjmuje element jako jedyny argument. Funkcja powinna zwrócić wartość True
jeśli argument jest zgodny.
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")))
Kolejny przykład, w którym znajdują się tagi z wartością href
, które się nie zaczynają
Dostarczenie dodatkowych argumentów do filtrowania funkcji
Ponieważ funkcja przekazana do find_all
może przyjąć tylko jeden argument, czasem przydatne jest utworzenie „fabryk funkcji”, które wytwarzają funkcje nadające się do użycia w find_all
. Jest to przydatne do uelastycznienia funkcji wyszukiwania znaczników.
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"))
Dostęp do tagów wewnętrznych i ich atrybutów początkowo wybranego tagu
Załóżmy, że masz html
po wybraniu 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>
'''
A jeśli chcesz uzyskać dostęp do href
znacznika <a>
, możesz to zrobić w ten sposób:
a_tag = html.a
link = a_tag['href']
print(link)
https://example.com
Jest to przydatne, gdy nie można bezpośrednio wybrać znacznika <a>
ponieważ attrs
nie dają unikalnej identyfikacji, istnieją inne „bliźniacze” znaczniki <a>
na przeanalizowanej stronie. Ale możesz jednoznacznie wybrać znacznik nadrzędny, który zawiera potrzebne <a>
.
Zbieranie opcjonalnych elementów i / lub ich atrybutów z serii stron
Rozważmy sytuację, gdy analizujesz liczbę stron i chcesz zebrać wartość z elementu, który jest opcjonalny (może być prezentowany na jednej stronie i może być nieobecny na innej) dla strony paticznej.
Ponadto sam element, na przykład, jest najbardziej zwyczajnym elementem na stronie, innymi słowy, żadne konkretne atrybuty nie mogą go jednoznacznie zlokalizować. Ale widzisz, że możesz poprawnie wybrać jego element nadrzędny i znasz numer zamówienia żądanego elementu na odpowiednim poziomie zagnieżdżenia.
from bs4 import BeautifulSoup
soup = BeautifulSoup(SomePage, 'lxml')
html = soup.find('div', class_='base class') # Below it refers to html_1 and html_2
Poszukiwany element jest opcjonalny, więc mogą być dwie sytuacje, w których html
powinien być:
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
'''
Jeśli masz html_1
, możesz odebrać !Needed text!
z tagu nr 3 w ten sposób:
wanted tag = html_1.div.find_next_sibling().find_next_sibling() # this gives you whole tag №3
Początkowo dostaje 1 div
, następnie 2 razy przełącza się na następny div
na tym samym poziomie zagnieżdżenia, aby dostać się do № 3.
wanted_text = wanted_tag.text # extracting !Needed text!
Przydatność tego podejścia pojawia się, gdy html_2
się html_2
- podejście nie spowoduje błędu, da None
:
print(html_2.div.find_next_sibling().find_next_sibling())
None
Użycie find_next_sibling()
jest tutaj kluczowe, ponieważ ogranicza wyszukiwanie elementów według odpowiedniego poziomu zagnieżdżenia. Jeśli użyjesz find_next()
tag nr 4 zostanie zebrany i nie chcesz:
print(html_2.div.find_next().find_next())
<div>Confusing div text</div>
Możesz także eksplorować find_previous_sibling()
i find_previous()
które działają find_previous()
odwrotnie.
Wszystkie opisane funkcje mają swoje miltiple warianty do przechwytywania wszystkich tagów, nie tylko pierwszego:
find_next_siblings()
find_previous_siblings()
find_all_next()
find_all_previous()