Menu Zamknij

Web scraping i MySQL część 8 – wyjątki try i except, modelowanie czytelnych tabel

Przyjrzyjmy się wszystkim plikom z tabelami, które zapisaliśmy w poprzedniej części. Powinny wyglądać trochę tak jak poniżej:

odmiana1GatunekKukurydza– nazwa angielskaMaize– nazwa botanicznaZea mays L.
ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek
odmiana1– ostatecznaAramillo– hodowlanaLEKG 1215– w badaniachLEKG 1215Status nazwyZ – ZatwierdzonaData zgł. nazwy05.06.2006Data opubl. nazwy15.07.2006Data zatw. nazwy22.02.2007
ctl00_ContentPlaceHolderZawartosc_DetailsViewNazwy
odmiana1Status w krajowym rejestrze (KR)R – Odmiana wpisanaStatus w księdze ochrony (KO)Zgoda na obrót
ctl00_ContentPlaceHolderZawartosc_DetailsViewStatusy
odmiana1zachowujący654Lima, spółka jaskółkaMordor 16ZS – 15-340 Złe Śródziemiehodowca654Lima, spółka jaskółkaMordor 16ZS – 15-340 Złe Śródziemiereprezentant554Saruman ltd. oddział pod lasemul. Entów 164SR – 61-168 Buk
ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR

Pliki są w porządku. Widać, że dane w każdym pliku dotyczą jednej odmiany. Co prawda nasz tajemniczy klient musiałby sobie to posklejać jakoś do kupy i przetworzyć do bardziej czytelnej formy. Z drugiej strony im lepiej przygotujemy pliki tym większa satysfakcja a zadowolony zleceniodawca może nam zrobić skuteczny szeptany marketing. Zacznijmy od dodania pozostałych odmian do naszej listy.

Do wykonania tego zadania przyda się zastosowanie pętli. Domyślamy się, że adresy stron z odmianami nadawane są według schematu odmiana1, odmiana2 itd. Zacznijmy od napisania instrukcji iteracyjnej for, która wygeneruje nam potrzebne adresy:

for nr in range(1, 11):
    strona = f"https://inferiordatascience.com/odmiana{nr}/"
    print(strona)

W 1 linijce zaczynamy pętlę, która będzie pod zmienną nr podstawiać liczby z zakresu 1 do 10.
W 2 linijce wykorzystujemy fstring by pod zmienną strona podstawić string z pełnym adresem strony.
W 3 linijce taki adres drukujemy. Zobaczmy efekt:

==================== RESTART: F:\python38\Web scraping 08.py ===================
https://inferiordatascience.com/odmiana1/
https://inferiordatascience.com/odmiana2/
https://inferiordatascience.com/odmiana3/
https://inferiordatascience.com/odmiana4/
https://inferiordatascience.com/odmiana5/
https://inferiordatascience.com/odmiana6/
https://inferiordatascience.com/odmiana7/
https://inferiordatascience.com/odmiana8/
https://inferiordatascience.com/odmiana9/
https://inferiordatascience.com/odmiana10/
>>>

Dobra nasza! Teraz zmień kod tak, żeby otwierał każdą stronę i podawał ile tabel znalazł. Porównaj z kodem poniżej:

from urllib.request import urlopen
from bs4 import BeautifulSoup

for nr in range(1, 11):
    strona = f"https://inferiordatascience.com/odmiana{nr}/"
    otwarta_strona = urlopen(strona)
    html = BeautifulSoup(otwarta_strona.read(), "html.parser")
    #znajdz wszystkie tabele tabelę
    tabele = html.findAll("table")
    #wydrukuj liczbę tabel
    print(len(tabele))

Nic niezwykłego w programie nie zostało zapisane. Po po prostu go uruchommy:

