Interpreter IDLE
Nie ma co zwlekać, zacznijmy pisać program. Jeśli jeszcze nie zainstalowałeś Pythona zapoznaj się z tymi poradnikami i uruchom interpreter IDLE. W okno interpretera możesz wpisywać wprost komendy i wykonywać wszystkie operacje niezbędne do programowania. Najpierw oswój się trochę z terminalem. Twoje polecenia wpisywane są po znaku zachęty >>> a odpowiedź Pythona pojawi się pod nim. Wpisz cyfrę 3 i wciśnij enter, zobacz efekt:
>>> 3
3
>>>
Okno interpretera IDLE potwierdziło wpisanie 3. Teraz spróbuj dodać 3 do 3:
>>> 3+3
6
>>>
Python zrozumiał, że podałeś dwie cyfry i je dodał. Ale skąd wiedział, że podałeś akurat cyfry?
Każde dane mają swój typ. By wyświetlić typ danych musisz użyć odpowiedniej funkcji. W naszym przypadku będzie to funkcja type(). Funkcjom zawsze towarzyszą nawiasy () a w nawiasach często występują argumenty funkcji. Wypróbuj takie przykłady:
>>> type(3)
<class 'int'>
>>> 3+3
6
>>> type("3")
<class 'str'>
>>> "3"+"3"
'33'
>>>
W pierwszej linijce napisałeś type(3), czyli użyłeś funkcji type() z argumentem 3. Inaczej mówiąc, zapytałeś Pythona jakim typem danych jest 3. I dostałeś odpowiedź class 'int'. To oznacza, że 3 jest liczbą całkowitą – integer. Jak widzisz dodawanie liczb całkowitych przynosi oczekiwany rezultat w postaci cyfry 6.
Następnie napisałeś type("3"), czyli czyli użyłeś funkcji type() z argumentem "3". Inaczej mówiąc, zapytałeś Pythona jakim typem danych jest „3”. I dostałeś odpowiedź class 'str'. To oznacza, że „3” jest teraz tekstowym typem danych – string. Każda wartość podana w cudzysłowach podwójnych "" lub pojedynczych '' jest traktowana jak tekst. Jak widzisz dodawanie stringów wygląda nieco inaczej niż dodawanie liczb i cyfr. Oczywiście możesz dodawać też nieidentyczne stringi:
>>> "Mariusz "+"Barbara"
'Mariusz Barbara'
>>>
urlopen() i importowanie funkcji
Do celu web scrapingu potrzebujesz użyć innej funkcji niż type(). Do otwierania stron internetowych przez Pythona użyjesz funkcji urlopen() a jej argumentem będzie adres strony internetowej. Spróbuj otworzyć stronę.
>>> urlopen(https://inferiordatascience.com/przyklad.html)
SyntaxError: invalid syntax
>>>
Dostałeś informację o błędzie składni SyntaxError: invalid syntax. Jeśli chcemy podać adres strony jako argument funkcji, musi się znaleźć on w cudzysłowach (ale nie jest regułą, że argumenty funkcji muszą być stringami, zależy to od funkcji). Poprawmy naszą funkcję:
>>> urlopen("https://inferiordatascience.com/przyklad.html")
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
urlopen("https://inferiordatascience.com/przyklad.html")
NameError: name 'urlopen' is not defined
>>>
Tym razem otrzymaliśmy inną informację, mówiącą o błędnej nazwie NameError: name 'urlopen’ is not defined. Ten błąd znaczy, że albo zrobiliśmy literówkę w nazwie funkcji bądź zmiennej (co to są zmienne dowiesz się za moment), albo takiej funkcji bądź zmiennej w ogóle nie ma. Przed chwilą używałeś funkcji type() bez żadnego trudu, czemu nie możesz funkcji urlopen()?
Python domyślnie ładuje do pamięci tylko niektóre, podstawowe funkcje. Jesli chcesz używać tych mniej popularnych, musisz je zaimportować. Funkcje importuje się z bibliotek, jaka funkcja jest w jakiej bibliotece dowiesz się z np. Google. Funkcję urlopen() potrzebujesz zaimportować z modułu (biblioteki) urllib.request. Czyli mógłbyś powiedzieć „z urllib.request zaimportuj urlopen” (przy imporcie nie podajesz nawiasów funkcji, dla Pythona jest jasne, że importujesz funkcję). W języku zrozumiałym dla Pythona polecenie „z urllib.request zaimportuj urlopen” wygląda tak from urllib.request import urlopen. Napisz to w terminalu IDLE:
>>> from urllib.request import urlopen
>>>
W końcu nie ma żadnego błędu. Spróbujmy teraz dopisać funkcję urlopen() z adresem strony jako argumentem:
>>> from urllib.request import urlopen
>>> urlopen("https://inferiordatascience.com/przyklad.html")
<http.client.HTTPResponse object at 0x01574D48>
>>>
Coś się niewątpliwie wydarzyło, terminal potwierdził nam, że otwarł stronę i jest ona obiektem w takiej a takiej lokalizacji.
Jak widzisz w terminalu interpretera IDLE wpisujesz linijkę po linijce i każde polecenie potwierdzasz enterem. To nie jest dla programisty dobre rozwiązanie. Wyobraź sobie program składający się ze 100 linijek! Na szczęście IDLE daje nam lepszą opcję. W górnej, lewej części okienka kliknij File->New file, albo użyj skrótu ctrl+n. Pojawi się nowe okno, okno gdzie będziesz pisał, zapisywał i uruchamiał programy. Wpisz w nie te same dwie linijki co w terminal:
from urllib.request import urlopen
urlopen("https://inferiordatascience.com/przyklad.html")
Tak napisany program trzeba uruchomić. Zrobisz to wybierając z górnego menu opcję Run->Run module, lub wciskając F5 na klawiaturze. IDLE poinformuje, że przed uruchomieniem musi zapisać program, kliknij ok i nadaj mu jakąś nazwę. Po uruchomieniu zobaczysz coś takiego:
==================== RESTART: F:/python38/Web scraping 03.py ===================
>>>
Dobra wiadomość jest taka, że nie ma błędu. Zła, że nie widać efektu działania programu. Uruchomiony program, w przeciwieństwie do terminala, nie potwierdza twoich działań. Poprosiłeś o otwarcie adresu i program go otworzył. To pierwsza różnica między wpisywaniem komend do terminala a uruchamianiem programu – programy nie potwierdzają Twoich działań, chyba, że tego zażądasz w jakiś sposób. Druga różnica – nie musisz wciskać enter po każdej linijce. Napisz inny program.
3
3 + 3
"3"
"3" + "3"
W linijkach 1-4 wpisujesz to samo, co w okno IDLE na początku tej części. Uruchom program (F5) i zobacz efekt:
==================== RESTART: F:/python38/Web scraping 03.py ===================
>>>
Program nie wyświetlił nic, zmieńmy go trochę. Tym razem użyjemy funkcji print():
print(3)
print(3+3)
print("3")
print("3" + "3")
Wszystkie poprzednie polecenia stały się argumentami funkcji print(). Zobacz efekt programu:
==================== RESTART: F:/python38/Web scraping 03.py ===================
3
6
3
33
>>>
No w końcu mamy efekt o jaki nam chodziło. I widzisz przy okazji, że funkcja print() drukuje do terminala to, co znajdzie się w nawiasach i pamięta o operacjach takich jak np. dodawanie. Jak widzisz print() stringa do terminala nie wyświetla już cudzysłowów, ale to nie jest dla Ciebie żaden kłopot, ważne, że Python pamięta o jaki typ danych chodzi. Ale czy argumentem funkcji może być inna funkcja? Czy można w nawiasach print() umieścić urlopen() wraz z argumentami? Sprawdźmy:
from urllib.request import urlopen
print(urlopen("https://inferiordatascience.com/przyklad.html"))
I zobacz, co wydarzy się po uruchomieniu programu:
==================== RESTART: F:\python38\Web scraping 03.py ===================
<http.client.HTTPResponse object at 0x03685D60>
>>>
No i fajnie, efekt jest taki jaki uzyskałeś bez funkcji print() w terminalu. Wiesz już, jaka funkcja będzie Ci niezbędna do wyświetlania danych. Funkcji print() będziemy używać bardzo często i często jej argumentem będzie inna funkcja, lub też funkcje.
Instalowanie modułów (bibliotek)
Dla naszych celów, informacja, że strona została otworzona to za mało. Chcemy ją wyświetlić. Do tego celu potrzebujesz modułu bs4, który nie jest standardowym modułem Pythona. Z bs4 potrzebujemy zaimportować funkcję BeautifulSoup() (tak, wielkie litery musisz wpisać jako wielkie). Spróbujmy importu:
from bs4 import BeautifulSoup
I uruchom program:
==================== RESTART: F:\python38\Web scraping 03.py ===================
Traceback (most recent call last):
File "F:\python38\Web scraping 03.py", line 1, in <module>
from bs4 import BeautifulSoup
ModuleNotFoundError: No module named 'bs4'
>>>
Wyświetlił się błąd modułu ModuleNotFoundError: No module named 'bs4′. To znaczy, że Python tego modułu nie znalazł i trzeba go zainstalować. Instalowanie modułów to coś podobnego do instalowania dodatków do gier – nowy moduł to nowe możliwości. Uruchom linię komend (klikając lupę koło znaczka Windows w lewym dolnym rogu, wpisując cmd i klikając enter) i wydaj polecenie pip install bs4, jeśli coś nie działa zapoznaj się z tą instrukcją. Efekt instalacji w linii komend powinien być podobny do tego poniżej:
F:\python38\Scripts>pip install bs4
Collecting bs4
Using cached bs4-0.0.1.tar.gz (1.1 kB)
Collecting beautifulsoup4
Downloading beautifulsoup4-4.9.1-py3-none-any.whl (115 kB)
|████████████████████████████████| 115 kB 939 kB/s
Collecting soupsieve>1.2
Downloading soupsieve-2.0.1-py3-none-any.whl (32 kB)
Installing collected packages: soupsieve, beautifulsoup4, bs4
Running setup.py install for bs4 ... done
Successfully installed beautifulsoup4-4.9.1 bs4-0.0.1 soupsieve-2.0.1
Uruchom program raz jeszcze i zobacz efekt:
==================== RESTART: F:\python38\Web scraping 03.py ===================
>>>
Nie ma błędu, jest ok.
Zmienne i metody
Zanim zajmiesz się funkcją BeautifulSoup(), powinieneś dowiedzieć się trochę o zmiennych i metodach. Popatrz na przykład, wszystko co jest między cudzysłowami wklej, szkoda przepisywać:
print("Zanim zajmiesz się funkcją BeautifulSoup()")
print("Zanim zajmiesz się funkcją BeautifulSoup()".lower())
print("Zanim zajmiesz się funkcją BeautifulSoup()".upper())
I uruchom program, efekt powinien być taki:
==================== RESTART: F:\python38\Web scraping 03.py ===================
Zanim zajmiesz się funkcją BeautifulSoup()
zanim zajmiesz się funkcją beautifulsoup()
ZANIM ZAJMIESZ SIĘ FUNKCJĄ BEAUTIFULSOUP()
>>>
Przeanalizujmy razem co się tutaj wydarzyło. W 1 linijce podajesz argument dla funkcji print(), który jest stringiem i efekt jest taki jakiego się spodziewałeś.
W drugiej linijce, po funkcji print() pojawiło się .lower(). Efekt jest taki, że wszystkie wielkie litery stały się małymi. Zauważ, że .lower() zaczyna się od kropki. Możesz przyjąć, że od kropki zaczynają się metody i jak widzisz można ich używać na stringach, ale to nie wszystko, metody będą pojawiać się też nie tylko przy stringach. Oczywiście metoda .lower() służy zamianie liter na małe. W 3 linijce użyta metoda .upper() zamienia małe litery na wielkie.
W tych trzech linijkach kodu, spora cześć wygląda tak samo, za każdym razem wpisujesz całkiem długi tekst „Zanim zajmiesz się funkcją BeautifulSoup()”. Zamiast go wpisywać, możesz ten tekst podstawić pod zmienną, zrobisz to w bardzo prosty sposób:
tekst = "Zanim zajmiesz się funkcją BeautifulSoup()"
print(tekst)
print(tekst.lower())
print(tekst.upper())
To co widzisz w 1 linijce, to podstawianie stringa pod zmienną, która nazywa się tekst, inaczej mówiąc deklarujesz zmienną. Nazwa zmiennej musi spełniać kilka reguł:
- Pierwszym znakiem nazwy zmiennej musi być litera lub „_”
- Nazwa zmiennej nie może się zaczynać od cyfry
- Nazwa może zawierać tylko: litery (bez polskich znaków), cyfry (0-9) i znak podkreślenia („_”)
- Dla zmiennych wielkość liter ma znaczenie, „Tekst” i „tekst” to dwie, różne zmienne
Potem piszesz znak = oznaczający, że wszystko co znajdzie się po jego prawej stronie będzie reprezentowane przez zmienną.
Następnie, w linijkach 2-4 używasz tych samych funkcji i metod co poprzednio, ale zamiast stringa, używasz zmiennej, która ten string reprezentuje. Zobaczmy efekt:
==================== RESTART: F:\python38\Web scraping 03.py ===================
Zanim zajmiesz się funkcją BeautifulSoup()
zanim zajmiesz się funkcją beautifulsoup()
ZANIM ZAJMIESZ SIĘ FUNKCJĄ BEAUTIFULSOUP()
>>>
Pamiętaj, że zmiennych nie podajesz w cudzysłowach, nawet jeśli przechowują string:
>>> tekst = "Zanim zajmiesz się funkcją BeautifulSoup()"
>>> print(tekst)
Zanim zajmiesz się funkcją BeautifulSoup()
>>> print("tekst")
tekst
>>>
BeautifulSoup()
Mając w pamięci wszystko, czego przed chwilą się nauczyłeś, użyjemy funkcji BeautifulSoup(). Argumentami funkcji będzie otwarta strona wraz z metodą .read(), oraz wskazanie jakiego parsera ma funkcja BeautifulSoup() użyć. W pierwszym podejściu pominiemy parser. Napiszmy program:
from urllib.request import urlopen
from bs4 import BeautifulSoup
print(BeautifulSoup(urlopen("https://inferiordatascience.com/przyklad.html").read()))
W 1 i 2 linijce importujesz niezbędne funkcje z modułów. Pierwszym argumentem funkcji BeautifulSoup(), jest inna funkcja, urlopen(), której to argumentem jest strona, którą chcemy otworzyć – BeautifulSoup(urlopen("https://inferiordatascience.com/przyklad.html"). Następnie podajemy metodę .read(), bo chcemy, by otwarta strona została przeczytana – BeautifulSoup(urlopen("https://inferiordatascience.com/przyklad.html").read()). No i na koniec chcemy całość wydrukować, czyli argumentem funkcji print() staje się funkcja BeautifulSoup() a jej argumentem jest funkcja urlopen(). Policz dobrze nawiasy, otwierających musi być tyle samo co zamykających. Uruchom program.
==================== RESTART: F:\python38\Web scraping 03.py ===================
Warning (from warnings module):
File "F:\python38\Web scraping 03.py", line 3
print(BeautifulSoup(urlopen("https://inferiordatascience.com/przyklad.html").read()))
GuessedAtParserWarning: No parser was explicitly specified, so I'm using the best available HTML parser for this system ("html.parser"). This usually isn't a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently.
The code that caused this warning is on line 3 of the file F:\python38\Web scraping 03.py. To get rid of this warning, pass the additional argument 'features="html.parser"' to the BeautifulSoup constructor.
<html>
<head>
<title>The Very Last Page On The Internet</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
</head>
<body bgcolor="#FFFFFF" onunload="onExit()" text="#000000">
<p> </p>
<p> </p>
<table align="center" border="0" cellpadding="0" cellspacing="0" width="90%">
<tr>
<td colspan="2">
<h1 align="center"><font face="Verdana, Arial, Helvetica, sans-serif"><b>This
Is The Very Last Page On The Internet</b></font></h1>
<h1 align="center"> </h1>
<h1 align="center"><b><font color="#666666" face="Verdana, Arial, Helvetica, sans-serif">Please
turn off your computer!!!</font></b></h1>
<h1 align="center"> </h1>
<h1 align="center"><font color="#666666"><b><font face="Verdana, Arial, Helvetica, sans-serif">Go
outside and play!!!</font></b></font></h1>
<h1 align="center"> </h1>
<h1 align="center"><b><font color="#FF0000" face="Verdana, Arial, Helvetica, sans-serif">The
End.</font><font color="#666666" face="Verdana, Arial, Helvetica, sans-serif">
</font></b></h1>
</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
</table>
</body>
</html>
>>>
Na początku dostajemy piękne ostrzeżenie, że GuessedAtParserWarning: No parser was explicitly specified. Nie został wybrany parser, albo inaczej mówiąc, nie został wybrany analizator składniowy. Funkcja BeautifulSoup() wybrała domyślny, ale lepiej podać go wprost jako drugi argument.
Pod ostrzeżeniem natomiast wydrukowało się źródło strony! I tego właśnie chcieliśmy. Zróbmy jeszcze porządek w kodzie, niech będzie czytelny, bez ostrzeżeń i ładniejszy. Po pierwsze dodajmy argument z parserem:
from urllib.request import urlopen
from bs4 import BeautifulSoup
print(BeautifulSoup(urlopen("https://inferiordatascience.com/przyklad.html").read(), "html.parser"))
W 3 linijce dodaliśmy parser „html.parser” jako drugi argument funkcji, argumenty funkcji rozdzielane są przecinkami. Zobaczmy efekt:
==================== RESTART: F:\python38\Web scraping 03.py ===================
<html>
<head>
<title>The Very Last Page On The Internet</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
</head>
<body bgcolor="#FFFFFF" onunload="onExit()" text="#000000">
<p> </p>
<p> </p>
<table align="center" border="0" cellpadding="0" cellspacing="0" width="90%">
<tr>
<td colspan="2">
<h1 align="center"><font face="Verdana, Arial, Helvetica, sans-serif"><b>This
Is The Very Last Page On The Internet</b></font></h1>
<h1 align="center"> </h1>
<h1 align="center"><b><font color="#666666" face="Verdana, Arial, Helvetica, sans-serif">Please
turn off your computer!!!</font></b></h1>
<h1 align="center"> </h1>
<h1 align="center"><font color="#666666"><b><font face="Verdana, Arial, Helvetica, sans-serif">Go
outside and play!!!</font></b></font></h1>
<h1 align="center"> </h1>
<h1 align="center"><b><font color="#FF0000" face="Verdana, Arial, Helvetica, sans-serif">The
End.</font><font color="#666666" face="Verdana, Arial, Helvetica, sans-serif">
</font></b></h1>
</td>
</tr>
<tr>
<td> </td>
<td> </td>
</tr>
</table>
</body>
</html>
>>>
Tym razem nie pojawiło się ostrzeżenie. Użyjmy jeszcze zmiennej, by poprawić przejrzystość kodu:
from urllib.request import urlopen
from bs4 import BeautifulSoup
strona = "https://inferiordatascience.com/przyklad.html"
print(BeautifulSoup(urlopen(strona).read(), "html.parser"))
Tym razem w 4 linijce pod zmienną strona podstawiamy string zawierający adres strony, którą chcemy scrapować. W ostatniej linijce korzystamy z tej zmiennej. Możemy jeszcze bardziej poprawić czytelność:
from urllib.request import urlopen
from bs4 import BeautifulSoup
strona = "https://inferiordatascience.com/przyklad.html"
otwarta_strona = urlopen(strona)
print(BeautifulSoup(otwarta_strona.read(), "html.parser"))
W 5 linijce dodaliśmy nową zmienną otwarta_strona (warto nazywać zmienne tak, byś rozumiał co zawierają), która zawiera stronę otwartą funkcją urlopen(), której argumentem jest zmienna, która ma zadeklarowany adres strony. Możemy jeszcze bardziej poprawić czytelność:
from urllib.request import urlopen
from bs4 import BeautifulSoup
strona = "https://inferiordatascience.com/przyklad.html"
otwarta_strona = urlopen(strona)
html = BeautifulSoup(otwarta_strona.read(), "html.parser")
print(html)
Teraz mamy 3 zmienną w 6 linijce, którą to ostatecznie drukujemy w 8 linijce. Zauważ, że taki zapis jest bardzo przejrzysty. Zauważ też, że na początku nie potrzebowałeś deklarować żadnych zmiennych, by uzyskać ten sam efekt. Sam wybierz którzy sposób wolisz i zapisuj kod programu tak, by go rozumieć już przy pierwszym czytaniu.
Jeśli nie czujesz się jeszcze zbyt pewnie w tematyce funkcji, argumentów i zmiennych, zapraszam do trzeciej części kursu Porównaj styl pisarzy, gdzie tłumaczę te zagadnienia na innych przykładach.
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ź.
- Wydrukuj jaki typ ma zmienna HTML
- Znajdź funkcję, która pozwoli zmienić typ zmiennej HTML na string, wydrukuj tak zmieniony HTML, czy różni się czymś od tego, wydrukowanego przed zadaniem domowym?