Hlavní navigace

Létající cirkus (16)

6. 9. 2002
Doba čtení: 8 minut

Sdílet

Po delší pauze způsobené tragickými srpnovými záplavami se opět setkáváme u dalšího dílu našeho seriálu o programovacím jazyce Python, který bude tentokráte věnován práci s internetovými protokoly FTP, HTTP a SMTP, přičemž nevynecháme ani knihovnu urllib.
PROTOKOL SMTP

Jak jistě mnozí z vás ví, je protokol SMTP (Simple Mail Transfer Protocol, viz. RFC 821) navržen pro přenos elektronické pošty. Tato pošta se sestává z pouhého prostého textu. Pro přenos strukturovaných e-mailů (tj. e-mailů, které se skládají z více částí, např. text a přiložené obrázky apod.) se musíme držet standardu RFC 2822. Práci s takto formátovanými zprávami se zabývá modul email. S jeho pomocí můžeme zkonstruovat strukturovaný e-mail z jeho jednotlivých částí. Následně si od něj vyžádáme tento e-mail jako prostý text, který odešleme pomocí protokolu SMTP. Klientská část protokolu SMTP je v Pythonu implementována v modulu smtplib, jenž si dnes popíšeme. Dokumentaci modulu email si můžete nastudovat jako malý domácí úkol.

Samotný modul smtplib toho příliš neobsahuje. Kromě několika výjimek nabízí pouze třídu SMTP, která ale sdružuje veškerou funkcionalitu. Pomocí jejích metod se můžeme připojit k SMTP serveru, odeslat e-mail a odpojit se. Zde je třeba podotknout, že pomocí modulu smtplib je možné implementovat pouze klientskou část protokolu SMTP. Následně si popíšeme třídu SMTP a její metody.

Veškerá komunikace s SMTP serverem začne vytvořením nové instance třídy SMTP, přičemž konstruktoru předáme jako argument jméno hostitele a číslo portu, kam se má tato instance připojit. Číslo portu můžeme vynechat (pak se použije 25) nebo může obsahovat řetězec hostitele (např. „smtp.nekde.com:8989“). Dokonce je možné vynechat i jméno hostitele, pak se vytvoří nepřipojená instance třídy SMTP (před jejím používáním je třeba se nejprve připojit k serveru pomocí metody connect(), která akceptuje stejné argumenty jako konstruktor). Nepodaří-li se navázat spojení s tímto serverem, dojde k výjimce smtplib.SMTPCon­nectError.

Následuje odeslání e-mailu pomocí metody sendmail(). Ta má tři povinné argumenty: první je adresa odesílatele e-mailu, druhý pak adresa (případně adresy) adresáta e-mailu a poslední je vlastní tělo e-mailu včetně hlaviček. Adresy předané metodě sendmail() slouží pouze pro vytvoření „obálky“ e-mailu, modul smtplib nijak neovlivňuje obsah samotného těla ani hlaviček. Pokud při volání metody sendmail() nedojde k výjimce, máme jistotu, že alespoň jednomu adresátovi se e-mail podařilo odeslat. Adresy těch, jimž se zprávu nepodařilo doručit, vrátí metoda sendmail() (jako asociativní pole, klíče jsou adresy adresátů, hodnoty pak tuple (chybový_kód, popis_chyby)). Při vzniku výjimky SMTPRecipientsRe­fused se e-mail nepodařilo doručit nikomu z adresátů (přičemž atribut recipients objektu výjimky obsahuje asociativní pole ve tvaru popsaném výše). Pro popis dalších výjimek vás odkáži do dokumentace modulu smtplib.

Pro ukončení komunikace s SMTP serverem je zapotřebí zavolat metodu quit(). Ta ukončí sezení a uzavře komunikační kanál k SMTP serveru. Po jejím zavolání již není možné používat metody této instance.

Nakonec si ukážeme, jak by mohl vypadat jednoduchý program pro odesílání e-mailů:

import smtplib
import sys

od = raw_input('Od: ')
pro = raw_input('Pro: ')
predmet = raw_input('Předmet: ')

msg = ("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n"
       % (od, pro, predmet))

print "Zadejte text zprávy, ukončete stiskem ^D na samotném řádku:"

msg += sys.stdin.read()

server = smtplib.SMTP('localhost')
server.sendmail(od, pro, msg)
server.quit()
PROTOKOL FTP

