XPath to język stworzony do obsługi składni XML. Za jego pomocą, używając odpowiedniej składni, jesteśmy wskazać konkretny element strony internetowej, bądź kilka elementów, co jest kluczowe w web scrapingu
Selektory XPath są podstawą do ekstrakcji danych we frameworku Scrapy.
Początkowo składnia może być nieco odrzucająca, szczególnie porównując ją np. z BeautifulSoup. Jest to jednak naprawdę świetne narzędzie.
Wykorzystywane w odpowiedni sposób pozwala przynieść naprawdę wymierne korzyści i bardzo przyspieszyć pracę.
Zalety XPath
Ogromne możliwości
Selektory dają naprawdę wiele możliwości przetwarzania kodu. Oprócz klasycznego wskazywania elementów po nazwie możemy tutaj szukać po fragmentach tekstu, po przedrostkach i przyrostkach, dokonywać operacji matematycznych czy nawet poruszać się po strukturze drzewa pobierając elementy nadrzędne, podrzędne lub równoległe.
Przenaszalność
Pisząc scrapera w Scrapy najczęściej wybieramy pomiędzy selektorami CSS a Xpath. Selektory CSS na pierwszy rzut oka wydają się mieć podobne możliwości co Xpath, jednak część operacji na tych selektorach jest dostępna tylko we frameworku Scrapy, który uzupełnił ich składnie o dodatkowe możliwości. Wykorzystanie niektórych selektorów poza Scrapym będzie więc niemożliwe.
XPath zazwyczaj w każdej bibliotece obsługiwane jest w takim sam sposób, dzięki czemu jest przenaszalne nawet pomiędzy technologiami.
Komfort korzystania
Mimo trudno początków korzystanie z narzędzia jest naprawdę proste i przyjemne. Sam właściwie korzystam już tylko z tego języka.
Jedynym wyjątkiem są sytuacje, w których selektor XPath zająłby 2 linijki, a selektor CSS załatwi to w krótkim wyrażeniu.
Wady XPath
Wysoki próg wejścia
Początkowo narzędzie naprawę odstrasza. W porównaniu do selektorów CSS ta metoda jest znacznie trudniejsza i znacznie mniej używana w innych technologiach. Trudności w korzystaniu sprawia również specyficzna składnia
Specyficzna składnia
Składnia XPath jest dość specyficzna i w pewnych momentach tekst konieczny do napisania staje się naprawdę długi i musimy ciąć go na kilka linijek. Poniżej przykład:
data = response.xpath(
".//div[contains(@class, 'content-block-data')]/@span[contains(text(), 'forward to')]/a[contains(@href, '/post/')]/@href"
).get()
Brak wsparcia w niektórych bibliotekach
Selektory nie są wspierane we wszystkich bibliotekach. Przykładem jest bardzo popularne w web scrapingu BeautifulSoup. Nie jest to jednak duży problem, gdyż zamiast tego możesz skorzystać między innymi z lxml.
Jak korzystać z XPath?
Pokażę to na przykładzie:
.//h1[@class="entry-title"]//text()
Symbol kropki i ukośników na początku .//
oznacza, że chcemy pobierać dane, zaczynając od obecnego znacznika i pobierać wszystko, co pasuje.
Zazwyczaj parsować będziemy cały kod. Jeżeli użylibyśmy dwóch kropek, parsowalibyśmy znacznik rodzic. Pojedynczą kropkę można pominąć, ja jednak dodaję ją dla czytelności (kwestia przyzwyczajenia).
Dalej wskazujemy element po nazwie znacznika, a w naszym przypadku znacznika HTML. Listę wszystkich znaczników element znajdziesz np. w poradniku Mozilli.
Najważniejszym elementem składni właściwie jest to, co się dzieje w nawiasie kwadratowym. Wskazujemy tam bezpośredni warunek, jaki może powinien być spełniony. W podanym przykładzie szukamy wszystkich h1, które mają klasę o DOKŁADNEJ wartości entry-title
.
UWAGA! W przypadku atrybutu class składnia ta może nie działać na wielu stronach. Wynika to z faktu, że na atrybut class może składać się z klas elementów znajdujących się wyżej na drzewie, tak jak tutaj:
Selektory CSS poradzą sobie z takim zapisem, jednak w przypadku w omawianym przykładzie lepiej użyć funkcji contains:
.//h1[contains(@class, "entry-title")]//text()
Po zamknięciu nawiasu występują ponownie dwa ukośniki //
, które oznaczają, że pobieramy elementy w dół, niezależnie jak bardzo głęboko w strukturze drzewa się znajdują. Jeżeli użylibyśmy jednego ukośnika, oznaczałoby to pobranie jedynie elementu poniższego.
Żeby to zobrazować wyboraźmy sobie prostą strukturę:
<div>
<a href="#">
Button text
</a>
</div>
Jak będzie wyglądało tutaj użycie dwóch lub jednego ukośnika?
>>> .//div/text()
None
>>> .//div//text()
['Button text']
>>> .//div/a/text()
['Button text']
Dalszy element w przykładzie jak już pewnie wiesz pobiera tekst wewnątrz znacznika
Zamiast tego, możemy pobrać wartość innego parametru stosując symbol @
, np:
.//meta/@content
Poniżej pokażę kilka przykładów zastosowania XPath z opisem, które mam nadzieję Ci się przydadzą:
.//a[contains(@class, 'btn-3')]... ==> pobiera element, który w klasie zawiera konkretny tekst
.//ol/li[last()]... ==> pobiera ostatni element listy
.//ol/li[position()>1].. ==> pobiera wszystkie elementy oprócz pierwszego
.//div/a[ends-with(@href, '.json')]/@href ==> pobiera wszystkie linki, które kończą się formatem .json
Dzięki, że dotarłeś do końca tego wpisu!
Mam nadzieję, że będzie on dla Ciebie przydatny i że może chociaż trochę zachęciłem Cię do używania XPath.
Jeżeli chcesz poznać więcej przykładów to polecam Ci ściągawkę od devhints.
Pozdrawiam i do następnego!