Comment envoyer une requête HTTP HEAD en Python 2?

114

Ce que j'essaie de faire ici, c'est d'obtenir les en-têtes d'une URL donnée afin que je puisse déterminer le type MIME. Je veux pouvoir voir si http://somedomain/foo/retournera un document HTML ou une image JPEG par exemple. Ainsi, je dois comprendre comment envoyer une requête HEAD afin de pouvoir lire le type MIME sans avoir à télécharger le contenu. Quelqu'un connaît-il un moyen facile de faire cela?

fuentesjr
la source

Réponses:

104

edit : Cette réponse fonctionne, mais de nos jours, vous devez simplement utiliser la bibliothèque de requêtes comme mentionné par d'autres réponses ci-dessous.


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

Il y a aussi un getheader(name)pour obtenir un en-tête spécifique.

Évoli
la source
2
cette réponse a marqué comme répondu mais il faut regarder les requêtes lib. Regardez la réponse de Dalius qui est un peu plus bas.
Bahadir Cambel
C'est vraiment sympa, mais cela vous oblige à avoir des valeurs séparées pour l'hôte et le chemin de la requête. Il est utile d'avoir urlparsesous la main, ce qui est montré par une réponse de rang inférieur.
Tomasz Gandor
7
Remarque pour Python 3; httplibest renommé en http.client.
Santosh Kumar
2
Malheureusement, requestsn'est pas livré avec Python par défaut.
tour du
@rook n'est pas non plus votre programme :)
Evoli
109

urllib2 peut être utilisé pour exécuter une requête HEAD. C'est un peu plus agréable que d'utiliser httplib car urllib2 analyse l'URL pour vous au lieu de vous obliger à diviser l'URL en nom d'hôte et chemin.

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

Les en-têtes sont disponibles via response.info () comme auparavant. Fait intéressant, vous pouvez trouver l'URL vers laquelle vous avez été redirigé:

>>> print response.geturl()
http://www.google.com.au/index.html
doshea
la source
1
response.info () .__ str __ () retournera le format de chaîne de l'en-tête, au cas où vous voudriez faire quelque chose avec le résultat obtenu.
Shane
6
sauf que d'essayer cela avec python 2.7.1 (ubuntu natty), s'il y a une redirection, il fait un GET sur la destination, pas un HEAD ...
eichin
1
C'est l'avantage du httplib.HTTPConnection, qui ne gère pas automatiquement les redirections.
Ehtesh Choudhury
mais avec la réponse de doshea. comment définir le délai d'expiration? Comment gérer les mauvaises URL, c'est-à-dire les URL qui ne sont plus actives.
fanchyna
65

RequestsManière obligatoire :

import requests

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

Je pense que la bibliothèque Requests devrait également être mentionnée.

Daliusd
la source
5
Cette réponse mérite plus d'attention. On dirait une assez bonne bibliothèque qui rend le problème trivial.
Nick Retallack
3
Je suis d'accord. C'était très simple de faire des requêtes: {code} demandes d'importation r = requests.head (' github.com' ) {code}
Luis R.
@LuisR .: s'il y a une redirection, elle suit également GET / POST / PUT / DELETE.
jfs
@Nick Retallack: il n'y a pas de moyen simple de désactiver les redirections. allow_redirectsne peut désactiver que les redirections POST / PUT / DELETE. Exemple: head request no redirect
jfs
@JFSebastian Le lien vers votre exemple semble être rompu. Pourriez-vous élaborer sur le problème des redirections suivantes?
Piotr Dobrogost
17

Juste:

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

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

Edit: je viens de réaliser qu'il y a 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'
...

texte du lien

Paweł Prażak
la source
Légèrement désagréable en ce que vous laissez get_method comme une fonction non liée plutôt que de la lier à request. (À savoir, cela fonctionnera mais c'est un mauvais style et si vous vouliez l'utiliser self- difficile.)
Chris Morgan
4
Pourriez-vous nous en dire un peu plus sur les avantages et les inconvénients de cette solution? Je ne suis pas un expert de Python comme vous pouvez le voir, donc je pourrais bénéficier de savoir quand cela peut mal tourner;) Pour autant que je sache, le problème est que c'est un hack qui peut ou non fonctionner en fonction du changement d'implémentation?
Paweł Prażak
Cette deuxième version de ce code est la seule qui a fonctionné pour moi pour une URL avec un 403 interdit. D'autres lançaient une exception.
duality_
10

Pour être complet, avoir une réponse Python3 équivalente à la réponse acceptée en utilisant httplib .

Il est fondamentalement le même code juste que la bibliothèque est pas appelée httplib plus mais 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
la source
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
la source
Quels sont les signes dollar avant import? +1 pour le urlparse- avec, httplibils donnent le confort de urllib2, lorsqu'il s'agit d'URL du côté de l'entrée.
Tomasz Gandor
1

En passant, lors de l'utilisation de httplib (au moins sur 2.5.2), essayer de lire la réponse d'une requête HEAD bloquera (sur readline) et échouera par la suite. Si vous n'émettez pas de lecture sur la réponse, vous ne parvenez pas à envoyer une autre demande sur la connexion, vous devrez en ouvrir une nouvelle. Ou acceptez un long délai entre les demandes.


la source
1

J'ai trouvé que httplib est légèrement plus rapide que urllib2. J'ai chronométré deux programmes - l'un utilisant httplib et l'autre utilisant urllib2 - envoyant des requêtes HEAD à 10000 URL. Celui de httplib était plus rapide de plusieurs minutes. Les statistiques totales de httplib étaient: utilisateur réel 6m21.334s 0m2.124s sys 0m16.372s

Et les statistiques totales de urllib2 étaient les suivantes: utilisateur réel de 9m1.380s 0m16.666s sys 0m28.565s

Quelqu'un d'autre a-t-il des commentaires à ce sujet?

IgorGanapolsky
la source
Contribution? Le problème est lié aux E / S et vous utilisez des bibliothèques de blocage. Passez à eventlet ou tordu si vous voulez de meilleures performances. Les limitations de urllib2 que vous mentionnez sont liées au processeur.
Devin Jeanpierre
3
urllib2 suit les redirections, donc si certaines de vos URL redirigent, ce sera probablement la raison de la différence. Et, httplib est plus bas niveau, urllib2 analyse l'url par exemple.
Marian
1
urllib2 n'est qu'une fine couche d'abstraction au-dessus de httplib, je serais très surpris si vous étiez lié au processeur à moins que les URL ne soient sur un LAN très rapide. Est-il possible que certaines des URL soient des redirections? urllib2 suivra les redirections alors que httplib ne le ferait pas. L'autre possibilité est que les conditions du réseau (tout ce que vous n'avez pas de contrôle explicite dans cette expérience) ont fluctué entre les 2 exécutions. vous devriez faire au moins 3 exécutions entrelacées de chacun pour réduire cette probabilité
John La Rooy
0

Et encore une autre approche (similaire à la réponse de Pawel):

import urllib2
import types

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

Juste pour éviter d'avoir des méthodes illimitées au niveau de l'instance.

estani
la source
-4

Probablement plus simple: utilisez urllib ou urllib2.

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

f.info () est un objet de type dictionnaire, vous pouvez donc faire 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

La documentation note que httplib n'est normalement pas utilisé directement.


la source
14
Cependant, urllib fera un GET et la question est de réaliser un HEAD. Peut-être que l'affiche ne veut pas récupérer un document coûteux.
Philippe F