Pour Python
Pyro
- Python Remote Objects, pour développer une application client serveur en appelant des classes distantes comme si elles étaient locales (un peu comme RMI pour Java)
Twisted Python
- Twisted Python est un framework qui devrait simplifier la programmation reseau avec Python:
Exemples de code
FTP
Rien de plus facile que d'envoyer un fichier par FTP:
import ftplib # On importe le module FTP de Python session = ftplib.FTP('212.12.34.56','sebsauvage','batman') # On se connecte au serveur (serveur, login, mot de passe) monfichier = open('toto.txt','rb') # On ouvre le fichier à envoyer session.storbinary('STOR toto.txt', monfichier) # On envoie le fichier monfichier.close() # On ferme le fichier session.quit() # On se déconnecte
Vous avez bien entendu à votre disposition toutes les autres commandes FTP (lister un répertoire, changer de répertoire, reprendre un téléchargement interrompu, renommer un fichier...) dans le module ftplib. (Voir http://python.org/doc/current/lib/ftp-objects.html)
un mini serveur HTTP
from BaseHTTPServer import HTTPServer from SimpleHTTPServer import SimpleHTTPRequestHandler import os os.chdir('/home/oli/dev/python/httpserver') # le répertoire où les pages html seront stockées. serv = HTTPServer( ("", 10080), SimpleHTTPRequestHandler) serv.serve_forever()
Dans ce répertoire, vous placer un fichier index.html, ainsi que toutes les autres pages.
Avant dernière ligne: 10080 est le port réseau utilisé. Les ports inférieurs ou égaux à 1024 ne sont utilisables que par root.
PS: très pratique pour échanger des fichiers de machines à machines lorsque FTP n'est pas disponible.
Une article plus complet est disponible a cette adresse:
http://etudiant.epita.fr/~duponc_j/articles/webinterface.html
récupérer un forum Usenet (newsgroups, NNTP)
Voici un petit programme qui permet de récupérer tous les messages d'un forum. Chaque message est sauvegardé dans un fichier individuel. Vous pouvez à tout moment interrompre le script et le relancer: il reprendra là où il en était.
http://sebsauvage.net/python/newsarchiver.py
En lançant ce script tous les jours, vous pouvez ainsi archiver tous les messages d'un forum.
Sockets
Un exemple simple
Vous trouverez dans la documentation de Python un exemple de serveur et client socket très simple: http://docs.python.org/lib/socket-example.html
Le serveur se met en écoute sur le port 50007, et le client vient s'y connecter pour écrire "Hello, world". Le serveur renvoie cette chaîne au client.
Sockets non bloquants
Par défaut, l'utilisation de sockets est bloquant (lors d'un .recv() par exemple).
Pour travailler avec des sockets non bloquants, vous avez 2 solutions:
- les sockets asynchrones
- les threads
Chaque solution a ses avantages.
Les sockets asynchrones sont intéressants quand votre goulot d'étranglement est le débit réseau.
Les threads sont intéressants quand votre goulot d'étranglement est le traitement CPU.
Voici un article en anglais avec des exemples pour chacune de ces méthodes: http://www.onlamp.com/pub/a/python/2004/02/12/advanced_nio.html
Pour faire des sockets asynchrone, vous pouvez utiliser les module asyncore et asynchat de Python. Notez qu'il existe des frameworks qui simplifient l'utilisation des sockets asynchrone, tels que Twisted http://www.twistedmatrix.com/.
Pour les threads, le module thread de Python est à votre disposition. Le module threading vous offre même une interface de plus haut niveau, plus simple à manipuler.
Les proxy
Les modules urllib et urllib2 vous permettent de faire des requêtes HTTP.
urllib2 s'utilise de la même façon qu'urllib, mais il supporte également les proxy, avec ou sans mot de passe.
Voici comment l'utiliser. (Code inspiré de http://groups.google.com/groups?selm=mailman.983901970.11969.python-list%40python.org)
Passer par un proxy
1 proxy_info = { 'host' : 'netcache.monentreprise.com',
2 'port' : 3128
3 }
4 # On créé un handler pour le proxy:
5 proxy_support = urllib2.ProxyHandler({"http" : "http://%(host)s:%(port)d" % proxy_info})
6 # On créé un opener utilisant ce handler:
7 opener = urllib2.build_opener(proxy_support)
8 # Puis on installe cet opener comme opener par défaut du module urllib2.
9 urllib2.install_opener(opener)
10
11 # Et on peut alors lancer nos requêtes HTTP:
12 pagehtml = urllib2.urlopen("http://wikipython.flibuste.net/").read()
Passer par un proxy avec mot de passe
C'est presque la même chose, mais on ajoute login et mot de passe:
1 proxy_info = { 'host' : 'netcache.monentreprise.com',
2 'port' : 3128,
3 'user' : 'gaston lagaffe',
4 'pass' : 'jeanne55'
5 }
6 proxy_support = urllib2.ProxyHandler({"http" : "http://%(user)s:%(pass)s@%(host)s:%(port)d" % proxy_info})
7 opener = urllib2.build_opener(proxy_support)
8 urllib2.install_opener(opener)
9
10 # Et on peut alors lancer nos requêtes HTTP:
11 pagehtml = urllib2.urlopen("http://wikipython.flibuste.net/").read()
Modification : urllib2 ne semble pas fonctionner avec l'authentification proxy. Ceci est apparemment un bug connu. La librairie pycurl est la plus avancée sur ce sujet
Note de sebsauvage: Si si ça marche, j'utilise urllib2 avec proxy (et login/mot de passe) sans problème dans webGobbler (http://sebsauvage.net/webgobbler). Notez qu'il existe plusieurs méthodes d'authentification pour les proxy HTTP: Basic, Digest, NTLM... En Python 2.4.1, urllib2 supporte 2 authentifications: Basic et Digest. Si votre proxy ne supporte que NTLM (protocole Microsoft, supporté par Internet Explorer), vous n'avez pas de chance.
Passer par un proxy avec mot de passe vi Authentification Proxy
La methode precedente ne fonctionne pas sur mon proxy: (authentification via un serveur de domaine NT), j'ai donc implementé un Handler Basic d'Authentification (Proxy compatible heureusement) au lieu du Handler de Proxy standard. Pour ceux dont le proxy est compatible Digest choisir ProxyDigestAuthHandler.
1 import urllib2
2
3 passwdMgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
4 passwdMgr.add_password(None, "proxy:8080", r"DOMAINE\jvacher", "monpassamoi")
5 opener = urllib2.build_opener(urllib2.ProxyBasicAuthHandler(passwdMgr))
6 urllib2.install_opener(opener)
7
8 pagehtml = urllib2.urlopen("http://wikipython.flibuste.net/").read()
9 print pagehtml
Voilà j'éspère que cela en aidera certains. Jérôme Vacher alias jerrykhan
urllib/urllib2
User-agent
En principe, si vous avez créé une application qui envoie des requêtes HTTP, la netiquette dit qu'elle devrait s'identifier proprement dans le champ "User-Agent" des requêtes HTTP.
Par défaut, Python utilise le User-Agent Python-urllib/1.16
Voici comment mettre votre propre User-Agent:
En règle générale:
- Assurez-vous que votre user agent n'existe pas déjà (recherchez sur Googe).
Adoptez le format nomDuProgramme/version, par exemple webGobbler/1.2.4
Si votre programme parcours des sites web, il devrait respecter les robot rules: http://en.wikipedia.org/wiki/Robots_Exclusion_Standard
- Utilisez toujours des .read() limités (.read(200000) et pas .read())
- Choisissez bien le timeout réseau (que vous pouvez régler avec: socket.setdefaulttimeout(60) )
Gestion d'erreur
Voici comment gérer les codes d'erreur HTTP (404 et autres) avec urllib2:
1 try:
2 urlfile = urllib2.urlopen('http://sebsauvage.net/nonexistingpage.html')
3 except urllib2.HTTPError, exc:
4 if exc.code == 404:
5 print "Page non trouvée !"
6 else:
7 print "La requête HTTP a échoué avec le code %d (%s)" % (exc.code, exc.msg)
8 except urllib2.URLError, exc:
9 print "Echec. Cause:", exc.reason
De cette manière, vous pouvez tester les 404 et autres codes d'erreur HTTP. Notez que urllib2 ne lèvera pas d'exception pour les codes 2xx et 3xx. L'exception urllib2.HTTPError sera levée pour les codes 4xx et 5xx (ce qui est le comportement attendu).
Notez également que les codes de redirection 30x sont gérés automatiquement et de manière transparente par urllib2.
Content-type
Quand vous envoyez une requête HTTP, elle peut retourner du HTML, des images, des fichiers zip... Par exemple, une requête comme http: //toto.com/image.gif peut très bien retourner du HTML ! Il est nécessaire de contrôller le type des données que vous recevez.
Il suffit de regarder dans le champ "Content-type" des entêtes HTTP de réponse. Par exemple:
Ce qui donne par exemple:
Le type de document est text/html
Mais attention, il arrive qu'il y ait des informations supplémentaires, telles que:
Le type de document est text/html; charset=iso-8859-1
Donc je vous recommande d'utiliser systématiquement:
1 print "Document type is", urlfile.info().getheader("Content-Type","").split(';')[0].strip()
pour être sûr de bien récupérer le Content-type seul.
Notez que .info() vous donnera les autres entêtes réponse HTTP:
ce qui donne des choses telles que:
Document type is Date: Thu, 23 Mar 2006 15:13:29 GMT Content-Type: text/html; charset=iso-8859-1 Server: Apache X-Powered-By: PHP/5.1.2-1.dotdeb.2 Connection: close
Gérer les cookies
Depuis la version 2.4, Python contient le module cookielib qui peut gérer automatiquement les cookies.
(Notez qu'il est possible d'avoir une gestion des cookies dans les versions précédentes de Python avec des modules séparés tels que ClientCookie).
Les cookies sont utile pour parcourir les sites qui nécessite un login/password: Ces sites gèrent habituellement les sessions avec un cookie.
Voici un exemple: Se loguer sur le site imdb.com:
1 import cookielib, urllib, urllib2
2
3 login = 'ismellbacon123@yahoo.com'
4 password = 'login'
5
6 # On active le support des cookies pour urllib2
7 cookiejar = cookielib.CookieJar()
8 urlOpener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookiejar))
9
10 # On envoie login/password au site qui nous renvoie un cookie de session
11 values = {'login':login, 'password':password }
12 data = urllib.urlencode(values)
13 request = urllib2.Request("http://www.imdb.com/register/login", data)
14 url = urlOpener.open(request) # Notre cookiejar reçoit automatiquement les cookies
15 page = url.read(500000)
16
17 # On s'assure qu'on est bien logué en vérifiant la présence du cookie "id"
18 # (qui est - sur le site imdb.com - le cookie contenant l'identifiant de session.)
19 if not 'id' in [cookie.name for cookie in cookiejar]:
20 raise ValueError, "Echec connexion avec login=%s, mot de passe=%s" % (login,password)
21
22 print "Nous sommes connecte !"
23
24 # Maintenant on fait une autre requête sur le site avec notre cookie de session.
25 # (Notre urlOpener utilise automatiquement les cookies de notre cookiejar)
26 url = urlOpener.open('http://imdb.com/find?s=all&q=grave')
27 page = url.read(200000)
Il n'est généralement pas utile de vous déloguer.