Python: Obtiene encabezados HTTP de urllib2.¿urlopen call?


¿urllib2 obtiene toda la página cuando se realiza una llamada urlopen?

Me gustaría leer el encabezado de respuesta HTTP sin obtener la página. Parece que urllib2 abre la conexión HTTP y luego obtiene la página HTML real... ¿o simplemente comienza a almacenar en búfer la página con la llamada 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
Author: crazyhatfish, 2009-05-09

6 answers

Use el método response.info() para obtener los encabezados.

De la urllib2 docs:

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

...

Esta función devuelve un objeto similar a un archivo con dos métodos adicionales:

  • geturl () - devuelve la URL del recurso recuperado, comúnmente utilizado para determinar si se siguió una redirección
  • info () - devuelve la meta-información de la página, como encabezados, en forma de un httplib.Instancia HttpMessage (consulte Referencia rápida a Encabezados HTTP)

Así que, para su ejemplo, intente pasar por el resultado de response.info().headers para lo que está buscando.

Tenga en cuenta la advertencia principal para usar httplib.HttpMessage está documentado en python issue 4773.

 45
Author: tolmeda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-11 03:07:38

¿Qué hay de enviar una solicitud HEAD en lugar de una solicitud GET normal? El siguiente fragmento (copiado de una pregunta similar ) hace exactamente eso.

>>> 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')]
 40
Author: reto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:11

En realidad, parece que urllib2 puede hacer una petición HTTP HEAD.

La pregunta a la que @reto enlazó, arriba, muestra cómo hacer que urllib2 haga una petición HEAD.

Aquí está mi opinión:

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)

Si comprueba esto con algo como el protocolo de red Wireshark analazer, puede ver que en realidad está enviando una solicitud HEAD, en lugar de un GET.

Esta es la solicitud HTTP y la respuesta del código anterior, según lo capturado por Wireshark:

HEAD / doFeT HTTP / 1.1
Accept-Encoding: identity
Host: bit.ly
Conexión: cerrar
Agente de usuario: Python-urllib/2.7

HTTP / 1.1 301 Moved
Servidor: nginx
Fecha: Dom, 19 Feb 2012 13:20: 56 GMT
Content-Type: text / html; charset = utf-8{[16]]} Cache-control: private; max-age = 90
Ubicación: http://www.kidsidebyside.org/?p=445
MIME-Version: 1.0
Contenido-Longitud: 127
Conexión: cerrar
Set-Cookie: _bit = 4f40f738-00153-02ed0-421cf10a;domain=.bit.ly; expires = Vie Aug 17 13: 20: 56 2012; path=/; HttpOnly

Sin embargo, como se mencionó en uno de los comentarios en la otra pregunta, si la URL en cuestión incluye una redirección, urllib2 hará una solicitud GET al destino, no a HEAD. Esto podría ser un defecto importante, si realmente quieres hacer solo peticiones de CABEZA.

La solicitud anterior implica una redirección. Aquí está la petición a la destino, según lo capturado por Wireshark:

OBTENER /2009/05/ven y dibuja el círculo de la unidad con nosotros / HTTP / 1.1
Accept-Encoding: identidad
Host: www.kidsidebyside.org
Conexión: close
Agente de usuario: Python-urllib/2.7

Una alternativa al uso de urllib2 es usar la biblioteca de 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)

Esto tiene la ventaja de usar peticiones HEAD tanto para la petición HTTP inicial como para la petición redirigida a la URL de destino.

Aquí está la primera petición:

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

Aquí está la segunda petición, al destino:

CABEZA /2009/05/ven y dibuja el círculo de la unidad con nosotros / HTTP / 1.1
Anfitrión: www.kidsidebyside.org
accept-encoding: gzip, deflate{[16]]} agente de usuario: Python-httplib2 / 0.7.2 (gzip)

 20
Author: Simon Tewsi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:17:42

Urllib2.urlopen hace un HTTP GET (o POST si proporciona un argumento de datos), no un HTTP HEAD (si lo hizo, no podría hacer readlines u otros accesos al cuerpo de la página, por supuesto).

 8
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-09 14:18:33

One-liner:

$ python -c "import urllib2; print urllib2.build_opener(urllib2.HTTPHandler(debuglevel=1)).open(urllib2.Request('http://google.com'))"
 5
Author: quanta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-30 08:11:23
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  
 -1
Author: vitperov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-28 09:25:02