Praktyczna wiedza, może się przydać w wielu sytuacjach. Do tej pory robiliśmy wymyślone przykłady. W tym przykładzie zobaczymy jak we współpracy z Amelia.app ściągnęliśmy wszystkie ogłoszenia o wolontariacie ze strony z ofertami tak żeby zasilić ich silnik łączenia potrzebujących z wolontariuszami.
Nawiązanie do już istniejącego artykułu o webscrapingu
Zaczynamy
Wchodząc na stronę https://ogloszenia.ngo.pl/wolontariat/oferuje widzimy listę inicjatyw które potrzebują wolontariuszy. Chcielibyśmy regularnie odwiedzać tę stronę i ściągać inicjatywy które powstają i zasilać nią aplikację https://amelia.app/
Badanie strony
Pierwszym etapem zbierania danych ze strony jest zrozumienie jej struktury. Stąd korzystamy z opcji przeglądarki klikając prawym klawiszem myszy na element na stronie i wybieramy opcje „zbadaj”
Dzięki temu możemy zrozumieć jak „nazywa” się dany element żeby zlokalizować go w strukturze strony i znaleźć jego identyfikator.
Wiemy w takim razie, aby wyciągnąć dane o pojedynczej inicjatywie skorzystamy z identyfikatora „class”: „pv2 pv3-ns bb b–light-gray” (w kodzie programu wytłumaczymy jak z tego skorzystać)
My natomiast chcielibyśmy też wyciągnąć wszystkie inne inicjatywy zarówno z Dzisiaj jak i z innych dni, stąd poszukamy elementu wyżej który w sobie zawiera wszystkie pojedyncze inicjatywy
Widzimy, że element który grupuje wszystkie inicjatywy charakteryzuje się identyfikatorem „class”: „relative mb5 nt3” (w kodzie programu wytłumaczymy jak z tego skorzystać)
Tworzenie skryptu
W tym przykładzie skorzystamy z biblioteki requests i biblioteki BeautifulSoup:
import requests from bs4 import BeautifulSoup
Następnie wejdziemy na stronę i pobierzemy jej wszystkie dane za pomocą metody requests.get :
#sciagnij strone z ofertami start_url = "https://ogloszenia.ngo.pl/wolontariat/oferuje" download_html = requests.get(start_url)
Przygotujemy ściągnięte dane do wyszukiwania potrzebnych przez nas elementów:
soup = BeautifulSoup(download_html.text) with open('downloaded.html', 'w', encoding="utf-8") as file: file.write(soup.prettify())
Chcemy znaleźć wszystkie istniejące ogłoszenia na stronie, także pierwszym krokiem będzie stworzenie listy wszystkich grup ogłoszeń które strona dzieli na „Dzisiejsze, itd”, po naszym przebadaniu strony wiemy, że zidentyfikować możemy je za pomocą ich nazwy, prosta metoda findAll z biblioteki BeautifulSoup zwraca nam listę ich wszystkich:
#znajdz wszystkie kontenery z ogloszeniami mydivs = soup.findAll("div", {"class": "relative mb5 nt3"})
W ramach jednej grupy zgłoszeń możemy wyszukać wszystkie za pomocą tej samej metody, korzystając z identyfikatora pojedynczego ogłoszenia:
moje_ogloszenia = day.find_all("div", {"class": "pv2 pv3-ns bb b--light-gray"})
Wyciąganie danych z pojedynczego ogłoszenia
Udało nam się już zlokalizować pojedyncze ogłoszeni patrząc na jego dane, chcielibyśmy wyciągnąć z niego:
- Tytuł
- Opis
- Link
- Lokalizację
przechodzimy ten sam proces dla ogłoszenia który przeszliśmy dla całej strony, identyfikując nazwy poszczególnych pól które przechowują potrzebne nam informację
link = ogloszenie.find('a', href=True) title = link.span.string link = link['href'] location_raw = ogloszenie.find("div", {"class": "f6-xl"}) location = str(location_raw.string).strip() location = location[:-1]
Sam opis będzie trochę trudniej wyciągnąć gdyż znajduję się już w treści samego ogłoszenia, natomiast nie jest nam to straszne bo to jedynie powtórzenie tego samego mechanizmu, który już przeszliśmy
start_url = link download_html = requests.get(start_url) soup_pojedyncze = BeautifulSoup(download_html.text) all_text = soup_pojedyncze.findAll("div", {"class": "lh-copy cms cms-colors f5-ns"}) akapity = all_text[0].find_all("p") description = "" for p in akapity: description = description+p.text #print("akapity=", p.text) description = description[0:254]
Na końcu skryptu możemy dodać wypisanie wszystkich zmiennych i zobaczyć, że dobrze wyciągnęliśmy wszystkie informację:
print("desc=",description) print("title=", title) print("link=", link) print("location=", location)
Powtórzenie tej samej czynności dla wszystkich elementów
Nauczyliśmy się już pętli „for”, którą można znaleźć pod tym linkiem http://analityk.edu.pl/python-petla-for-oraz-while/
Wykorzystamy ją teraz zarówno do przejścia przez wszystkie ogłoszenia w ramach jednej grupy ogłoszeń jak i przez wszystkie grupy na samej stronie, otrzymując w ten sposób wszystkie ogłoszenia!
Dla każdego dnia na liście wszystkich elementów grupujących znajdziemy wszystkie ogłoszenia
for day in mydivs: moje_ogloszenia = day.find_all("div", {"class": "pv2 pv3-ns bb b--light-gray"})
Następnie dla każdego z tych ogłoszeń wyszukamy wszystkie nasze potrzebne informację:
for ogloszenie in moje_ogloszenia:
Cały, połączony kod wyglądać będzie następująco:
import requests from bs4 import BeautifulSoup #sciagnij strone z ofertami start_url = "https://ogloszenia.ngo.pl/wolontariat/oferuje" download_html = requests.get(start_url) soup = BeautifulSoup(download_html.text) with open('downloaded.html', 'w', encoding="utf-8") as file: file.write(soup.prettify()) #znajdz wszystkie kontenery z ogloszeniami mydivs = soup.findAll("div", {"class": "relative mb5 nt3"}) #pierwszy element z listy mydivs to najwyzej ustawiony zbior(kontener na zgloszenia" ogloszenna stronie for day in mydivs: moje_ogloszenia = day.find_all("div", {"class": "pv2 pv3-ns bb b--light-gray"}) #moje_ogloszenia to wszystkie ogloszenia juz ze zbioru np. "Dodane Wczesniej" albo "Dodane przedwczoraj" for ogloszenie in moje_ogloszenia: print("-----------------------NOWE OGLOSZENIE----------------------") link = ogloszenie.find('a', href=True) title = link.span.string link = link['href'] location_raw = ogloszenie.find("div", {"class": "f6-xl"}) location = str(location_raw.string).strip() location = location[:-1] start_url = link download_html = requests.get(start_url) soup_pojedyncze = BeautifulSoup(download_html.text) all_text = soup_pojedyncze.findAll("div", {"class": "lh-copy cms cms-colors f5-ns"}) akapity = all_text[0].find_all("p") description = "" for p in akapity: description = description+p.text #print("akapity=", p.text) description = description[0:254] print("desc=",description) print("title=", title) print("link=", link) print("location=", location)
A efekt końcowy:
Podsumowując
Ucząc się programować i korzystać z języka python warto pomyśleć jak możemy go użyć na co dzień , a nie koniecznie jedynie w pracy. Ucząc się webscrapingu, analizy danych czy wizualizacji wykresów przygotowujemy się również na sytuację w których możemy z czasem bezinteresownie pomóc swoją wiedzą.
Cały kod można znaleźć w naszym repozytorium na githubie:
https://github.com/AnalitykEduPL/Python/blob/master/WebScrapingForCorona.ipynb