¿Cómo se envía una solicitud HEAD HTTP en Python 2?

114

Lo que trato de hacer aquí es obtener los encabezados de una URL determinada para poder determinar el tipo MIME. Quiero poder ver si http://somedomain/foo/devolveré un documento HTML o una imagen JPEG, por ejemplo. Por lo tanto, necesito averiguar cómo enviar una solicitud HEAD para poder leer el tipo MIME sin tener que descargar el contenido. ¿Alguien conoce una forma fácil de hacer esto?

fuentesjr
fuente

Respuestas:

104

editar : esta respuesta funciona, pero hoy en día solo debe usar la biblioteca de solicitudes como se menciona en otras respuestas a continuación.


Utilice httplib .

>>> 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')]

También hay una getheader(name)opción para obtener un encabezado específico.

Eevee
fuente
2
esta respuesta marcada como respondida, pero uno debe mirar las solicitudes lib. Mire la respuesta de Dalius que está un poco más abajo.
Bahadir Cambel
Esto es realmente bueno, pero requiere que tenga valores separados para el host y la ruta de la solicitud. Es útil tenerlo urlparsea mano, lo que se muestra mediante una respuesta de menor rango.
Tomasz Gandor
7
Nota para Python 3; httplibse renombra a http.client.
Santosh Kumar
2
Desafortunadamente, requestsno se envía con Python de forma predeterminada.
torre
@rook tampoco es tu programa :)
Eevee
109

urllib2 se puede utilizar para realizar una solicitud HEAD. Esto es un poco más agradable que usar httplib, ya que urllib2 analiza la URL por usted en lugar de requerir que divida la URL en nombre de host y ruta.

>>> import urllib2
>>> class HeadRequest(urllib2.Request):
...     def get_method(self):
...         return "HEAD"
... 
>>> response = urllib2.urlopen(HeadRequest("http://google.com/index.html"))

Los encabezados están disponibles a través de response.info () como antes. Curiosamente, puede encontrar la URL a la que fue redirigido:

>>> print response.geturl()
http://www.google.com.au/index.html
doshea
fuente
1
response.info () .__ str __ () devolverá el formato de cadena del encabezado, en caso de que desee hacer algo con el resultado obtenido.
Shane
6
excepto que al intentar esto con python 2.7.1 (ubuntu natty), si hay una redirección, hace un GET en el destino, no un HEAD ...
eichin
1
Esa es la ventaja de httplib.HTTPConnection, que no maneja los redireccionamientos automáticamente.
Ehtesh Choudhury
pero con la respuesta de doshea. ¿Cómo configurar el tiempo de espera? Cómo manejar URL incorrectas, es decir, URL que ya no están activas.
fanchyna
65

Forma obligatoria Requests:

import requests

resp = requests.head("http://www.google.com")
print resp.status_code, resp.text, resp.headers
KZ
fuente
36

Creo que la biblioteca de solicitudes también debería mencionarse.

daliusd
fuente
5
Esta respuesta merece más atención. Parece una biblioteca bastante buena que hace que el problema sea trivial.
Nick Retallack
3
Estoy de acuerdo Fue muy simple hacer solicitudes: {código} solicitudes de importación r = solicitudes.head (' github.com' ) {código}
Luis R.
@LuisR .: si hay una redirección, también sigue a GET / POST / PUT / DELETE.
jfs
@Nick Retallack: no hay una manera fácil de desactivar las redirecciones. allow_redirectssolo puede deshabilitar las redirecciones POST / PUT / DELETE. Ejemplo: solicitud de encabezado sin redireccionamiento
jfs
@JFSebastian El enlace a su ejemplo parece estar roto. ¿Podría explicar el problema de los siguientes redireccionamientos?
Piotr Dobrogost
17

Sólo:

import urllib2
request = urllib2.Request('http://localhost:8080')
request.get_method = lambda : 'HEAD'

response = urllib2.urlopen(request)
response.info().gettype()

Editar: Me acabo de dar cuenta de que hay httplib2: D

import httplib2
h = httplib2.Http()
resp = h.request("http://www.google.com", 'HEAD')
assert resp[0]['status'] == 200
assert resp[0]['content-type'] == 'text/html'
...

Texto del enlace