Pro potřebu přenosu souborů po síti internet byl navržen protokol FTP. Již v základní distribuci Pythonu je obsažen modul implementující klientskou část tohoto protokolu – ftplib. Tento modul má obdobnou strukturu jako výše uvedený modul smtplib, čili základní modul obsahuje třídu FTP, která slouží pro práci s protokolem FTP, a několik výjimek.

Třídě FTP se budeme věnovat pouze stručně, protože případný zájemce si další najde v dokumentaci modulu ftplib. Třídě FTP můžeme při jejím vzniku (stejně jako u třídy SMTP) předat adresu počítače, na který se má připojit. Předáme-li jí tuto adresu, je zavolána metoda connect() této instance s adresou předanou jako jediný parametr (v případě, že adresu nepředáme, musíme metodu connect() volat sami). Dále je možné konstruktoru předat další dva parametry – uživatelské jméno a heslo na vzdáleném počítači, přičemž konstruktor zavolá metodu login(), jíž tyto dva argumenty předá (obdobně – pokud tyto argumenty nepředáme konstruktoru, musíme sami zavolat metodu login()).

Specifickou vlastností protokolu FTP je používání dvou různých módů – binárního a textového. Modul ftplib samozřejmě tyto dva módy podporuje (příkladem může být dvojice metod retrbinary() a retrlines()),

Po připojení na vzdálený počítač můžeme používat metody pro práci s jednotlivými službami protokolu FTP. Následuje stručný výčet těchto metod (pro kompletní dokumentaci nahlédněte, prosím, do dokumentace modulu ftplib případně přímo do jeho zdrojového kódu):

- sendcmd(příkaz) - zašle serveru příkaz a vrátí odpověd serveru
        jako jediný řetězec (obdobně existuje i voidcmd(),
        který v případě chyby vyvolá výjimku)

- retrlines(příkaz, funkce) - zašle serveru příkaz (téměř vždy
        jím je řetězec 'RETR jméno_souboru', který slouží
        pro stáhnutí souboru) a začne stahovat odpověď na
        příkaz v textovém módu, přičemž pro každý řádek
        zavolá funkci, které předá jako jediný argument
        tuto řádku. Funkce je nepovinný argument, je-li
        vynechána, vytiskne se obsah souboru na standardní
        výstup.

- retrbinary(příkaz, funkce) - obdobně jako metoda retrlines()
        zašle serveru příkaz (opět řetězec
        'RETR jméno_souboru') a odpověď začne stahovat
        v binárním módu, přičemž pro každý blok
        binárních dat zavolá funkci.

- storlines(příkaz, soubor) - zašle serveru příkaz (většinou jím
        je řetězec ve tvaru 'STOR jméno_souboru'), přičemž
        čte řádky ze souboru (pomocí metody readlines())
        a zapisuje je do souboru na vzdáleném počítači, pro
        komunikaci používá textový mód.

- storbinary(příkaz, soubor) - pracuje obdobně jako metoda
        storlines(), přenos ale pracuje v binárním módu.
        Pro čtení souboru se používá metoda read(), zároveň
        je možné použít třetí nepovinný argument, který
        určuje velikost bloku.

- dir(adresář, funkce) - zašle FTP serveru příkaz 'LIST adresář'
        a výsledek přečte v textovém módu, význam funkce
        je stejný jako u metody retrlines(). Je-li funkce
        vynechána, je výsledek vytisknut na standardní
        výstup.

- quit() - zašle FTP server příkaz 'QUIT', čímž ukončí spojení
        s tímto serverem. Po zavolání quit() již není možné
        další metody této instance používat.

Existují i další metody pro práci se soubory jako rename(), delete(), cwd(), pwd(), mkd() a další. Pro nedostatek prostoru se na ně nedostalo, jsou ale dobře popsány v dokumentaci jazyka Python.

PROTOKOL HTTP

Pro práci s klientskou částí protokolu HTTP nabízí Python modul httplib. Ten, narozdíl od výše uvedených modulů, nabízí hned dvě třídy. První z nich, HTTPConnection, odpovídá spojení s HTTP serverem, druhá, HTTPResponse, reprezentuje odpověď HTTP serveru.

