Подтвердить что ты не робот

Python: Получить HTTP-заголовки от вызова urllib2.urlopen?

Получает ли urllib2 всю страницу при вызове urlopen?

Я бы хотел просто прочитать заголовок ответа HTTP без получения страницы. Похоже, что urllib2 открывает HTTP-соединение, а затем получает фактическую HTML-страницу... или просто начинает буферизацию страницы при вызове urlopen?

import urllib2
myurl = 'http://www.kidsidebyside.org/2009/05/come-and-draw-the-circle-of-unity-with-us/'
page = urllib2.urlopen(myurl) // open connection, get headers

html = page.readlines()  // stream page
4b9b3361

Ответ 1

Используйте метод response.info() для получения заголовков.

Из urllib2 docs:

urllib2.urlopen(url [, data] [, timeout])

...

Эта функция возвращает файл-подобный объект с двумя дополнительными методами:

  • geturl() - возвращает URL-адрес извлеченного ресурса, обычно используемый для определения того, выполнялось ли перенаправление
  • info() - вернуть метаинформацию страницы, например заголовки, в форме экземпляра httplib.HTTPMessage(см. краткую ссылку на заголовки HTTP).

Итак, для вашего примера попробуйте выполнить результат response.info().headers для того, что вы ищете.

Обратите внимание на основную оговорку в отношении использования httplib.HTTPMessage задокументирована в проблема с python 4773.

Ответ 2

Как насчет отправки запроса HEAD вместо обычного запроса GET. Следующий снимок (скопированный из аналогичного question) делает именно это.

>>> import httplib
>>> conn = httplib.HTTPConnection("www.google.com")
>>> conn.request("HEAD", "/index.html")
>>> res = conn.getresponse()
>>> print res.status, res.reason
200 OK
>>> print res.getheaders()
[('content-length', '0'), ('expires', '-1'), ('server', 'gws'), ('cache-control', 'private, max-age=0'), ('date', 'Sat, 20 Sep 2008 06:43:36 GMT'), ('content-type', 'text/html; charset=ISO-8859-1')]

Ответ 3

На самом деле, похоже, что urllib2 может выполнять запрос HTTP HEAD.

question, связанный с приведенной выше ссылкой @reto, показывает, как заставить urllib2 выполнять запрос HEAD.

Вот мой пример:

import urllib2

# Derive from Request class and override get_method to allow a HEAD request.
class HeadRequest(urllib2.Request):
    def get_method(self):
        return "HEAD"

myurl = 'http://bit.ly/doFeT'
request = HeadRequest(myurl)

try:
    response = urllib2.urlopen(request)
    response_headers = response.info()

    # This will just display all the dictionary key-value pairs.  Replace this
    # line with something useful.
    response_headers.dict

except urllib2.HTTPError, e:
    # Prints the HTTP Status code of the response but only if there was a 
    # problem.
    print ("Error code: %s" % e.code)

Если вы проверите это с чем-то вроде анализатора сетевого протокола Wireshark, вы увидите, что он фактически отправляет запрос HEAD, а не GET.

Это HTTP-запрос и ответ от кода выше, как показано Wireshark:

HEAD/doFeT HTTP/1.1
Accept-Encoding: identity
Хост: bit.ly
Соединение: закрыть
User-Agent: Python-urllib/2.7

HTTP/1.1 301 Перемещено
Сервер: nginx
Дата: Вс, 19 Фев 2012 13:20:56 GMT
Content-Type: text/html; кодировка = UTF-8
Кэш-контроль: частный; max-age = 90
Местоположение: http://www.kidsidebyside.org/?p=445
MIME-Version: 1.0
Контент-длина: 127
Подключение: закрыть
Set-Cookie: _bit = 4f40f738-00153-02ed0-421cf10a; domain =.bit.ly; expires = Fri Aug 17 13:20:56 2012; path =/; HttpOnly

Однако, как упоминалось в одном из комментариев в другом вопросе, если рассматриваемый URL-адрес включает перенаправление, то urllib2 выполнит запрос GET для адресата, а не HEAD. Это может стать серьезным недостатком, если вы действительно хотите только делать запросы HEAD.

Приведенный запрос включает перенаправление. Вот запрос к месту назначения, который был захвачен Wireshark:

GET/2009/05/come-and-draw-the-circle-of-unity-with-us/HTTP/1.1
Accept-Encoding: identity
Хост: www.kidsidebyside.org
Соединение: закрыть
User-Agent: Python-urllib/2.7

Альтернативой использованию urllib2 является использование Joe Gregorio httplib2 библиотека:

import httplib2

url = "http://bit.ly/doFeT"
http_interface = httplib2.Http()

try:
    response, content = http_interface.request(url, method="HEAD")
    print ("Response status: %d - %s" % (response.status, response.reason))

    # This will just display all the dictionary key-value pairs.  Replace this
    # line with something useful.
    response.__dict__

except httplib2.ServerNotFoundError, e:
    print (e.message)

Это имеет преимущество использования запросов HEAD для начального HTTP-запроса и перенаправленного запроса к целевому URL.

Здесь первый запрос:

HEAD/doFeT HTTP/1.1
Хост: bit.ly
accept-encoding: gzip, deflate
user-agent: Python-httplib2/0.7.2 (gzip)

Здесь второй запрос, к месту назначения:

HEAD/2009/05/come-and-draw-the-circle-of-unity-with-us/HTTP/1.1
Хост: www.kidsidebyside.org
accept-encoding: gzip, deflate
user-agent: Python-httplib2/0.7.2 (gzip)

Ответ 4

urllib2.urlopen выполняет HTTP GET (или POST, если вы поставляете аргумент данных), а не HTTP HEAD (если это было последним, вы, конечно, не могли бы читать строки для чтения или другие обращения к телу страницы).

Ответ 5

Однострочник:

$ python -c "import urllib2; print urllib2.build_opener(urllib2.HTTPHandler(debuglevel=1)).open(urllib2.Request('http://google.com'))"

Ответ 6

def _GetHtmlPage(self, addr):
  headers = { 'User-Agent' : self.userAgent,
            '  Cookie' : self.cookies}

  req = urllib2.Request(addr)
  response = urllib2.urlopen(req)

  print "ResponseInfo="
  print response.info()

  resultsHtml = unicode(response.read(), self.encoding)
  return resultsHtml