Autorzy: Anna Wszeborowska, Rafał Stożek
prezentacja na githubie
pip install requests
pip install beautifulsoup4
Test instalacji w interpreterze Pythona
import requests
from bs4 import BeautifulSoup
Przykłady:
Protokół HTTP (ang. Hypertext Transfer Protocol) to zbiór zasad i standardów przesyłania dokumentów w sieci WWW. Jest podstawą komunikacji serwerów WWW z klientami, określając znormalizowany format zapytań i odpowiedzi.
Przykładowe zapytanie do serwera o przesłanie pliku:
GET /index.html HTTP/1.1
Dodatkowe nagłówki
Pusty wiersz
prośba o zwrócenie dokumentu o URI /index.html zgodnie z protokołem HTTP/1.1
Metody HTTP (do wersji HTTP/1.0):
W specyfikacji HTTP/1.1 dodano 5 nowych metod: OPTIONS, PUT, DELETE, TRACE oraz CONNECT.
Przykładowa odpowiedź serwera:
HTTP/1.1 200 OK
Date: Thu, 16 Oct 2014 00:20:28 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 53
Pusty wiersz
Zawartość pliku
Pierwsza linia - Status-line: wersja protokołu, kod odpowiedzi, tekstowy opis kodu
Częste kody odpowiedzi dla każdej klasy:
Więcje informacji: RFC 2616
Prosta i przyjazna użytkownikowi biblioteka na licencji Apache2.
Wprawdzie biblioteka standardowa Pythona zawiera moduł urllib2 pozwalający na obsługę komunikacji HTTP, jednak wykonanie nawet najbardziej podstawowych zadań przy jego użyciu wymaga dużego nakładu pracy.
import urllib2
gh_url = 'https://api.github.com'
req = urllib2.Request(gh_url)
password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, gh_url, 'user', 'pass')
auth_manager = urllib2.HTTPBasicAuthHandler(password_manager)
opener = urllib2.build_opener(auth_manager)
urllib2.install_opener(opener)
handler = urllib2.urlopen(req)
print handler.getcode()
print handler.headers.getheader('content-type')
requests:
import requests
r = requests.get('https://api.github.com', auth=('user', 'pass'))
print r.status_code
print r.headers['content-type']
requests w swojej zwięzłości i prostocie jest tym, czego oczekujemy od Pythona
Tworzenie zapytań
import requests
r = requests.get('http://pyladies.com/')
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
print(r.url)
http://httpbin.org/get?key2=value2&key1=value1
Widzimy, że URL został poprawnie zakodowany
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.post("http://httpbin.org/post", data=payload)
r = requests.head("http://httpbin.org/get")
Czytanie odpowiedzi serwera
import requests
r = requests.get("http://isitfriday.info/")
r.text # tekst (kodowanie można ustawić zmieniając r.encoding)
r.content # binarnie
r = requests.get('https://api.github.com/events')
r.json()
>>> r.status_code
200
>>> r.status_code == requests.codes.ok
True
>>> r.headers
{
'content-encoding': 'gzip',
'transfer-encoding': 'chunked',
'connection': 'close',
'server': 'nginx/1.0.4',
'x-runtime': '148ms',
'etag': '"e1ca502697e5c9317743dc078f67693f"',
'content-type': 'application/json'
}
Ćwiczenie
Napisz skrypt, który wypisze Twoje IP. Wykorzystaj w tym celu treść zwracaną przez http://httpbin.org/ip
Dokumentacja biblioteki requests jest dostępna pod adresem: http://docs.python-requests.org/
HyperText Markup Language
Lub po ludzku - sposób w jaki zapisujemy tekstowo nasze drzewo elementów
<tag attribute1="value1" attribute2="value2">content</tag> <p style="font-size: 12px;">Hello world!</p>Niektóre nie muszą (np. obrazek):
<img src="myimage.jpg" alt="Mój obrazek" height="50" width="50">
<!-- To jest komentarz -->
<img src="/adres_obrazka.png">
<p>Tutaj wstawić długi paragraf tekstu</p>
<a href="http://google.com/">Google</a>
<a href="http://google.com/"><img src="/images/google-logo.png"></a>
<div> <a href="/about-us/">O stronie</a> <a href="/contact/">Kontakt</a> </div>
Używamy go głównie do wydzielania bardziej "logicznych" elementów strony, np. lewe menu, jeden post na blogu, lista komentarzy.
<div class="my-square">
Mój kwadracik
</div>
.my-square {
background: red;
color: white;
padding: 10px;
text-align: center;
}
Narzędzia developerskie
Biblioteka do wyciągania danych z plików HTML oraz XML. Wygodne, 'pythonowe' API umożliwia nawigowanie, przeszukiwanie oraz modyfikowanie drzewa dokumentu.
html_doc = """
<!DOCTYPE html>
<html lang="en-US"><head><meta charset="UTF-8" /><title>Is it friday? | isitfriday.info</title></head>
<body><div style="margin: 30px; text-align: center;"><h1>Is it friday?</h1><div style="margin-top: 20px; font-size: 13em;">No</div><br /><div id="impressum" style="margin-top: 30px; font-size: 10px;">another shiny project by <a href="https://nekudo.com/">nekudo.com</a></div></div></body>
</html>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc)
print(soup.prettify())
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8"/>
<title>
Is it friday? | isitfriday.info
</title>
</head>
<body>
<div style="margin: 30px; text-align: center;">
<h1>
Is it friday?
</h1>
<div style="margin-top: 20px; font-size: 13em;">
No
</div>
<br/>
<div id="impressum" style="margin-top: 30px; font-size: 10px;">
another shiny project by
<a href="https://nekudo.com/">
nekudo.com
</a>
</div>
</div>
</body>
</html>
Nawigowanie po drzewie
>>> soup.title
>>> soup.title.string
>>> soup.div['style']
>>> soup.find_all('div')
>>> soup.find(id="impressum")
Praktyczne przykłady:
>>> for link in soup.find_all('a'):
... print(link.get('href'))
>>> print(soup.get_text())
Więcej informacji w dokumentacji bs4
Ćwiczenie
Ze strony PyLadies (http://www.pyladies.com/locations/) wypisz wszystkie lokalizacje lokalnych społeczności
Napisz program, który wyszukuje oferty na grouponie (np. oferty sushi), a następnie wysyła je mailem.
import smtplib
from email.mime.text import MIMEText
from_addr = 'my@domain.com'
password = 'mypassword'
smtp_server = 'smtp.server.com'
smtp_port = 465
recipient = 'your@domain.com'
subject = 'email subject'
message = '<div>this is my email message</div>'
msg = MIMEText(message, 'html', 'utf-8')
msg['Subject'] = subject
msg['From'] = from_addr
msg['To'] = recipient
s = smtplib.SMTP_SSL(smtp_server, smtp_port)
s.login(from_addr, password)
s.sendmail(from_addr, [recipient], msg.as_string())
s.quit()