Come si invia una richiesta HTTP HEAD in Python 2?


114

Quello che sto cercando di fare qui è ottenere le intestazioni di un determinato URL in modo da poter determinare il tipo MIME. Voglio essere in grado di vedere se http://somedomain/foo/restituirà un documento HTML o un'immagine JPEG, ad esempio. Pertanto, ho bisogno di capire come inviare una richiesta HEAD in modo da poter leggere il tipo MIME senza dover scaricare il contenuto. Qualcuno conosce un modo semplice per farlo?

Risposte:


104

modifica : questa risposta funziona, ma al giorno d'oggi dovresti semplicemente usare la libreria delle richieste come menzionato da altre risposte di seguito.


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

C'è anche un getheader(name)per ottenere un'intestazione specifica.


2
questa risposta contrassegnata come risposta ma si dovrebbe guardare le richieste lib. Guarda la risposta di Dalio che è un po 'sotto.
Bahadir Cambel

Questo è davvero carino, ma richiede di avere valori separati per l'host e il percorso della richiesta. È utile averlo urlparsea portata di mano, il che è dimostrato da una risposta di livello inferiore.
Tomasz Gandor

7
Nota per Python 3; httplibviene rinominato in http.client.
Santosh Kumar

2
Sfortunatamente, requestsnon viene fornito con Python per impostazione predefinita.
torre

@rook non è nemmeno il tuo programma :)
Eevee

109

urllib2 può essere utilizzato per eseguire una richiesta HEAD. Questo è un po 'più carino rispetto all'utilizzo di httplib poiché urllib2 analizza l'URL per te invece di richiederti di dividere l'URL in nome host e percorso.

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

Le intestazioni sono disponibili tramite response.info () come prima. È interessante notare che puoi trovare l'URL a cui sei stato reindirizzato:

>>> print response.geturl()
http://www.google.com.au/index.html

1
response.info () .__ str __ () restituirà il formato stringa dell'intestazione, nel caso tu voglia fare qualcosa con il risultato che ottieni.
Shane

6
tranne che provando questo con python 2.7.1 (ubuntu natty), se c'è un reindirizzamento, fa un GET sulla destinazione, non una HEAD ...
eichin

1
Questo è il vantaggio di httplib.HTTPConnection, che non gestisce automaticamente i reindirizzamenti.
Ehtesh Choudhury

ma con la risposta di Doshea. come impostare il timeout? Come gestire gli URL non validi, ovvero gli URL che non sono più attivi.
fanchyna

65

RequestsModo obbligatorio :

import requests

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

36

Credo che anche la libreria Requests dovrebbe essere menzionata.


5
Questa risposta merita più attenzione. Sembra una libreria piuttosto buona che rende il problema banale.
Nick Retallack

3
Accetto È stato molto semplice fare richieste: {code} import requests r = requests.head (' github.com' ) {code}
Luis R.

@LuisR .: se c'è un reindirizzamento, segue anche GET / POST / PUT / DELETE.
jfs

@ Nick Retallack: non esiste un modo semplice per disabilitare i reindirizzamenti. allow_redirectspuò disabilitare solo i reindirizzamenti POST / PUT / DELETE. Esempio: richiesta principale senza reindirizzamento
jfs

@JFSebastian Il collegamento al tuo esempio sembra essere interrotto. Potresti approfondire il problema con i seguenti reindirizzamenti?
Piotr Dobrogost

17

Appena:

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

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

Modifica: mi sono appena reso conto che esiste 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'
...

testo del collegamento


Un po 'sgradevole in quanto stai lasciando get_method come una funzione non associata invece di vincolarla a request. (Vale a dire, funzionerà ma è un pessimo stile e se vuoi usarlo self- duro.)
Chris Morgan

4
Potresti approfondire un po 'di più sui pro e contro di questa soluzione? Non sono un esperto di Python come puoi vedere, quindi potrei trarre vantaggio dal sapere quando può diventare cattivo;) Per quanto ho capito, la preoccupazione è che sia un hack che potrebbe o non potrebbe funzionare a seconda del cambiamento di implementazione?
Paweł Prażak

Questa seconda versione in questo codice è l'unica che ha funzionato per me per un URL con un 403 Forbidden. Altri lanciavano un'eccezione.
dualità_

10

Per completezza, avere una risposta Python3 equivalente alla risposta accettata utilizzando httplib .

E 'sostanzialmente lo stesso codice solo che la libreria non si chiama httplib più ma 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)

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

Quali sono i segni del dollaro prima import? +1 per il urlparse- insieme a httplibdanno la comodità di urllib2, quando si tratta di URL sul lato di input.
Tomasz Gandor

1

Per inciso, quando si usa httplib (almeno su 2.5.2), provare a leggere la risposta di una richiesta HEAD si bloccherà (su readline) e successivamente fallirà. Se non esegui la lettura della risposta, non sei in grado di inviare un'altra richiesta sulla connessione, dovrai aprirne una nuova. Oppure accetta un lungo ritardo tra le richieste.


1

Ho scoperto che httplib è leggermente più veloce di urllib2. Ho cronometrato due programmi, uno utilizzando httplib e l'altro utilizzando urllib2, inviando richieste HEAD a 10.000 URL. Quello httplib è stato più veloce di diversi minuti. Le statistiche totali di httplib erano: reali 6m21.334s utente 0m2.124s sys 0m16.372s

E le statistiche totali di urllib2 erano: reali 9m1.380s utente 0m16.666s sys 0m28.565s

Qualcun altro ha input su questo?


Ingresso? Il problema è legato all'IO e stai usando le librerie di blocco. Passa a eventlet o twisted se desideri prestazioni migliori. I limiti di urllib2 che hai menzionato sono legati alla CPU.
Devin Jeanpierre

3
urllib2 segue i reindirizzamenti, quindi se alcuni dei tuoi URL vengono reindirizzati, questo sarà probabilmente il motivo della differenza. E, httplib è di livello più basso, urllib2 analizza l'URL per esempio.
Marian

1
urllib2 è solo un sottile strato di astrazione sopra httplib, sarei molto sorpreso se fossi legato alla cpu a meno che gli URL non siano su una LAN molto veloce. È possibile che alcuni degli URL fossero reindirizzamenti? urllib2 seguirà i reindirizzamenti mentre httplib no. L'altra possibilità è che le condizioni della rete (qualsiasi cosa di cui non hai un controllo esplicito in questo esperimento) abbiano fluttuato tra le 2 prove. dovresti fare almeno 3 corse interlacciate di ciascuna per ridurre questa probabilità
John La Rooy,

0

E ancora un altro approccio (simile alla risposta di Pawel):

import urllib2
import types

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

Solo per evitare di avere metodi illimitati a livello di istanza.


-4

Probabilmente più semplice: usa urllib o urllib2.

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

f.info () è un oggetto simile a un dizionario, quindi puoi fare f.info () ['content-type'], ecc.

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

La documentazione nota che httplib normalmente non viene utilizzato direttamente.


14
Tuttavia, urllib eseguirà un GET e la domanda riguarda l'esecuzione di un HEAD. Forse il poster non vuole recuperare un documento costoso.
Philippe F
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.