==================== RESTART: F:\python38\Web scraping 08.py ===================
6
6
6
7
6
Traceback (most recent call last):
  File "F:\python38\Web scraping 08.py", line 6, in <module>
    otwarta_strona = urlopen(strona)
  File "F:\python38\lib\urllib\request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "F:\python38\lib\urllib\request.py", line 531, in open
    response = meth(req, response)
  File "F:\python38\lib\urllib\request.py", line 640, in http_response
    response = self.parent.error(
  File "F:\python38\lib\urllib\request.py", line 569, in error
    return self._call_chain(*args)
  File "F:\python38\lib\urllib\request.py", line 502, in _call_chain
    result = func(*args)
  File "F:\python38\lib\urllib\request.py", line 649, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 404: Not Found
>>> 

Błąd! Co tu się wydarzyło? Jaki błąd nam się przytrafił powie ci ostatnia linijka: urllib.error.HTTPError: HTTP Error 404: Not Found. W uproszczeniu ten błąd informuje, że nie udało się odnaleźć strony. Szybkie policzenie ile razy pętla wykonała się poprawnie zobaczysz, że nie udało się wejść na https://inferiordatascience.com/odmiana6/. Sprawdź w przeglądarce czy taka strona istnieje. Sprawdziłeś? Super, to teraz trzeba znaleźć sposób, żeby nasz program nie zakańczał się przy każdej nieznalezionej stronie.

Z biblioteki urllib musimy zaimportować obsługę błędu HTTPError, dokładnie to nam podpowiada ostatnia linijka błędu urllib.error.HTTPError. Prócz biblioteki, musisz jeszcze nauczyć się, jak program ma takie błędy obsługiwać. Popatrz na poniższy kod:

from urllib.request import urlopen
from urllib.error import HTTPError

strona = "https://inferiordatascience.com/odmiana6/"
try:
    otwarta_strona = urlopen(strona)
except HTTPError:
    print(f"brak strony: {strona}")

W 2 linijce z modułu urllib.error importujemy HTTPError
W 5 linijce piszemy słowo kluczowe try: czyli tłumacząc na nasze spróbuj. Po try pojawia się dwukropek. To co ma być spróbowane napiszesz w kolejnej, wciętej o jeden poziom linijce.
W 6 linijce próbujemy otworzyć stronę. W tym wypadku wiemy już, że takiej strony nie ma. Gdy próba się nie powiedzie i kod programu wygeneruje błąd HTTPError to…
W 7 linijce użyjemy obsługi wyjątku poprzez użycie słowa kluczowego except. Prócz except który jest na tej samej głębokości wcięty co try, musimy napisać jakiego błędu wyjątek ma dotyczyć i na końcu linijki stawiamy dwukropek.
W 8, wciętej linijce (linijka wyżej kończyła się dwukropkiem, wcięcie jest niezbędne) piszemy co ma się wydarzyć, gdy nasz program natknie się na błąd HTTPError. W naszym wypadku pojawi się komunikat o braku strony.
Uruchom program i zobacz jak działa:

==================== RESTART: F:\python38\Web scraping 08.py ===================
brak strony: https://inferiordatascience.com/odmiana6/
>>> 

Obsługa błędów jest przydatna z wielu względów. Gdybyś chciał sprawdzić ile istnieje trzyliterowych domen kończących się na .com, możesz użyć do tego skryptu w Pythonie i obsługi wyjątków. Przeanalizuj poniższy program:

from urllib.request import urlopen
from urllib.error import HTTPError, URLError
litery = ["a","b","c"]

#ułóż 3 literowy ciąg z dostępnych liter
for pierwsza_litera in litery:
    for druga_litera in litery:
        for trzecia_litera in litery:
            domena = f"{pierwsza_litera}{druga_litera}{trzecia_litera}"
            #wygeneruj link
            strona = f"https://{domena}.com/"
            #sprawdź czy stronę da się otworzyć
            try:
                otwarta_strona = urlopen(strona)
                print(f"Strona o adresie {strona} istnieje!")
            except HTTPError:
                print(f"Nie odnaleziono strony: {strona}")
            except URLError:
                print(f"Nie odnaleziono strony: {strona}")

W 2 linijce dodałem do naszego programu drugi, popularny błąd do obsługi.
W 3 linijce tworzę listę trzech pierwszych liter alfabetu.
Następnie pętle for wybierają wszystkie możliwe kombinacje liter, które następnie są wykorzystane do wygenerowania adresów stron. Na koniec program sprawdza czy stronę da się otworzyć i informuje nas o tym. Na dzień 2020-09-27 wynik działania programu jest taki:

Strona o adresie https://aaa.com/ istnieje!
Nie odnaleziono strony: https://aab.com/
Strona o adresie https://aac.com/ istnieje!
Nie odnaleziono strony: https://aba.com/
Strona o adresie https://abb.com/ istnieje!
(...)

Rozumiejąc już, jak działa obsługa wyjątków sprawdźmy czy uda nam się znaleźć 10 odmian. Zmodyfikujmy program tak, by obsłużył wyjątek:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup

for nr in range(1, 11):
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele tabelę
        tabele = html.findAll("table")
        #wydrukuj liczbę tabel
        print(len(tabele))
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

Program nie zmienił się jakoś dramatycznie.
W 6 linijce zaczyna się try: i w jego obrębie próbujemy pobrać długości tabel.
Linijki 14-15 obsługują błędy, które, jak wiemy, na pewno się pojawią. Zauważ, że mimo tych błędów program wykona się do samego końca.

Efekt działania wygląda teraz tak:

==================== RESTART: F:\python38\Web scraping 08.py ===================
6
6
6
7
6
Nie odnaleziono strony: https://inferiordatascience.com/odmiana6/
6
Nie odnaleziono strony: https://inferiordatascience.com/odmiana8/
5
5
>>> 

Coraz więcej wiemy o stronach z odmianami. Wiemy, że zawierają różną liczbę tabel i że nie ma dwóch stron z odmianami. Czy to oznacza, że ktoś bezpowrotnie usunął dane o odmianie 6 i 8? Zwiększmy zakres przeszukiwanych stron do 15:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup

for nr in range(1, 16):
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele tabelę
        tabele = html.findAll("table")
        #wydrukuj liczbę tabel
        print(len(tabele))
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

Jedyna zmiana została wprowadzona w 5 linijce, w której zwiększyliśmy zakres funkcji range(). Zobaczmy efekt:

==================== RESTART: F:\python38\Web scraping 08.py ===================
6
6
6
7
6
Nie odnaleziono strony: https://inferiordatascience.com/odmiana6/
6
Nie odnaleziono strony: https://inferiordatascience.com/odmiana8/
5
5
5
5
Nie odnaleziono strony: https://inferiordatascience.com/odmiana13/
Nie odnaleziono strony: https://inferiordatascience.com/odmiana14/
Nie odnaleziono strony: https://inferiordatascience.com/odmiana15/
>>> 

No i super. Mamy wszystkie 10 odmian! Nasz zleceniodawca będzie wniebowzięty. Spróbujmy teraz zapisać tabele wszystkich odmian do plików. To nie powinno być trudne, skoro mamy kod, który zapisuje tabele dla jednej odmiany, umieścimy go w pętli, dodamy obsługę wyjątków i zaczniemy dopisywać kolejne linijki tabeli dla kolejnych odmian. Zabierzmy się za to:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv

#dla zakresu 12 stron
for nr in range(1, 13):
    #sprawdź czy strona istnieje
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele tabelę
        tabele = html.findAll("table")
        #dla każdej tabeli
        for tabela in tabele:
            #pobierz jej id
            tytul_tabeli = tabela.get("id")
            #i jeśli id nie jest puste
            if tytul_tabeli != None:
                #przygotuj listę z identyfikatorem odmiany
                komorki= [f"odmiana{nr}"]
                #dodaj do listy wszystkie znajdujące się w tabeli dane
                for komorka_wiersza in tabela.findAll("td"):
                    komorki.append(komorka_wiersza.get_text().replace("\n", ''))
                #zapisz listę tabeli do pliku i nazwie = id
                with open(f"{tytul_tabeli}.csv", "w") as plik:
                    csv.writer(plik).writerow(komorki)
    #jeśli strony nie ma, poinformuj
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

W 7 linijce definiujemy sobie zakres otwieranych stron.
W 9 linijce zaczynamy od obsługi wyjątków.
Reszta programu jest prawie bez zmian. Uruchom program i zobacz jak wyglądają pliki wynikowe. Po otwarciu zobaczysz, że jest tam zapisana tylko jedna odmiana. Dlaczego nie zapisały się wszystkie?

Różnica pomiędzy write a append

W 27 linijce kodu prosimy program, żeby zapisał dane do pliku i program robi to za każdym razem, gdy wchodzi w pętlę. Argument "w" powoduje, że przy kolejnym wejściu w pętlę, poprzednia wartość zostaje nadpisana nową wartością i zapisana. Musimy zastąpić argument "w" argumentem "a" (append), który powoduje, że do pliku będą dopisywane nowe wartości bez ingerencji w poprzednie. Usuń pliki i popraw kod programu:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv

#dla zakresu 12 stron
for nr in range(1, 13):
    #sprawdź czy strona istnieje
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele tabelę
        tabele = html.findAll("table")
        #dla każdej tabeli
        for tabela in tabele:
            #pobierz jej id
            tytul_tabeli = tabela.get("id")
            #i jeśli id nie jest puste
            if tytul_tabeli != None:
                #przygotuj listę z identyfikatorem odmiany
                komorki= [f"odmiana{nr}"]
                #dodaj do listy wszystkie znajdujące się w tabeli
                for komorka_wiersza in tabela.findAll("td"):
                    komorki.append(komorka_wiersza.get_text().replace("\n", ''))
                #zapisz listę tabeli do pliku i nazwie = id
                with open(f"{tytul_tabeli}.csv", "a") as plik:
                    csv.writer(plik).writerow(komorki)
    #jeśli strony nie ma, poinformuj
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

I sprawdź jak teraz wyglądają pliki w edytorze tekstowym, np. plik ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek.csv:

odmiana12,Gatunek,Melon,– nazwa angielska,Melon,– nazwa botaniczna,Cucumis melo L.


odmiana1,Gatunek,Kukurydza,– nazwa angielska,Maize,– nazwa botaniczna,Zea mays L.


odmiana2,Gatunek,Kukurydza,– nazwa angielska,Maize,– nazwa botaniczna,Zea mays L.
(...)

Fajnie, ale mamy niepotrzebne, dodatkowe puste linijki przeplatające te z tekstem. Dodajmy argument newline = "" do funkcji open():

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv

#dla zakresu 12 stron
for nr in range(1, 13):
    #sprawdź czy strona istnieje
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele tabelę
        tabele = html.findAll("table")
        #dla każdej tabeli
        for tabela in tabele:
            #pobierz jej id
            tytul_tabeli = tabela.get("id")
            #i jeśli id nie jest puste
            if tytul_tabeli != None:
                #przygotuj listę z identyfikatorem odmiany
                komorki= [f"odmiana{nr}"]
                #dodaj do listy wszystkie znajdujące się w tabeli
                for komorka_wiersza in tabela.findAll("td"):
                    komorki.append(komorka_wiersza.get_text().replace("\n", ''))
                #zapisz listę tabeli do pliku i nazwie = id
                with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
                    csv.writer(plik).writerow(komorki)
    #jeśli strony nie ma, poinformuj
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

Usuń pliki i uruchom program jeszcze raz. Sprawdź wygląd plików, tak powinien wyglądać początek pliku ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek.csv:

odmiana1,Gatunek,Kukurydza,– nazwa angielska,Maize,– nazwa botaniczna,Zea mays L.
odmiana2,Gatunek,Kukurydza,– nazwa angielska,Maize,– nazwa botaniczna,Zea mays L.
odmiana3,Gatunek,Pszenica zwyczajna ozima,– nazwa angielska,Winter Wheat,– nazwa botaniczna,Triticum aestivum L.
odmiana4,Gatunek,Pszenica zwyczajna ozima,– nazwa angielska,Winter Wheat,– nazwa botaniczna,Triticum aestivum L.
odmiana5,Gatunek,Pszenica zwyczajna ozima,– nazwa angielska,Winter Wheat,– nazwa botaniczna,Triticum aestivum L.
(...)

Nie ma tragedii, co? Można już taki efekt przekazać zleceniodawcy, ale to wciąż bardzo pokraczne pliki. Dla każdej linijki możesz zauważyć identyczne „nagłówki” i dane dla każdego z nagłówków. Plik byłby czytelniejszy, gdyby miał taką postać:

NrGatunekNazwa angielskaNazwa botaniczna
odmiana1KukurydzaMaizeZea mays L.
odmiana2KukurydzaMaizeZea mays L.
odmiana3Pszenica zwyczajna ozimaWinter WheatTriticum aestivum L.
Docelowy kształt tabeli „Gatunek”

Przygotujmy tabele ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek w ten sposób. Zacznijmy od wydrukowania każdego elementu tabeli z 1 odmiany. Do tego celu przerobimy co nieco program:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv

tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek"
#dla pierwszej odmiany
for nr in range(1, 2):
    #sprawdź czy strona istnieje
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele
        tabele = html.findAll("table")
        #dla każdej tabeli
        for tabela in tabele:
            #pobierz jej id
            tytul_tabeli = tabela.get("id")
            #i jeśli id odpowiada zmiennej tabela_gatunek
            if tytul_tabeli == tabela_gatunek:
                #wydrukuj tekst wszystkich komórek
                 for komorka_wiersza in tabela.findAll("td"):
                     print(komorka_wiersza.get_text())
                     
    #jeśli strony nie ma, poinformuj
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

W 6 linijce dodajemy sobie zmienną, zawierającą id tabeli.
W 8 linijce ograniczamy pętlę tylko do otwarcia jednej strony
W 21 linijce wybieramy ze wszystkich tabeli tylko jedną, o id równym ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek.
Linijki 22 i 23 odpowiadają za pobranie zawartości komórek i wydrukowaniu ich zawartości. Zobaczmy czy program zachowuje się poprawnie:

==================== RESTART: F:\python38\Web scraping 08.py ===================
Gatunek
Kukurydza
– nazwa angielska
Maize
– nazwa botaniczna
Zea mays L.
>>> 

Teraz musimy jakoś wyciągnąć nagłówki i zapisać je na liście. Łatwo można zauważyć, że wartości, które mają stać się nagłówkami są co drugą linijkę a w sumie tych wartości jest 6. Wydrukujmy same wartości, które staną się nagłówkami:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv

tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek"
#dla pierwszej odmiany
for nr in range(1, 2):
    #sprawdź czy strona istnieje
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele
        tabele = html.findAll("table")
        #dla każdej tabeli
        for tabela in tabele:
            #pobierz jej id
            tytul_tabeli = tabela.get("id")
            #i jeśli id odpowiada zmiennej tabela_gatunek
            if tytul_tabeli == tabela_gatunek:
                for indeks in range(0,6,2):
                    for komorka_wiersza in tabela.findAll("td")[indeks]:
                        print(komorka_wiersza)
                     
    #jeśli strony nie ma, poinformuj
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

W 22 linijce dodajemy pętlę for, która pod zmienną indeks podstawia wartości 0,2,4. Dlaczego? Ano funkcja range() ma w naszym przypadku 3 argumenty, liczbę początkową, liczbę końcową i „krok” czyli o ile zwiększa się kolejna liczba w zakresie. Możesz sprawdzić zasadę działania bezpośrednio w terminalu:

>>> for indeks in range(0,6,2):
	print(indeks)

	
0
2
4
>>> 

W linijce 23 tworzona jest lista komórek a my podając indeks w kwadratowych nawiasach wybieramy tylko te wartości, które nas interesują podając odpowiedni indeks. Zastosujmy taki sposób do naszego programu:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv

tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek"
#dla pierwszej odmiany
for nr in range(1, 2):
    #sprawdź czy strona istnieje
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele
        tabele = html.findAll("table")
        #dla każdej tabeli
        for tabela in tabele:
            #pobierz jej id
            tytul_tabeli = tabela.get("id")
            #i jeśli id odpowiada zmiennej tabela_gatunek
            if tytul_tabeli == tabela_gatunek:
                for indeks in range(0,6,2):
                    for komorka_wiersza in tabela.findAll("td")[indeks]:
                        print(komorka_wiersza)
                     
    #jeśli strony nie ma, poinformuj
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

Zauważ, że nie musiałeś używa funkcji get_text() i za diabła nie wiem dlaczego. Jeśli ty wiesz, napisz w komentarzu! Zobaczmy efekt:

==================== RESTART: F:\python38\Web scraping 08.py ===================
Gatunek
– nazwa angielska
– nazwa botaniczna
>>> 

Teraz te tytuły musimy umieścić w pliku .csv. Już wiemy jak to zrobić. Sprawdź czy wyszło ci coś podobnego do mojego kodu:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv

tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek"
#dla pierwszej odmiany
for nr in range(1, 2):
    #sprawdź czy strona istnieje
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele
        tabele = html.findAll("table")
        #dla każdej tabeli
        for tabela in tabele:
            #pobierz jej id
            tytul_tabeli = tabela.get("id")
            #i jeśli id odpowiada zmiennej tabela_gatunek
            if tytul_tabeli == tabela_gatunek:
                komorki= [f"id_odmiany"]
                for indeks in range(0,6,2):
                    for komorka_wiersza in tabela.findAll("td")[indeks]:
                        komorki.append(komorka_wiersza.replace("\n", ''))
                #zapisz listę tabeli do pliku i nazwie = id
                with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
                    csv.writer(plik).writerow(komorki)
                     
    #jeśli strony nie ma, poinformuj
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

Pozostaje dodanie pobrania danych do naszego nagłówka. Można zrobić to tak:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv

tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek"
#dla pierwszej odmiany
for nr in range(1, 2):
    #sprawdź czy strona istnieje
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele
        tabele = html.findAll("table")
        #dla każdej tabeli
        for tabela in tabele:
            #pobierz jej id
            tytul_tabeli = tabela.get("id")
            #i jeśli id odpowiada zmiennej tabela_gatunek
            if tytul_tabeli == tabela_gatunek:
                komorki= [f"id_odmiany"]
                for indeks in range(0,6,2):
                    for komorka_wiersza in tabela.findAll("td")[indeks]:
                        komorki.append(komorka_wiersza.replace("\n", ''))
                #zapisz listę tabeli do pliku i nazwie = id
                with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
                    csv.writer(plik).writerow(komorki)
                    komorki= [f"odmiana{nr}"]
                for indeks in range(1,6,2):
                    for komorka_wiersza in tabela.findAll("td")[indeks]:
                        komorki.append(komorka_wiersza.replace("\n", ''))
                #zapisz listę tabeli do pliku i nazwie = id
                with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
                    csv.writer(plik).writerow(komorki)
                     
    #jeśli strony nie ma, poinformuj
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

W linijkach 22 i 29 dodajemy do listy te informacje, których nie pobieramy z tabeli, czyli nagłówek kolumny „id” a potem numer odmiany.
W linijkach 23-28 pętla for zapisuje nagłówki do pliku.
W linijkach 30-35 pętka for zapisuje dane do pliku.
Sprawdź czy efekt jest zadowalający. I powinien być zadowalający do momentu zwiększenia zasięgu pętli do wszystkich odmian:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv

tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek"
#dla pierwszej odmiany
for nr in range(1, 13):
    #sprawdź czy strona istnieje
    try:
        strona = f"https://inferiordatascience.com/odmiana{nr}/"
        otwarta_strona = urlopen(strona)
        html = BeautifulSoup(otwarta_strona.read(), "html.parser")
        #znajdz wszystkie tabele
        tabele = html.findAll("table")
        #dla każdej tabeli
        for tabela in tabele:
            #pobierz jej id
            tytul_tabeli = tabela.get("id")
            #i jeśli id odpowiada zmiennej tabela_gatunek
            if tytul_tabeli == tabela_gatunek:
                komorki= [f"id_odmiany"]
                #zapisz nagłówki tabeli
                for indeks in range(0,6,2):
                    for komorka_wiersza in tabela.findAll("td")[indeks]:
                        komorki.append(komorka_wiersza.replace("\n", ''))
                #zapisz listę tabeli do pliku i nazwie = id
                with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
                    csv.writer(plik).writerow(komorki)
                    komorki= [f"odmiana{nr}"]
                #zapisz treść tabeli
                for indeks in range(1,6,2):
                    for komorka_wiersza in tabela.findAll("td")[indeks]:
                        komorki.append(komorka_wiersza.replace("\n", ''))
                #zapisz listę tabeli do pliku i nazwie = id
                with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
                    csv.writer(plik).writerow(komorki)
                     
    #jeśli strony nie ma, poinformuj
    except HTTPError:
        print(f"Nie odnaleziono strony: {strona}")

Zmiana jest tylko w 8 linijce, pewnie już domyślasz się efektu:

id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana1,Kukurydza,Maize,Zea mays L.
id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana2,Kukurydza,Maize,Zea mays L.
id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana3,Pszenica zwyczajna ozima,Winter Wheat,Triticum aestivum L.
id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana4,Pszenica zwyczajna ozima,Winter Wheat,Triticum aestivum L.
id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana5,Pszenica zwyczajna ozima,Winter Wheat,Triticum aestivum L.
id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana7,Melon,Melon,Cucumis melo L.
id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana9,Melon,Melon,Cucumis melo L.
id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana10,Melon,Melon,Cucumis melo L.
id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana11,Melon,Melon,Cucumis melo L.
id_odmiany,Gatunek,– nazwa angielska,– nazwa botaniczna
odmiana12,Melon,Melon,Cucumis melo L.

Nagłówki zapisywane są przy każdym wejściu na kolejną stronę. Rozwiązaniem tego problemu zajmiesz się w kolejnej lekcji.

Zadanie Domowe

Podążanie za instrukcjami, nawet jeśli je wszystkie wykonujesz samodzielnie, nie zrobi z ciebie programisty. Zadania domowe mogą wydawać się na początku trudne. Tu nie ma rozwiązania podanego na talerzu, użyj dowolnych źródeł, by znaleźć odpowiedź.

  1. Napisz program, który zliczy wszystkie linki ze strony głównej dowolnego portalu, wydrukuj treść pierwszych 20 linków
  2. Napisz program, który sprawdza czy istnieją strony mające w nazwie polskie imię (np. jan). Niech program sprawdza je z końcówkami .com i .pl oraz strony http i https (np. http://jan.com, http://jan.pl, https://jan.com, https://jan.pl). Niech program zawiera listę 6 polskich imion
0 0 votes
Ocena artykułu

0 komentarzy
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
0
Chcesz podzielić się komentarzem?x