Como você envia uma solicitação HEAD HTTP no Python 2?

114

O que estou tentando fazer aqui é obter os cabeçalhos de um determinado URL para determinar o tipo de MIME. Eu quero ser capaz de ver se http://somedomain/foo/retornarei um documento HTML ou uma imagem JPEG, por exemplo. Portanto, preciso descobrir como enviar uma solicitação HEAD para poder ler o tipo MIME sem ter que baixar o conteúdo. Alguém conhece uma maneira fácil de fazer isso?

Fuentesjr
fonte

Respostas:

104

editar : Esta resposta funciona, mas hoje em dia você deve apenas usar a biblioteca de solicitações conforme mencionado nas outras respostas abaixo.


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

Também existe um getheader(name)para obter um cabeçalho específico.

Eevee
fonte
2
esta resposta foi marcada como respondida, mas deve-se olhar para a biblioteca de solicitações . Veja a resposta de Dalius um pouco abaixo.
Bahadir Cambel
Isso é muito bom, mas requer que você tenha valores separados para o host e o caminho da solicitação. É útil ter urlparseà mão, o que é mostrado por algumas respostas de classificação inferior.
Tomasz Gandor
7
Nota para Python 3; httplibfoi renomeado para http.client.
Santosh Kumar
2
Infelizmente, requestsnão é fornecido com Python por padrão.
torre
@rook também não é o seu programa :)
Eevee
109

urllib2 pode ser usado para executar uma solicitação HEAD. Isso é um pouco melhor do que usar o httplib, já que o urllib2 analisa a URL para você em vez de exigir que você divida a URL em nome de host e caminho.

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

Os cabeçalhos estão disponíveis via response.info () como antes. Curiosamente, você pode encontrar o URL para o qual foi redirecionado:

>>> print response.geturl()
http://www.google.com.au/index.html
Doshea
fonte
1
response.info () .__ str __ () retornará o formato de string do cabeçalho, caso você queira fazer algo com o resultado obtido.
Shane,
6
exceto que tentar isso com python 2.7.1 (ubuntu natty), se houver um redirecionamento, ele faz um GET no destino, não um HEAD ...
eichin
1
Essa é a vantagem do httplib.HTTPConnection, que não controla os redirecionamentos automaticamente.
Ehtesh Choudhury
mas com a resposta de Doshea. como definir o tempo limite? Como lidar com URLs ruins, ou seja, URLs que não estão mais vivos.
fanchyna de
65

RequestsForma obrigatória :

import requests

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

Eu acredito que a biblioteca Requests deve ser mencionada também.

Daliusd
fonte
5
Essa resposta merece mais atenção. Parece uma biblioteca muito boa que torna o problema trivial.
Nick Retallack
3
Concordo. Era muito simples fazer solicitações: {code} import requests r = requests.head (' github.com' ) {code}
Luis R.
@LuisR .: se houver um redirecionamento, ele também seguirá GET / POST / PUT / DELETE.
jfs de
@Nick Retallack: não há uma maneira fácil de desabilitar redirecionamentos. allow_redirectspode desativar apenas redirecionamentos POST / PUT / DELETE. Exemplo: solicitação principal sem redirecionamento
jfs de
@JFSebastian O link para o seu exemplo parece estar quebrado. Você poderia explicar o problema dos redirecionamentos a seguir?
Piotr Dobrogost
17

Somente:

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

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

Edit: Acabei de perceber que existe 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 do link

Paweł Prażak
fonte
Um pouco desagradável porque você está deixando get_method como uma função não vinculada em vez de vinculá-la a request. (Viz, vai funcionar, mas é um estilo ruim e se você quiser usar selfnele - difícil.)
Chris Morgan
4
Você poderia elaborar um pouco mais sobre os prós e os contras dessa solução? Não sou um especialista em Python, como você pode ver, então poderia me beneficiar sabendo quando ele pode ficar ruim;) Pelo que eu entendo, a preocupação é que é um hack que pode ou não funcionar dependendo da mudança na implementação.
Paweł Prażak
Esta segunda versão neste código é a única que funcionou para mim para um URL com 403 Forbidden. Outros estavam lançando uma exceção.
dualidade_
10

Para ser completo, tenha uma resposta Python3 equivalente à resposta aceita usando httplib .

É basicamente o mesmo código, só que a biblioteca não é mais chamada de httplib, mas de 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
fonte
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
fonte
Quais são os cifrões antes import? +1 para o urlparse- junto com httplibeles fornecem o conforto de urllib2, ao lidar com URLs no lado da entrada.
Tomasz Gandor
1

Como um aparte, ao usar o httplib (pelo menos em 2.5.2), tentar ler a resposta de uma solicitação HEAD irá bloquear (em readline) e subsequentemente falhar. Se você não emitir ler na resposta, você não conseguirá enviar outra solicitação na conexão, você precisará abrir uma nova. Ou aceite um longo atraso entre os pedidos.


fonte
1

Eu descobri que o httplib é um pouco mais rápido que o urllib2. Cronometrei dois programas - um usando httplib e outro usando urllib2 - enviando solicitações HEAD para 10.000 URLs. O httplib foi mais rápido por vários minutos. As estatísticas totais de httplib foram: real 6m21.334s usuário 0m2.124s sys 0m16.372s

E as estatísticas totais do urllib2 foram: real 9m1.380s usuário 0m16.666s sys 0m28.565s

Alguém mais tem opinião sobre isso?

IgorGanapolsky
fonte
Entrada? O problema é vinculado ao IO e você está usando bibliotecas de bloqueio. Mude para eventlet ou twisted se quiser melhor desempenho. As limitações do urllib2 que você menciona são vinculadas à CPU.
Devin Jeanpierre
3
urllib2 segue redirecionamentos, portanto, se algum de seus URLs redirecionar, provavelmente esse será o motivo da diferença. E ,httplib é mais de baixo nível, urllib2 analisa o url, por exemplo.
Marian
1
urllib2 é apenas uma camada fina de abstração sobre o httplib. Eu ficaria muito surpreso se você estivesse vinculado à CPU, a menos que os urls estejam em uma LAN muito rápida. É possível que alguns dos URLs tenham sido redirecionados? urllib2 seguirá os redirecionamentos, ao passo que httplib não. A outra possibilidade é que as condições da rede (qualquer coisa que você não tenha controle explícito neste experimento) flutuaram entre as 2 execuções. você deve fazer pelo menos 3 execuções intercaladas de cada para reduzir essa probabilidade
John La Rooy
0

E ainda outra abordagem (semelhante à resposta de Pawel):

import urllib2
import types

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

Apenas para evitar métodos ilimitados no nível da instância.

Estani
fonte
-4

Provavelmente mais fácil: use urllib ou urllib2.

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

f.info () é um objeto semelhante a um dicionário, então você pode fazer 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

Os documentos observam que httplib normalmente não é usado diretamente.


fonte
14
No entanto, o urllib fará um GET e a questão é sobre como realizar um HEAD. Talvez o autor da postagem não queira recuperar um documento caro.
Philippe F