web-dev-qa-db-fra.com

Obtenez du HTML en utilisant Python requêtes?

J'essaie de m'enseigner quelques grattages Web de base. En utilisant le module de requêtes de Python, j'ai pu récupérer du HTML pour divers sites Web jusqu'à ce que j'essaye:

>>> r = requests.get('http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F')

Au lieu du HTML de base qui est la source de cette page, j'obtiens:

>>> r.text
'\x1f\ufffd\x08\x00\x00\x00\x00\x00\x00\x03\ufffd]o\u06f8\x12\ufffd\ufffd\ufffd+\ufffd]...

>>> r.content
b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xed\x9d]o\xdb\xb8\x12\x86\xef\xfb+\x88]\x14h...

J'ai essayé de nombreuses combinaisons de get/post avec toutes les syntaxes que je peux deviner à partir de la documentation et de SO et d'autres exemples. Je ne comprends pas ce que je vois ci-dessus, je n'ai pas pu pour le transformer en tout ce que je peux lire, et je ne sais pas comment obtenir ce que je veux réellement. Ma question est, comment puis-je obtenir le code html pour la page ci-dessus?

20
Rich Thompson

Le serveur en question vous donne une réponse gzippée . Le serveur est également très cassé ; il envoie les en-têtes suivants:

$ curl -D - -o /dev/null -s -H 'Accept-Encoding: gzip, deflate' http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F
HTTP/1.1 200 OK
Date: Tue, 06 Jan 2015 17:46:49 GMT
Server: Apache
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd"><html xmlns="http: //www.w3.org/1999/xhtml" lang="en-US">
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 3659
Content-Type: text/html

Le <!DOCTYPE..> il y a pas un en-tête HTTP valide. En tant que tel, les en-têtes restants après Server sont ignorés . Pourquoi le serveur interrompt cela n'est pas clair; dans toute la hotte probable WRCCWrappers.py est un script CGI qui ne produit pas d'en-têtes mais inclut un double retour à la ligne après la ligne doctype, dupant le serveur Apache à y insérer des en-têtes supplémentaires.

En tant que tel, requests ne détecte pas non plus le codage gzip des données. Les données sont là, il suffit de les décoder. Ou vous pourriez si ce n'était pas assez incomplet.

La solution consiste à dire au serveur de ne pas se soucier de la compression:

headers = {'Accept-Encoding': 'identity'}
r = requests.get(url, headers=headers)

et une réponse non compressée est renvoyée.

Par ailleurs, sur Python 2, l'analyseur d'en-tête HTTP n'est pas si strict et parvient à déclarer le doctype un en-tête:

>>> pprint(dict(r.headers))
{'<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "dtd/xhtml1-transitional.dtd"><html xmlns="http': '//www.w3.org/1999/xhtml" lang="en-US">',
 'connection': 'Keep-Alive',
 'content-encoding': 'gzip',
 'content-length': '3659',
 'content-type': 'text/html',
 'date': 'Tue, 06 Jan 2015 17:42:06 GMT',
 'keep-alive': 'timeout=5, max=100',
 'server': 'Apache',
 'vary': 'Accept-Encoding'}

et le content-encoding les informations survivent, donc requests décode le contenu pour vous, comme prévu.

17
Martijn Pieters

Les en-têtes HTTP pour cette URL ont maintenant été corrigés.

>>> import requests
>>> print requests.__version__
2.5.1
>>> r = requests.get('http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F')
>>> r.text[:100]
u'\n<!DOCTYPE html>\n<HTML>\n<HEAD><TITLE>Monthly Average of Precipitation, Station id: 028815</TITLE></H'
>>> r.headers
{'content-length': '3672', 'content-encoding': 'gzip', 'vary': 'Accept-Encoding', 'keep-alive': 'timeout=5, max=100', 'server': 'Apache', 'connection': 'Keep-Alive', 'date': 'Thu, 12 Feb 2015 18:59:37 GMT', 'content-type': 'text/html; charset=utf-8'}
3
Grant