Получить html с помощью запросов Python?

Я пытаюсь научить себя некоторым базовым стираниям в Интернете. Используя модуль запросов Python, я смог захватить html для различных сайтов, пока не попробовал это:

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

Вместо базового html, являющегося источником для этой страницы, я получаю:

>>> 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...

Я пробовал много комбинаций get/post с каждым синтаксисом, который я могу угадать из документации и из SO и других примеров. Я не понимаю, что я вижу выше, не смог превратить его во все, что я могу прочитать, и не могу понять, как получить то, что я действительно хочу. Мой вопрос: как мне получить html для указанной выше страницы?

Ответ 1

Сервер, о котором идет речь, дает вам ответ gzipped. Сервер также очень сломан; он отправляет следующие заголовки:

$ 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

Строка <!DOCTYPE..> содержит не допустимый HTTP-заголовок. Таким образом, оставшиеся заголовки Server игнорируются. Почему сервер не вмешивается, что неясно; во всех возможных капюшонах WRCCWrappers.py есть CGI script, который не выводит заголовки, но включает двойную новую строку после строки doctype, дублируя сервер Apache, добавляя туда дополнительные заголовки.

Таким образом, requests также не обнаруживает, что данные кодируются gzip. Все данные есть, вам просто нужно его расшифровать. Или вы могли бы, если бы это было не совсем неполно.

Обход - это сказать серверу не беспокоить сжатие:

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

и возвращается несжатый ответ.

Кстати, на Python 2 анализатор HTTP-заголовков не так строг и ему удается объявить doctype заголовком:

>>> 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'}

и сохраняется content-encoding информация, поэтому requests декодирует контент для вас, как и ожидалось.

Ответ 2

Заголовки HTTP для этого URL-адреса теперь исправлены.

>>> 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'}