Nejprve tedy vytvoříme spojení, instanci HTTPConnection. Té musíme předat adresu počítače, na který se má připojit. Můžeme uvést i port, na němž běží HTTP server. Není-li číslo portu uvedeno, použije se standardní 80. Číslo portu předáme buď jako samostatný argument nebo může být součástí adresy počítače (podobdně jako je tomu u třídy SMTP).

Po vytvoření instance již můžeme serveru zasílat požadavky pomocí metody request(). Její první argument je název metody (např. ‚GET‘, ‚PUT‘), druhý je URL, jehož se tato metoda týká (např. ‚/index.html‘). Dále mohou následovat nepovinné argumenty, první jsou data, která budou poslána jako součást požadavku, přičemž hodnota hlavičky Content-Lenght je automaticky nastavena na velikost dat. Druhý nepovinný argument může být associativní pole, které reprezentuje hlavičky předané spolu s požadavkem (např. {‚User-Agent‘: ‚X-browser/3.0‘}).

Po odeslání požadavku zavoláme metodu getresponse(), která vrátí instanci třídy HTTPResponse, pomocí níž můžeme přečíst odpověd serveru.

Po získání odpovědi můžeme buď zaslat další požadavek (pokud server podporuje HTTP/1.1) nebo ukončit spojení pomocí metody close(), která uzavře spojení se serverem. Další volání metody request() pak již nebude možné.

Instance třídy HTTPResponce vrácená metodou getresponse() obsahuje několik metod a atributů, sloužících k získání informací o odpovědi serveru. Nejdůležitější je metoda read(), která vrátí tělo odpovědi jako jediný řetězec. Další důležitá metoda je getheader() sloužící pro dotazování hlaviček. První argument je jméno hlavičky, jejíž hodnotu chceme získat. Metodě můžeme předat i druhý, nepovinný argument, který bude použit jako návratová hodnota v případě, že požadovaná hlavička není nalezena.

Ve zkratce ještě zmiňme další atributy. Především version, který udává používanou verzi protokolu HTTP (pro HTTP/1.0 je to číslo 10, pro HTTP/1.1 pak 11). Další dvojice atributů – status a reason – úzce souvisí, jedná se totiž o návratový kód odpovědi. status odpovídá jeho číslu, reason pak obsahuje řetězec vypovídající více o samotném návratovém kódu.

Následuje příklad (po jeho vykonání obsahuje proměnná data úvodní stránku serveru www.root.cz):

>>> from httplib import HTTPConnection
>>> conn = HTTPConnection('www.root.cz')

>>> conn.request('GET', '/')
>>> r = conn.getresponse()
>>> print r.status, r.reason
200 OK
>>> data = r.read()
>>> conn.close()
MODUL urllib

Modul urllib je vysokoúrovňová nadstavba nad moduly httplib a ftplib. Dokáže rovněž pracovat s lokálními soubory. Dokáže otevřít soubory pomocí protokolů HTTP a FTP a nakonec vrátí souborový objekt, který má stejné rozhraní jako standardní souborový objekt vrácený funkcí open(). (Má však omezenou funkcionalitu, podporovány jsou pouze metody read(), readline(), readlines(), fileno() a close()).

Pro základní práci s modulem urllib stačí znát jedinou funkci – urlopen(). Té předáme URL, která chceme otevřít a ona vrátí souborový objekt:

>>> from urllib import urlopen
>>> f = urlopen('http://www.root.cz')
>>> r = f.read()

Tento příklad provádí přesně totéž, co výše uvedený příklad použití modul httplib. Pokud URL neobsahuje schema (čili http:, ftp: nebo file:) je automaticky předpokládán lokální souborový systém, čili schema file:.

Modul urllib nabízí i třídu URLOpener, pomocí níž můžeme dokonaleji řídit přístup ke vzdáleným souborů a hlavně přistupovat k serverům FTP, aniž by byl na obrazovku vypsán prompt pro zadání hesla. Tato třída totiž obsahuje metodu prompt_user_pas­swd(), jejíž předefinováním získáme požadované chování. Více o modulu urllib a třídě URLOpener naleznete ve standardní dokumentaci jazyka Python.

CS24_early

PŘÍŠŤĚ

V příštím díle se budeme věnovat dalším zajímavým a velice důležitým modulům. Budou to moduly pro vytvoření bezpečného prostředí určeného ke spouštění nedůvěryhodného kódu. Znalci již vědí, že se bude jednat o dvojici rexec a Bastion.

Byl pro vás článek přínosný?