Dziesiąta cześć i nowe wyzwania. Na stronie 1 odmiany została nam już tylko jedna tabela. Tyle już umiemy, że z zamkniętymi oczami możemy ją obsłużyć. Zaczynamy? Zaczynamy!
Najpierw sprawdźmy jak tabela się nazywa. Jej nazwę „ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR” będziemy w opisie skracać do „hodowcykr”. Ta tabela wygląda nieco inaczej. Nagłówki i treść są ułożona tak jak chcemy, nie trzeba będzie wybierać danych co drugi indeks. Nagłówki dodatkowo są umieszczone między znacznikami <th> a treść miedzy znacznikami <td>. Żeby było jeszcze ciekawiej, nazwy nagłówków nie są bezpośrednio w tagach <th>, a dodatkowo są otoczone tagami <a>. Zajmijmy się nimi na początek.
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
naglowek = tabela.findAll("a")
komorki = []
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
print(komorki)
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W 22 linijce szukamy wszystkich znaczników <a> w tabeli, wiemy, że występują tylko w nagłówku.
w 24 i 25 linijce każdą komórkę dodajemy do listy. Tutaj musimy użyć metody .get_text() (dla poprzednich 3 tabel, gdzie lokalizację danych wskazywał konkretny indeks, nie było to potrzebne).
W 26 linijce sprawdzamy czy nagłówek dodał się poprawnie do listy. Zobaczmy działanie programu:
==================== RESTART: C:\python38\Web scraping 10.py ===================
['Rodzaj', 'Kod', 'Nazwa', 'Adres']
>>>
Dodał się, jest fajnie. No to teraz zajmijmy się pozostałymi wierszami.
Ponieważ nasz program musi być jak najbardziej błędoodporny i uniwersalny, zakładamy, że tabela „hodowcykr” ma zawsze jeden wiersz nagłówka i co najmniej jeden wiersz danych. Czyli musimy nauczyć nasz program wyliczania liczby wierszy. Jak wiemy, albo właśnie się dowiadujesz, liczbę wierszy wyznacza liczba znaczników HTML <tr>. Policzmy je:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
wiersze = tabela.findAll("tr")
print(len(wiersze))
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W 22 linijce pod zmienną wiersze tworzymy listę wszystkich treści zawartych w znacznikach <tr>.
W 23 linijce drukujemy długość listy nazwanej wiersze.
Zobaczmy efekt:
==================== RESTART: C:\python38\Web scraping 10.py ===================
4
>>>
Świetnie, mamy 4 linijki – 1 linijka nagłówka i 3 linijki treści. No to teraz zapiszmy te linijki na liście. Może spróbujmy zapisać je na liście list? Zamiast zapisywać do pliku każdą linijkę z osoba, zapiszemy je za jednym razem? Oszczędzimy na tym 2 czasochłonne operacje (zapis na fizycznym nośniku jest nieporównywalnie dłuższy, niż zapis listy w pamięci Pythona).
Przygotujmy sobie najpierw jedną, długą listę ze wszystkimi danymi. Jak się okazało nagłówki były pomiędzy znacznikami <a>, treść jest pomiędzy znacznikami <td>, pewnie już wiesz jak to zrobić. Ja listę przygotowałem tak:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
naglowek = tabela.findAll("a")
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
print(komorki)
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W linijkach 22-25 i 27-32 wyszukujemy i zapisujemy na liście całą treść. Zobaczmy efekt:
['Rodzaj', 'Kod', 'Nazwa', 'Adres', 'zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie', 'hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie', 'reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']
>>>
Zgodnie z tym co wiemy, nasza tabela ma 4 wiersze, czyli musimy podzielić listę na 4 równe części. Sprawdźmy długość listy i podzielmy tę długość na 4:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
naglowek = tabela.findAll("a")
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
print((len(komorki)/4)
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W 33 linijce drukujemy wynik dzielenia i otrzymujemy:
==================== RESTART: F:/python38/Web scraping 10.py ===================
4.75
>>>
Taa, coś nie pykło. Popatrzmy na tabelę. Gdy się jej przyjrzysz, zauważysz, że jest jakaś dziwna. Mamy 4 wartości dla nagłówków: Rodzaj, Kod, Nazwa, Adres i „pustą” komórkę na końcu, która nie ma znacznika <a> a tylko <th>. Poniżej są wartości wierszy i w każdej linijce jest ich 5. Adres jest rozbity na miejscowość lub ulicę, oraz na pocztę i kod pocztowy z dodatkowym, dwuliterowym przedrostkiem. Projektant tabeli się nie popisał co? Nic na to nie poradzimy, musimy się uporać w jakiś ładny sposób z tą przeszkodą. Możemy na przykład porównać liczbę wystąpień <th> i <a> sprawdzając długość list.
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
print(f"liczba kolumn: {len(kolumny)}")
print(f"liczba nagłówków: {len(naglowek)}")
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W linijkach 23-24 pobieramy listę znaczników <th> i <a>
W linijkach 25-26 sprawdzamy długość tych list. Zobaczmy efekt:
==================== RESTART: F:\python38\Web scraping 10.py ===================
liczba kolumn: 5
liczba nagłówków: 4
>>>
Teraz wiemy co się nie zgadza w tej tabeli. Ponieważ zakładamy, że ten sam kod użyjemy w innych tabelach, nie chcemy dopisywać zmiany liczby nagłówków na stałe. Dopiszmy w naszym programie warunek, który doda „pusty” nagłówek tylko wtedy, kiedy jest to konieczne. „Pusty” nagłówek uwolni nas od problemu różnej długości list, które koniec w końcu staną się tabelą. Właściwie to ty dopisz a potem popatrz co dopisałem ja:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
print(len(komorki))
print(len(komorki)/4)
print(komorki)
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W 32 linijce dodajmy instrukcję warunkową if, która sprawdza, czy liczba nagłówków jest większa od liczby tytułów w nagłówkach. Jeśli tak to:
W 33 linijce dodajemy pusty tekst.
W linijkach 37-38 kontrolnie sprawdzamy jaka jest teraz długość listy i czy dzieli się nam ładnie przez liczbę wierszy.
Zobaczmy efekt:
================================= RESTART: F:\python38\Web scraping 10.py ================================
20
5.0
['Rodzaj', 'Kod', 'Nazwa', 'Adres', '', 'zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie', 'hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie', 'reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']
>>>
Wycinki listy
No to teraz trzeba podzielić listę na tyle kawałków ile jest wierszy. To nie będzie takie znów oczywiste. Posłużymy się wybieraniem z listy wycinków wartości. Zróbmy kilka przykładów w terminalu IDLE:
>>> lista = ['Rodzaj', 'Kod', 'Nazwa', 'Adres', '', 'zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie', 'hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie', 'reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']
>>> print(lista[0:5])
['Rodzaj', 'Kod', 'Nazwa', 'Adres', '']
>>> print(lista[5:10])
['zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie']
>>> print(lista[10:15])
['hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie']
>>> print(lista[15:20])
['reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']
>>>
Jak widzisz, używając indeksów, możemy z listy wydobyć nie tylko pojedynczy element, ale też wycinek listy (slice). Taki wycinek podajemy w nawiasach kwadratowych [] a wartości indeksów oddzielamy dwukropkiem :. Zauważ, że koniec zakresu, czyli druga wartość nie jest inkluzywna, czyli nie jest brana pod uwagę. Zakres [0:5] tak naprawdę zwraca wartości zapisane pod indeksem 0, 1, 2, 3, 4. Podobnie przy zakresie [5:10] dostaniemy listę wartości zapisanych pod indeksami od 5 do 9. W naszym przypadku dobranie się do odpowiednich indeksów wyglądało by tak:
>>> for x in range(0,20,5):
print(x, x +5)
0 5
5 10
10 15
15 20
>>>
W naszym programie zamiast 20 podstawimy długość listy: len(komorki), a zamiast 5: int(len(komorki)/liczba_wierszy)) (liczba komórek przez liczbę wierszy da nam informację co ile zaczyna się nowy wiersz), musimy użyć funkcji int(), domyślnie wynikiem dzielenia w Python jest liczba typu float, a float, nawet jeśli ma postać 5.0, nie może być wykorzystany w funkcji range(). U mnie wyszło to tak:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#wydrukuj każdy wiersz, niezależnie od liczby wierszy
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
print(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W 40 linijce w ładny sposób zapisujemy instrukcję iteracyjną for, która pod zmienną indeks podstawia cyfrę z zakresu 0-20 co 5 (0,5,10,15,20).
W linijce 42 drukujemy wycinki listy z podanego zakresu ([0:5],[5-10], itd.).
Zobaczmy czy program działa prawidłowo:
==================== RESTART: F:\python38\Web scraping 10.py ===================
['Rodzaj', 'Kod', 'Nazwa', 'Adres', '']
['zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie']
['hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie']
['reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']
>>>
Jest ok, teraz zapiszmy te listy na liście list:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
print(lista_list)
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W 40 linijce dodajemy pustą listę, na której będziemy zapisywać nasze listy.
W linijkach 41-44 dodajemy do listy list odpowiednie wycinki listy komorki.
W 45 linijce drukujemy powstałą listę list, lepiej się upewnić, że wszystko jest w porządku. Zobaczmy jak wygląda to „w porządku”:
==================== RESTART: F:\python38\Web scraping 10.py ===================
[['Rodzaj', 'Kod', 'Nazwa', 'Adres', ''], ['zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie'], ['hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie'], ['reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']]
>>>
Fajnie to wygląda, prawda? Na liście zapisaliśmy inne listy. Brakuje nam jeszcze np. id_odmiany jako pierwszej wartości pierwszej listy. Popatrz jak prosto to zrobić!
Metoda .insert()
>>> lista = [['Rodzaj', 'Kod', 'Nazwa', 'Adres', ''], ['zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie'], ['hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie'], ['reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']]
>>> print(lista[0])
['Rodzaj', 'Kod', 'Nazwa', 'Adres', '']
>>> lista[0].insert(0, "id_odmiany")
>>> print(lista[0])
['id_odmiany', 'Rodzaj', 'Kod', 'Nazwa', 'Adres', '']
>>> print(lista[0][1])
Rodzaj
>>> print(lista[0][3])
Nazwa
>>>
Co wydarzyło się powyżej? Ano użyliśmy indeksu, do wybrania pierwszego elementu listy nazwanej lista. Tym pierwszym elementem jest lista nagłówków. Nasz kod print(lista[0]) oznacza wydrukuj pierwszy element listy lista.
Następnie używamy metody .insert(). Różni się ona od metody .append() koniecznością podania dwóch argumentów, pierwszym jest indeks mówiący w które miejsce listy chcemy „coś” wstawić, drugim jest to „coś”, w naszym przypadku jest to string. oczywiście jeśli chcemy wyświetlić dowolny element listy znajdującej się na innej liście musimy zwiekszyć precyzję podawania indeksów. Funkcja print(lista[0][3]) wyświetli nam 4 element 1 listy. Dodajmy taki jeden .insert() do naszego programu i zobaczmy czy się spisał:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
lista_list[0].insert(0, "id_odmiany")
print(lista_list)
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
I zobaczmy co ta 45 linijka zmienia w działaniu programu:
=================== RESTART: F:\python38\Web scraping 10_1.py ==================
[['id_odmiany', 'Rodzaj', 'Kod', 'Nazwa', 'Adres', ''], ['zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie'], ['hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie'], ['reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']]
>>>
Poszło dobrze, to teraz wymyśl jak dodać do pozostałych list numer odmiany. Jak już przetestujesz pomysł, popatrz na mój:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
print(lista_list)
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W linijce 48 zaczynam instrukcję iteracyjną for, której zmienna przyjmuje wartości od 1 do długości listy, czyli od drugiego do ostatniego wiersza tabeli.
W linijce 49 używam wartości tej zmiennej do wskazania odpowiedniej „podlisty” a potem metodą .insert() wstawiam na pierwszym miejscu (indeks 0) numer odmiany. Zobaczmy czy zadziałało poprawnie:
=================== RESTART: F:\python38\Web scraping 10_1.py ==================
[['id_odmiany', 'Rodzaj', 'Kod', 'Nazwa', 'Adres', ''], ['odmiana1', 'zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie'], ['odmiana1', 'hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie'], ['odmiana1', 'reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']]
Zadziałało! Teraz sprawdźmy co stanie się przy zapisie takiej listy list do pliku, postąpimy analogicznie do poprzednich zapisów:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
#zapisz lista_list do pliku .csv
with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
csv.writer(plik).writerow(lista_list)
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
I zobaczmy jak wygląda plik .csv:
"['id_odmiany', 'Rodzaj', 'Kod', 'Nazwa', 'Adres', '']","['odmiana1', 'zachowujący', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie']","['odmiana1', 'hodowca', '654', 'Lima, spółka jaskółka', 'Mordor 16', 'ZS – 15-340 Złe Śródziemie']","['odmiana1', 'reprezentant', '554', 'Saruman ltd. oddział pod lasem ', 'ul. Entów 164', 'SR – 61-168 Buk']"
Uuu, no nie. z tego nie będzie porządnego pliku .csv. Pamiętasz jak używaliśmy metody .writerows() bez s? Teraz użyjemy tej z s. Popatrz na kod programu różniący się jedną literą:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv
tabela_gatunek = "ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR"
#dla 1 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:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
#zapisz lista_list do pliku .csv
with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
csv.writer(plik).writerows(lista_list)
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
I teraz efekt:
id_odmiany,Rodzaj,Kod,Nazwa,Adres,
odmiana1,zachowujący,654,"Lima, spółka jaskółka",Mordor 16,ZS – 15-340 Złe Śródziemie
odmiana1,hodowca,654,"Lima, spółka jaskółka",Mordor 16,ZS – 15-340 Złe Śródziemie
odmiana1,reprezentant,554,Saruman ltd. oddział pod lasem ,ul. Entów 164,SR – 61-168 Buk
Super! I już możemy wstawiać to do naszego głównego programu. Oczywiście musimy jeszcze pamiętać o tym, by nagłówek zapisał się tylko raz. Zanim to zrobimy zobaczmy taką niedoskonałą wersję. Pamiętaj o usunięciu plików .csv przed uruchomieniem!
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv
from os import path
def zapisz_naglowek(ile_komorek):
for indeks in range(0, ile_komorek, 2):
for komorka_wiersza in tabela.findAll("td")[indeks]:
komorki.append(komorka_wiersza.replace("\n", ''))
def zapisz_tresc(ile_komorek):
for indeks in range(1, ile_komorek, 2):
for komorka_wiersza in tabela.findAll("td")[indeks]:
komorki.append(komorka_wiersza.replace("\n", ''))
def zapisz_plik():
with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
csv.writer(plik).writerow(komorki)
id_tabel = ["ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek",
"ctl00_ContentPlaceHolderZawartosc_DetailsViewStatusy",
"ctl00_ContentPlaceHolderZawartosc_DetailsViewNazwy"]
#dla odmian
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 znajduje się na liście id_tabel
if tytul_tabeli in id_tabel:
if path.isfile(f"{tytul_tabeli}.csv"):
komorki= [f"odmiana{nr}"]
zapisz_tresc(len(tabela.findAll("td")))
#zapisz listę tabeli do pliku o nazwie = id
zapisz_plik()
else:
komorki= [f"id_odmiany"]
#zapisz nagłówki tabeli
zapisz_naglowek(len(tabela.findAll("td")))
#zapisz listę tabeli do pliku o nazwie = id
zapisz_plik()
komorki= [f"odmiana{nr}"]
#zapisz treść tabeli
zapisz_tresc(len(tabela.findAll("td")))
zapisz_plik()
if tytul_tabeli not in id_tabel and tytul_tabeli != None:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
#zapisz lista_list do pliku .csv
with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
csv.writer(plik).writerows(lista_list)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W 53 linijce zapisaliśmy warunek, który składa się z dwóch części. Co znaczy taki zapis – if tytul_tabeli not in id_tabel and tytul_tabeli != None: ? Ano można przeczytać go tak: jeśli id tabeli, zapisane pod zmienną tytul_tabeli nie znajduje się na liście nazwanej id_tabel i jeśli id tabeli jest różne od None to: Czemu tak to zapisałem? Wiemy, że nasza tabela nie jest tabelą pionową i wiemy, że nie interesują nasz tabele bez id (czyli z id równym None). Następnie jest kod, który przygotowaliśmy do tabeli „hodowcykr”. Podejrzyjmy jak tabela wygląda, odszukaj plik „ctl00_ContentPlaceHolderZawartosc_GridViewHodowcyKR.csv” i otwórz go w edytorze tekstu. Wygląda teraz tak:
id_odmiany,Rodzaj,Kod,Nazwa,Adres,
odmiana1,zachowujący,654,"Lima, spółka jaskółka",Mordor 16,ZS – 15-340 Złe Śródziemie
odmiana1,hodowca,654,"Lima, spółka jaskółka",Mordor 16,ZS – 15-340 Złe Śródziemie
odmiana1,reprezentant,554,Saruman ltd. oddział pod lasem ,ul. Entów 164,SR – 61-168 Buk
id_odmiany,Rodzaj,Kod,Nazwa,Adres,
odmiana2,zgłaszający,303,Polsko-Polska l.t.d,ul. Narodowa 44,PL – 61-003 Poznań
odmiana2,zachowujący,59,Polsko-Niemiecka Co,IchNicht Strasse 1,DE – 37574 Einbeck
odmiana2,hodowca,59,Polsko-Niemiecka Co,IchNicht Strasse 1,DE – 37574 Einbeck
odmiana2,reprezentant,303,Polsko-Polska l.t.d,ul. Narodowa 44,PL – 61-003 Poznań
id_odmiany,Rodzaj,Kod,Nazwa,Adres,
odmiana3,zgłaszający,610,„Hogwart sp zoo”,Rieka 127,GB- 600-22 Hogwart
odmiana3,zachowujący,610,„Hogwart sp zoo”,Rieka 127,GB- 600-22 Hogwart
odmiana3,hodowca,610,„Hogwart sp zoo”,Rieka 127,GB- 600-22 Hogwart
id_odmiany,Rodzaj,Kod,Nazwa,Adres,
odmiana4,zachowujący,150,Narvel inc.,Komiksowo 2a,PL – 64-101 Manaman
odmiana4,hodowca,150,Narvel inc.,Komiksowo 2a,PL – 64-101 Manaman
id_odmiany,Rodzaj,Kod,Nazwa,Adres,
odmiana5,zachowujący,999,DC Gmbh,Nachtstrasse 11/2,DE – 13478 Smuli
odmiana5,hodowca,999,DC Gmbh,Nachtstrasse 11/2,DE – 13478 Smuli
odmiana5,reprezentant,555,DC. Polska sp. z o.o.,ul. Butmana 72,PL – 62-131 Janowice
id_odmiany,Rodzaj,Kod,Nazwa,Adres,
odmiana7,zachowujący,1000,Przedsiębiorstwo Młode koty z o.o.,ul. Mruczki 3,PL – 05-150 Kocury Rude
odmiana7,hodowca,1000,Przedsiębiorstwo Młode koty z o.o.,ul. Mruczki 3,PL – 05-150 Kocury Rude
Tak jak się spodziewałeś, nagłówki występują tyle razy, ile razy występuje ta tabela dla poszczególnych odmian. Do zmiany zapisywania użyjemy znanej już funkcji isfile(). Pomyśl jaki warunek postawić i jak zapisać listę list w całości a jak jej kawałek w zależności czy plik istnieje, czy też nie. Ja zrobię to tak:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv
from os import path
def zapisz_naglowek(ile_komorek):
for indeks in range(0, ile_komorek, 2):
for komorka_wiersza in tabela.findAll("td")[indeks]:
komorki.append(komorka_wiersza.replace("\n", ''))
def zapisz_tresc(ile_komorek):
for indeks in range(1, ile_komorek, 2):
for komorka_wiersza in tabela.findAll("td")[indeks]:
komorki.append(komorka_wiersza.replace("\n", ''))
def zapisz_plik():
with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
csv.writer(plik).writerow(komorki)
id_tabel = ["ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek",
"ctl00_ContentPlaceHolderZawartosc_DetailsViewStatusy",
"ctl00_ContentPlaceHolderZawartosc_DetailsViewNazwy"]
#dla odmian
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 znajduje się na liście id_tabel
if tytul_tabeli in id_tabel:
if path.isfile(f"{tytul_tabeli}.csv"):
komorki= [f"odmiana{nr}"]
zapisz_tresc(len(tabela.findAll("td")))
#zapisz listę tabeli do pliku o nazwie = id
zapisz_plik()
else:
komorki= [f"id_odmiany"]
#zapisz nagłówki tabeli
zapisz_naglowek(len(tabela.findAll("td")))
#zapisz listę tabeli do pliku o nazwie = id
zapisz_plik()
komorki= [f"odmiana{nr}"]
#zapisz treść tabeli
zapisz_tresc(len(tabela.findAll("td")))
zapisz_plik()
if tytul_tabeli not in id_tabel and tytul_tabeli != None:
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
if path.isfile(f"{tytul_tabeli}.csv"):
lista_list = lista_list[1:len(lista_list)]
#zapisz lista_list do pliku .csv
with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
csv.writer(plik).writerows(lista_list)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W linijce 82 zaczynamy instrukcję warunkową, która sprawdza, czy istnieje plik o nazwie równej id tabeli z dodanym rozszerzeniem .csv, jeśli tak:
W linijce 83 lista_list zostaje pozbawiona pierwszej listy (listy nagłówków) poprzez wybranie wycinka lista_list[1:len(lista_list)], czyli elementów (będących listami) od drugiego do ostatniego. Obejrzyjmy ten śliczny kod w akcji!:
id_odmiany,Rodzaj,Kod,Nazwa,Adres,
odmiana1,zachowujący,654,"Lima, spółka jaskółka",Mordor 16,ZS – 15-340 Złe Śródziemie
odmiana1,hodowca,654,"Lima, spółka jaskółka",Mordor 16,ZS – 15-340 Złe Śródziemie
odmiana1,reprezentant,554,Saruman ltd. oddział pod lasem ,ul. Entów 164,SR – 61-168 Buk
odmiana2,zgłaszający,303,Polsko-Polska l.t.d,ul. Narodowa 44,PL – 61-003 Poznań
odmiana2,zachowujący,59,Polsko-Niemiecka Co,IchNicht Strasse 1,DE – 37574 Einbeck
odmiana2,hodowca,59,Polsko-Niemiecka Co,IchNicht Strasse 1,DE – 37574 Einbeck
odmiana2,reprezentant,303,Polsko-Polska l.t.d,ul. Narodowa 44,PL – 61-003 Poznań
odmiana3,zgłaszający,610,„Hogwart sp zoo”,Rieka 127,GB- 600-22 Hogwart
odmiana3,zachowujący,610,„Hogwart sp zoo”,Rieka 127,GB- 600-22 Hogwart
odmiana3,hodowca,610,„Hogwart sp zoo”,Rieka 127,GB- 600-22 Hogwart
odmiana4,zachowujący,150,Narvel inc.,Komiksowo 2a,PL – 64-101 Manaman
odmiana4,hodowca,150,Narvel inc.,Komiksowo 2a,PL – 64-101 Manaman
odmiana5,zachowujący,999,DC Gmbh,Nachtstrasse 11/2,DE – 13478 Smuli
odmiana5,hodowca,999,DC Gmbh,Nachtstrasse 11/2,DE – 13478 Smuli
odmiana5,reprezentant,555,DC. Polska sp. z o.o.,ul. Butmana 72,PL – 62-131 Janowice
odmiana7,zachowujący,1000,Przedsiębiorstwo Młode koty z o.o.,ul. Mruczki 3,PL – 05-150 Kocury Rude
odmiana7,hodowca,1000,Przedsiębiorstwo Młode koty z o.o.,ul. Mruczki 3,PL – 05-150 Kocury Rude
Bomba, ciekawe, czy zauważyłeś, że pojawił się jeszcze jeden plik: ctl00_ContentPlaceHolderZawartosc_GridViewWnioskiKR.csv. Widzisz, nasz program znalazł jeszcze jedną tabelę. Tabelę, której nie było na liście id_tabel. Nic nie powstrzyma naszej ciekawości, zobaczmy ten plik:
id_odmiany,Rodzaj,Nr wniosku,Data zgłoszenia,Data publikacji w Diariuszu,Data wycofania/odrzucenia,Powód wycofania/odrzucenia,wybierz
odmiana4,wybierz,R,ZZ 1029,11.03.2014,15.05.2014, ,
odmiana4,wybierz,SR,ZZ 1030,29.12.1993,31.12.1993, ,
odmiana4,wybierz
Na pierwszy rzut oka można by pomyśleć, że jest ok. Jednak gdy zrobimy tabelę z tych danych:
| id_odmiany | Rodzaj | Nr wniosku | Data zgłoszenia | Data publikacji w Diariuszu | Data wycofania/odrzucenia | Powód wycofania/odrzucenia | wybierz |
| odmiana4 | wybierz | R | ZZ 1029 | 11.03.2014 | 15.05.2014 | ||
| odmiana4 | wybierz | SR | ZZ 1030 | 29.12.1993 | 31.12.1993 | ||
| odmiana4 | wybierz |
to będzie wyglądać zupełnie inaczej niż ta na stronie. Można się domyślać, że to „wybierz” nam bruździ. „Wybierz” jak się okazuje jest między znacznikami <a>(opcja „zbadaj element” po kliknięciu prawym klawiszem myszki na tabelę na stronie odmiany 4), i nasz program potraktował go jako nagłówek a potem to się już wszystko rozjechało. Dla tabeli „hodowcykr” pozwoliliśmy szukać <a> w całej tabeli, jak widać to był błąd, tego <a> należy szukać tylko w obrębie znaczników nagłówka <th>. Spróbujmy poprawić nasz kod odpowiedzialny za pozyskiwanie tabeli „wnioskiKR”. Najpierw sobie wytnijmy z programu tylko potrzebne elementy i wydrukujmy listę list tak, by już na pierwszy rzut oka było widać co się zmienia. Możesz skopiować poniższy kod, tutaj nie ma zbyt wiele do zastanawiania się:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
#dla odmian
for nr in range(4, 5):
#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 znajduje się na liście id_tabel
if tytul_tabeli == \
"ctl00_ContentPlaceHolderZawartosc_GridViewWnioskiKR":
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
for podlista in lista_list:
print(podlista)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W linijkach 49-50 rozbiłem drukowanie listy list na osobne linijki, każda z jedną listą. Przypomnijmy sobie jak teraz wygląda sytuacja:
==================== RESTART: F:\python38\Web scraping 10.py ===================
['id_odmiany', 'Rodzaj', 'Nr wniosku', 'Data zgłoszenia', 'Data publikacji w Diariuszu', 'Data wycofania/odrzucenia', 'Powód wycofania/odrzucenia', 'wybierz']
['odmiana4', 'wybierz', 'R', 'ZZ 1029', '11.03.2014', '15.05.2014', '\xa0', '\xa0']
['odmiana4', 'wybierz', 'SR', 'ZZ 1030', '29.12.1993', '31.12.1993', '\xa0', '\xa0']
['odmiana4', 'wybierz']
>>>
Może spróbujmy najpierw poszukać znacznika <a> tylko tam, gdzie jest ten znacznik pomiędzy <th> i </th>. Zapiszmy taki kod:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
#dla odmian
for nr in range(4, 5):
#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 znajduje się na liście id_tabel
if tytul_tabeli == \
"ctl00_ContentPlaceHolderZawartosc_GridViewWnioskiKR":
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = []
for a in kolumny:
naglowek.append(a.find("a"))
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
for podlista in lista_list:
print(podlista)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W 23 linijce zamiast dodawać wszystkie <a> do nagłówka definiujemy pustą listę.
W 24 linijce zaczynamy instrukcję warunkową, która w obrębie zmiennej kolumny, gdzie są już pobrane wszystkie nagłówki będzie:
W 25 linijce do zdefiniowanej listy naglowek dodajemy, metodą .append() znaleziony znacznik <a>. Zauważ, że używamy tu metody .find() a nie .findAll() Metoda .find("a") znajduje tylko pierwsze wystąpienie znacznika <a>. Czemu szukamy tylko jednego? Ano taka jest nasza tabela. Co by było gdyby tych znaczników <a> więcej w jednym <th>? Zajmiesz się tym, gdy na taką tabelę trafisz ;). Zobaczmy jak nasz program działa:
============================================================== RESTART: F:\python38\Web scraping 10.py =============================================================
Traceback (most recent call last):
File "F:\python38\Web scraping 10.py", line 33, in <module>
komorki.append(komorka_wiersza.get_text())
AttributeError: 'NoneType' object has no attribute 'get_text'
>>>
No i zobaczyliśmy błąd. Bład AttributeError: 'NoneType’ object has no attribute 'get_text’ można przetłumaczyć, że na wartości None nie można użyć metody .get_text(). Upewnijmy się, że dobrze interpretujemy błąd. Wydrukujmy sobie wartość zmiennej komorka_wiersza:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
#dla odmian
for nr in range(4, 5):
#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 znajduje się na liście id_tabel
if tytul_tabeli == \
"ctl00_ContentPlaceHolderZawartosc_GridViewWnioskiKR":
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = []
for a in kolumny:
naglowek.append(a.find("a"))
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
print(komorka_wiersza)
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
for podlista in lista_list:
print(podlista)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
Efektem będzie:
==================== RESTART: F:\python38\Web scraping 10.py ===================
<a style="color: #666666;">Rodzaj</a>
<a style="color: #666666;">Nr wniosku</a>
<a style="color: #666666;">Data zgłoszenia</a>
<a style="color: #666666;">Data publikacji w Diariuszu</a>
<a style="color: #666666;">Data wycofania/odrzucenia</a>
<a style="color: #666666;">Powód wycofania/odrzucenia</a>
None
['id_odmiany', 'R', 'ZZ 1029', '11.03.2014', '15.05.2014']
['odmiana4', '\xa0', '\xa0', 'wybierz', 'SR']
['odmiana4', 'ZZ 1030', '29.12.1993', '31.12.1993', '\xa0']
['odmiana4', '\xa0', 'wybierz']
>>>
No i rzeczywiście mamy wartość None. Dociekliwie można by spytać, czemu wcześniej nie mieliśmy takiego problemu z None? Przecież wcześniej też pobieraliśmy dane z tej samej tabeli. Różnica jest taka, że teraz wskazujemy wprost, by dla każdego znacznika <a> zapisać treść na liście, nawet jeśli jest tam pusta wartość, przy .findAll("a") efekt jest inny:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
#dla odmian
for nr in range(4, 5):
#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 znajduje się na liście id_tabel
if tytul_tabeli == \
"ctl00_ContentPlaceHolderZawartosc_GridViewWnioskiKR":
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = tabela.findAll("a")
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
print(komorka_wiersza)
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
for podlista in lista_list:
print(podlista)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
Wartości None są ignorowane:
==================== RESTART: F:\python38\Web scraping 10.py ===================
<a style="color: #666666;">Rodzaj</a>
<a style="color: #666666;">Nr wniosku</a>
<a style="color: #666666;">Data zgłoszenia</a>
<a style="color: #666666;">Data publikacji w Diariuszu</a>
<a style="color: #666666;">Data wycofania/odrzucenia</a>
<a style="color: #666666;">Powód wycofania/odrzucenia</a>
<a style="color: black;">wybierz</a>
<a style="color: black;">wybierz</a>
['id_odmiany', 'R', 'ZZ 1029', '11.03.2014', '15.05.2014']
['odmiana4', '\xa0', '\xa0', 'wybierz', 'SR']
['odmiana4', 'ZZ 1030', '29.12.1993', '31.12.1993', '\xa0']
['odmiana4', '\xa0', 'wybierz']
>>>
Skoro mamy już to wyjaśnione poprawmy program tak, by nie dopisywał nam do listy wartości None:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
#dla odmian
for nr in range(4, 5):
#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 znajduje się na liście id_tabel
if tytul_tabeli == \
"ctl00_ContentPlaceHolderZawartosc_GridViewWnioskiKR":
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = []
for a in kolumny:
naglowek.append(a.find("a"))
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
if komorka_wiersza != None:
print(komorka_wiersza)
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
for podlista in lista_list:
print(podlista)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
W 33 linijce dokładamy instrukcję warunkową if, która pozwala na zapisanie na liście wartości różnych od None (!=None). Obejrzyjmy efekt:
==================== RESTART: F:\python38\Web scraping 10.py ===================
<a style="color: #666666;">Rodzaj</a>
<a style="color: #666666;">Nr wniosku</a>
<a style="color: #666666;">Data zgłoszenia</a>
<a style="color: #666666;">Data publikacji w Diariuszu</a>
<a style="color: #666666;">Data wycofania/odrzucenia</a>
<a style="color: #666666;">Powód wycofania/odrzucenia</a>
['id_odmiany', 'R', 'ZZ 1029', '11.03.2014', '15.05.2014']
['odmiana4', '\xa0', '\xa0', 'wybierz', 'SR']
['odmiana4', 'ZZ 1030', '29.12.1993', '31.12.1993', '\xa0']
['odmiana4', '\xa0', 'wybierz']
>>>
Widzimy naocznie, że wartości None już nie ma! Usuńmy print() i przywróćmy .append():
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
#dla odmian
for nr in range(4, 5):
#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 znajduje się na liście id_tabel
if tytul_tabeli == \
"ctl00_ContentPlaceHolderZawartosc_GridViewWnioskiKR":
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = []
for a in kolumny:
naglowek.append(a.find("a"))
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
if komorka_wiersza != None:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(naglowek):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
for podlista in lista_list:
print(podlista)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
I zobaczmy efekt:
['id_odmiany', 'Rodzaj', 'Nr wniosku', 'Data zgłoszenia', 'Data publikacji w Diariuszu', 'Data wycofania/odrzucenia', 'Powód wycofania/odrzucenia']
['odmiana4', 'R', 'ZZ 1029', '11.03.2014', '15.05.2014', '\xa0', '\xa0']
['odmiana4', 'wybierz', 'SR', 'ZZ 1030', '29.12.1993', '31.12.1993', '\xa0']
['odmiana4', '\xa0', 'wybierz']
>>>
Wciąż 'wybierz’ pojawia się w dziwnych miejscach. Nagłówek za to wygląda w porządku, brakuje mu tylko pustej wartości na samym końcu. Musimy zmienić nieco warunek, już nie porównujemy długości kolumn z nagłówkiem, a kolumn ze zmienną komorki:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
#dla odmian
for nr in range(4, 5):
#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 znajduje się na liście id_tabel
if tytul_tabeli == \
"ctl00_ContentPlaceHolderZawartosc_GridViewWnioskiKR":
#zapisz pod zmienną wszystkie nagłówki
kolumny = tabela.findAll("th")
naglowek = []
for a in kolumny:
naglowek.append(a.find("a"))
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki
for komorka_wiersza in naglowek:
if komorka_wiersza != None:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(komorki):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
for podlista in lista_list:
print(podlista)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
I zobaczmy efekt:
==================== RESTART: F:\python38\Web scraping 10.py ===================
['id_odmiany', 'Rodzaj', 'Nr wniosku', 'Data zgłoszenia', 'Data publikacji w Diariuszu', 'Data wycofania/odrzucenia', 'Powód wycofania/odrzucenia', '']
['odmiana4', 'R', 'ZZ 1029', '11.03.2014', '15.05.2014', '\xa0', '\xa0', 'wybierz']
['odmiana4', 'SR', 'ZZ 1030', '29.12.1993', '31.12.1993', '\xa0', '\xa0', 'wybierz']
>>>
Wygląda wporzo. Sprawdźmy czy wszystko działa tak samo wporzo w głównym programie:
from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup
import csv
from os import path
def zapisz_naglowek(ile_komorek):
for indeks in range(0, ile_komorek, 2):
for komorka_wiersza in tabela.findAll("td")[indeks]:
komorki.append(komorka_wiersza.replace("\n", ''))
def zapisz_tresc(ile_komorek):
for indeks in range(1, ile_komorek, 2):
for komorka_wiersza in tabela.findAll("td")[indeks]:
komorki.append(komorka_wiersza.replace("\n", ''))
def zapisz_plik():
with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
csv.writer(plik).writerow(komorki)
id_tabel = ["ctl00_ContentPlaceHolderZawartosc_DetailsViewGatunek",
"ctl00_ContentPlaceHolderZawartosc_DetailsViewStatusy",
"ctl00_ContentPlaceHolderZawartosc_DetailsViewNazwy"]
#dla odmian
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 znajduje się na liście id_tabel
if tytul_tabeli in id_tabel:
if path.isfile(f"{tytul_tabeli}.csv"):
komorki= [f"odmiana{nr}"]
zapisz_tresc(len(tabela.findAll("td")))
#zapisz listę tabeli do pliku o nazwie = id
zapisz_plik()
else:
komorki= [f"id_odmiany"]
#zapisz nagłówki tabeli
zapisz_naglowek(len(tabela.findAll("td")))
#zapisz listę tabeli do pliku o nazwie = id
zapisz_plik()
komorki= [f"odmiana{nr}"]
#zapisz treść tabeli
zapisz_tresc(len(tabela.findAll("td")))
zapisz_plik()
if tytul_tabeli not in id_tabel and tytul_tabeli != None:
kolumny = tabela.findAll("th")
#zapisz pod zmienną wszystkie nagłówki
naglowek = []
for a in kolumny:
naglowek.append(a.find("a"))
wiersze = tabela.findAll("tr")
liczba_wierszy = len(tabela.findAll("tr"))
#zapisz pod zmienną całą treść
tresc = tabela.findAll("td")
komorki = []
#dodaj do listy nagłówki posiadające treść
for komorka_wiersza in naglowek:
if komorka_wiersza != None:
komorki.append(komorka_wiersza.get_text())
#jeśli brakuje treści nagłówka dla kolumny, dodaj pusty
if len(kolumny) > len(komorki):
komorki.append("")
#do tej samej listy dodaj treść
for komorka_wiersza in tresc:
komorki.append(komorka_wiersza.get_text())
#zapisz każdy wiersz, niezależnie od liczby wierszy
lista_list = []
for indeks in range(0, len(komorki), \
int(len(komorki)/liczba_wierszy)):
lista_list.append(komorki[indeks:indeks + \
int(len(komorki)/liczba_wierszy)])
#dodaj identyfikator odmiany do listy nagłówków
lista_list[0].insert(0, "id_odmiany")
#dodaj numer odmiany do list treści
for wiersz in range(1,len(lista_list)):
lista_list[wiersz].insert(0,f"odmiana{nr}")
#jeśli plik już istnieje, pomiń nagłówki
if path.isfile(f"{tytul_tabeli}.csv"):
lista_list = lista_list[1:len(lista_list)]
#zapisz lista_list do pliku .csv
with open(f"{tytul_tabeli}.csv", "a", newline = "") as plik:
csv.writer(plik).writerows(lista_list)
#jeśli strony nie ma, poinformuj
except HTTPError:
print(f"Nie odnaleziono strony: {strona}")
Działa? U mnie działa. Mamy dobrze sformatowane pliki .csv, możemy je wysłać naszemu zleceniodawcy. Zastanów się chwilę jaki efekt osiągnęliśmy? Każda z tabel jest w osobnym pliku. Nasz zleceniodawca może sobie sprawdzić, np. wszystkie informacje na temat gatunku dla każdej z odmian. W naszym przykładzie było to 10 odmian, ale wyobraź sobie takie zlecenie na 100 albo 1000! Taki program zrobi wszystko za ciebie! W kolejnej części przerobimy program tak, żeby zapisywał jedną, dużą tabelę.
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ź.
- W naszym programie z tabeli „gatunek” pobierane są dwa nagłówki z niepotrzebnym znakiem „-” na początku: „– nazwa angielska” i „– nazwa botaniczna” użyj swoich programistycznych umiejętności do pozbycia się niepotrzebnych „-„
- Zmodyfikuj program tak, by zapisywał jako nazwę pliku tylko tą część id, występującą po „ctl00_ContentPlaceHolderZawartosc_DetailsView”. Czyli chemy pliki nazwane Gatunek.csv, Statusy.csv itd.