Data Scraping #1
Nadpis může být trošku zavádějící, každopádně jsem se rozhodl pokračovat v psaní článků na blogu. Už jsem tu viděl pár článků, tak jsem si řekl, že to taky zkusím :)
Ale k věci, snad se povede nějaká série, rád bych něco napsal na téma Data Scrapingu, což zní možná trošku líp, než co se pod tím skrývá a to sice vytahovat/extrahovat data z různých zdrojů za pomoci různých technologií, a pak je dávat do nějakého rozumného (strojově čitelného) formátu. Plán je menší seriál od jednodušších věcí až po komplexnější checkout procesy. Většinu budu psát v pythonu a doufám, že většina bude pochopitelná, kdyby ne, rád zodpovím v komentářích. Nebo se nebojte tweetnout na @Twistacz :)
Tak začněme trošku zlehka. Hledání příkladů je vždycky nejtěžší, proto jsem čistě náhodou našel náhodný eshop http://www.miravel.cz/, řekněme, že bychom třeba chtěli získat seznam všech lubrikačních gelů — proč ne :)
Mrkneme na stránky a zjistíme, že nás čeká taky nějaké stránkování, naštěstí je jako většinou vyřešené argumentem v url
?vp-page=?
Tak tedy, nejdřív si uděláme skeleton, kde si načteme první stránku kategorie.
Začneme tím, že si vytvoříme složku, ve které si vytvoříme virtual environment (pokud netušíte o co jde, více informací tady — http://docs.python-guide.org/en/latest/dev/virtualenvs/) a nainstalujeme knihovnu requests, která nám pomůže s dotazy.
$ virtualenv venv # vytvoreni virtual envu
$ . venv/bin/activate.fish # aktivace
$ pip install requests # instalace knihovny
Řekněme, že základ by mohl vypadat asi takto:
# -*- coding: utf-8 -*-
import requests
def main():
base_url = “http://www.miravel.cz/lubrikacni-gely/"
print(requests.get(base_url).content)
if __name__ == ‘__main__’:
main()
Tak se dostaneme k základnímu html. Teď by se hodilo vybrat si části html, co nás zajímají. Na to nám poslouží knihovna Beautiful Soup. Nainstalujeme jednoduše:
$ pip install beautifulsoup4
Kód bude vypadat nějak takhle:
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
def main():
base_url = "http://www.miravel.cz/lubrikacni-gely/"
content = requests.get(base_url).content
soup = BeautifulSoup(content, "html.parser")
products = soup.find_all("div", "productPreview")
for product in products:
product_link = product.find("a")
name = product_link.text
url = product_link.get("href")
price = product.find("div", "price").text.strip("\n")
text = "{} - {} - {}".format(name, url,price)
print(text)
if __name__ == '__main__':
main()
Výsledkem pak bude výpis názvů, url a ceny. Trošku se mrkneme na detaily.
content = requests.get(base_url).content
soup = BeautifulSoup(content, "html.parser")
Tohle by mělo být docela self-describing, každopádně v krátkosti. Načteme základní url první stránky a její obsah si uložíme do proměnné content, kterou následně hodíme právě zmíněné knihovně BeautifulSoup, abychom se jí mohli dotazovat.
products = soup.find_all("div", "productPreview")Vytáhneme si všechny divy s třídou productPreview, abychom skrz ně mohli iterovat.
for product in products:
product_link = product.find("a")
name = product_link.text
url = product_link.get("href")
price = product.find("div", "price").text.strip("\n")
text = "{} - {} - {}".format(name, url,price)
print(text)
A nakonec, pro každý produkt v kolekci si vytáhneme odkaz, což je první link, který jsme našli. Jméno, což je text onoho linku, a nakonec cenu, kterou najdeme v nadřazeném prvku (.productPreview) a v něm div s třídou price. Cenu navíc ještě osekáme o nové řádky, zformátujeme a vypíšeme, voila :)
Lubrikační gel Lona — základní — /23361-lubrikacni-gel-lona-zakladni.html — 119 Kč
Lubrikační gel lona — dezinfekční — /23349-lubrikacni-gel-lona-dezinfekcni.html — 119 Kč
Lubrikační gel Lona-jahoda — /23357-lubrikacni-gel-lona-jahoda.html — 119 Kč
...
Tak to bychom měli, teď se ještě poprat se stránkováním.
Sice je na stránce vidět stránkování jako seznam linků, ale když se podíváme blíže, tak se tam skrývá taky tlačítko “Další 12 produktů”, které vytvoří url ve tvaru
?p={a}/{b}kde a bude stránka, do které se mají produkty zobrazit a b je celkový počet stránek. Něco jako novodobý (alza)limit. Když správně dosadíme čísla do url — můžeme dostat všechny produkty na jednu stránku, což nám skript od 3 a více stránek dělá rychlejší a imo jednodušší.
Kód pro extrakci celkového počtu stránek může vypadat asi takhle:
more_products_link = soup.find("a", id="moreProductPage")
url = unquote(more_products_link.get("href"))
total = url[url.rindex("/")+1:]kdy unquote je funkce z modulu urllib.parse, která nám dekóduje speciální znaky v url, a pak poslední řádek vezme poslední výskyt pravého lomítka a extrahuje zbytek — tedy zbyde jen poslední číslo — což je celkový počet stránek.
Bude navíc potřeba přidat nějaký kód, abychom udělali další request na všechny produkty, a bylo by dobré si výstup uložit do něčeho, s čím se dá pracovat — třeba do csv. A nakonec ještě trošku rozházet do funkcí aby byl kód přehlednější.
Výsledek hodím do gistu, aby to bylo čitelnější.
A hotovo! Doufám, že se článek první série líbil. Případné postřehy nebo tipy na pokračovaní klidně nechte v komentářích.
Druhý díl který se věnuje práci se session je k nalezdnutí zde.