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

http://analityk.edu.pl/web-scraping-automatyczne-sciaganie-danych-ze-stron-www/

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”

Opcja Zbadaj

Dzięki temu możemy zrozumieć jak „nazywa” się dany element żeby zlokalizować go w strukturze strony i znaleźć jego identyfikator.

Chrome podświetla nam element kiedy najeżdżamy na niego

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

Chrome podświetla nam element kiedy najeżdżamy na niego

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)
wypisanie pojedynczego ogloszenia

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