web scraping

XPath – czym jest i jak z niego korzystać?

XPath Python

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

Znacznik HTML w składni XPath

Dalej wskazujemy element po nazwie znacznika, a w naszym przypadku znacznika HTML. Listę wszystkich znaczników element znajdziesz np. w poradniku Mozilli.

Selektor w składni XPath

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:

Atrybut class w HTML

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

Pobieranie danych za pomocą XPath

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!

Tagged ,