Paweł Prażak
fuente
Ligeramente desagradable porque está dejando get_method como una función no vinculada en lugar de vincularla a request. (A saber, funcionará, pero es de mal estilo y si quisieras usarlo self, difícil)
Chris Morgan
4
¿Podría explicar un poco más los pros y los contras de esta solución? No soy un experto en Python como puede ver, por lo que podría beneficiarme saber cuándo puede volverse malo;) Tan rápido como tengo entendido, la preocupación es que es un truco que puede o no funcionar dependiendo del cambio de implementación.
Paweł Prażak
Esta segunda versión de este código es la única que me funcionó para una URL con 403 Forbidden. Otros estaban lanzando una excepción.
dualidad_
10

Para completar, tener una respuesta de Python3 equivalente a la respuesta aceptada usando httplib .

Básicamente es el mismo código, solo que la biblioteca ya no se llama httplib sino http.client

from http.client import HTTPConnection

conn = HTTPConnection('www.google.com')
conn.request('HEAD', '/index.html')
res = conn.getresponse()

print(res.status, res.reason)
Octavian A. Damiean
fuente
2
import httplib
import urlparse

def unshorten_url(url):
    parsed = urlparse.urlparse(url)
    h = httplib.HTTPConnection(parsed.netloc)
    h.request('HEAD', parsed.path)
    response = h.getresponse()
    if response.status/100 == 3 and response.getheader('Location'):
        return response.getheader('Location')
    else:
        return url
Pranay Agarwal
fuente
¿Cuáles son los signos de dólar antes import? +1 para urlparse- junto con httplibellos brindan la comodidad de urllib2, cuando se trata de URL en el lado de entrada.
Tomasz Gandor
1

Como acotación al margen, cuando se usa httplib (al menos en 2.5.2), intentar leer la respuesta de una solicitud HEAD se bloqueará (en readline) y posteriormente fallará. Si no emite leer en la respuesta, no puede enviar otra solicitud en la conexión, deberá abrir una nueva. O acepte una gran demora entre solicitudes.


fuente
1

Descubrí que httplib es un poco más rápido que urllib2. Calculé el tiempo de dos programas, uno con httplib y el otro con urllib2, enviando solicitudes HEAD a 10,000 URL. El httplib uno fue más rápido en varios minutos. Las estadísticas totales de httplib fueron: real 6m21.334s usuario 0m2.124s sys 0m16.372s

Y las estadísticas totales de urllib2 fueron: real 9m1.380s usuario 0m16.666s sys 0m28.565s

¿Alguien más tiene comentarios sobre esto?

IgorGanapolsky
fuente
¿Entrada? El problema está vinculado a IO y está utilizando bibliotecas de bloqueo. Cambie a eventlet o twisted si desea un mejor rendimiento. Las limitaciones de urllib2 que menciona están vinculadas a la CPU.
Devin Jeanpierre
3
urllib2 sigue las redirecciones, por lo que si algunas de sus URL redirigen, probablemente esa sea la razón de la diferencia. Y, httplib es más de bajo nivel, urllib2 analiza la URL, por ejemplo.
Marian
1
urllib2 es solo una fina capa de abstracción encima de httplib, me sorprendería mucho si estuviera vinculado a la CPU a menos que las URL estén en una LAN muy rápida. ¿Es posible que algunas de las URL sean redireccionamientos? urllib2 seguirá las redirecciones, mientras que httplib no. La otra posibilidad es que las condiciones de la red (cualquier cosa sobre la que no tenga un control explícito en este experimento) fluctuaran entre las 2 ejecuciones. debe hacer al menos 3 ejecuciones intercaladas de cada una para reducir esta probabilidad
John La Rooy
0

Y otro enfoque (similar a la respuesta de Pawel):

import urllib2
import types

request = urllib2.Request('http://localhost:8080')
request.get_method = types.MethodType(lambda self: 'HEAD', request, request.__class__)

Solo para evitar tener métodos ilimitados a nivel de instancia.

estani
fuente
-4

Probablemente más fácil: use urllib o urllib2.

>>> import urllib
>>> f = urllib.urlopen('http://google.com')
>>> f.info().gettype()
'text/html'

f.info () es un objeto similar a un diccionario, por lo que puede hacer f.info () ['content-type'], etc.

http://docs.python.org/library/urllib.html
http://docs.python.org/library/urllib2.html
http://docs.python.org/library/httplib.html

Los documentos señalan que httplib normalmente no se usa directamente.


fuente
14
Sin embargo, urllib hará un GET y la pregunta es sobre realizar un HEAD. Tal vez el cartel no quiera recuperar un documento caro.
Philippe F