Wie senden Sie eine HEAD HTTP-Anfrage in Python 2?

113

Ich versuche hier, die Header einer bestimmten URL abzurufen, damit ich den MIME-Typ bestimmen kann. Ich möchte sehen können, ob beispielsweise http://somedomain/foo/ein HTML-Dokument oder ein JPEG-Bild zurückgegeben wird. Daher muss ich herausfinden, wie eine HEAD-Anfrage gesendet wird, damit ich den MIME-Typ lesen kann, ohne den Inhalt herunterladen zu müssen. Kennt jemand einen einfachen Weg, dies zu tun?

fuentesjr
quelle

Antworten:

103

Bearbeiten : Diese Antwort funktioniert, aber heutzutage sollten Sie nur die Anforderungsbibliothek verwenden, wie in anderen Antworten unten erwähnt.


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

Es gibt auch getheader(name)einen bestimmten Header.

Eevee
quelle
2
Diese Antwort wird als beantwortet markiert, aber man sollte sich die Anfragen lib ansehen . Schauen Sie sich die Antwort des Dalius an, die etwas weiter unten steht.
Bahadir Cambel
Das ist wirklich schön, erfordert jedoch separate Werte für den Host und den Pfad der Anforderung. Es ist nützlich, urlparsezur Hand zu haben , was durch eine Antwort mit niedrigerem Rang angezeigt wird.
Tomasz Gandor
6
Hinweis für Python 3; httplibwird umbenannt in http.client.
Santosh Kumar
2
Wird leider requestsnicht standardmäßig mit Python ausgeliefert.
Turm
@ Rook ist auch nicht Ihr Programm :)
Eevee
108

urllib2 kann verwendet werden, um eine HEAD-Anforderung auszuführen. Dies ist etwas besser als die Verwendung von httplib, da urllib2 die URL für Sie analysiert, anstatt dass Sie die URL in Hostnamen und Pfad aufteilen müssen.

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

Header sind wie bisher über response.info () verfügbar. Interessanterweise finden Sie die URL, zu der Sie umgeleitet wurden:

>>> print response.geturl()
http://www.google.com.au/index.html
Doshea
quelle
1
response.info () .__ str __ () gibt das Zeichenfolgenformat des Headers zurück, falls Sie mit dem erhaltenen Ergebnis etwas anfangen möchten.
Shane
6
mit der Ausnahme, dass dies mit Python 2.7.1 (Ubuntu Natty) versucht wird, wenn es eine Weiterleitung gibt, es ein GET am Ziel macht, kein HEAD ...
Eichin
1
Das ist der Vorteil von httplib.HTTPConnection, der Weiterleitungen nicht automatisch verarbeitet.
Ehtesh Choudhury
aber mit Dosheas Antwort. Wie stelle ich das Timeout ein? Umgang mit fehlerhaften URLs, dh URLs, die nicht mehr aktiv sind.
Fanchyna
65

Obligatorischer RequestsWeg:

import requests

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

Ich glaube, die Anforderungsbibliothek sollte ebenfalls erwähnt werden.

Daliusd
quelle
5
Diese Antwort verdient mehr Aufmerksamkeit. Sieht aus wie eine ziemlich gute Bibliothek, die das Problem trivial macht.
Nick Retallack
3
Ich stimme zu Es war sehr einfach, Anfragen zu stellen: {code} Importanfragen r = request.head (' github.com' ) {code}
Luis R.
@LuisR.: Wenn es eine Umleitung gibt, folgt auch GET / POST / PUT / DELETE.
JFS
@ Nick Retallack: Es gibt keine einfache Möglichkeit, Weiterleitungen zu deaktivieren. allow_redirectskann nur POST / PUT / DELETE-Weiterleitungen deaktivieren. Beispiel: Kopf Anfrage keine Weiterleitung
jfs
@JFSebastian Der Link zu Ihrem Beispiel scheint unterbrochen zu sein. Könnten Sie das Problem mit den folgenden Weiterleitungen näher erläutern?
Piotr Dobrogost
17

Gerade:

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

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

Bearbeiten: Ich habe gerade festgestellt, dass es httplib2: D gibt

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'
...

Link Text

Paweł Prażak
quelle
Etwas böse, weil Sie get_method als ungebundene Funktion verlassen, anstatt sie zu binden request. (Das heißt, es wird funktionieren, aber es ist ein schlechter Stil und wenn Sie es verwenden wollten self- hart.)
Chris Morgan
4
Könnten Sie etwas mehr über die Vor- und Nachteile dieser Lösung erläutern? Wie Sie sehen, bin ich kein Python-Experte, daher kann ich davon profitieren, wenn ich weiß, wann es schlecht werden kann;) Soweit ich weiß, besteht die Sorge darin, dass es sich um einen Hack handelt, der je nach Implementierungsänderung möglicherweise funktioniert oder nicht.
Paweł Prażak
Diese zweite Version in diesem Code ist die einzige, die für mich für eine URL mit einem 403 Forbidden funktioniert hat. Andere warfen eine Ausnahme.
Dualität_
9

Der Vollständigkeit halber muss eine Python3-Antwort der akzeptierten Antwort mit httplib entsprechen .

Es ist im Grunde der gleiche Code nur , dass die Bibliothek nicht genannt wird httplib mehr , sondern 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
quelle
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
quelle
Was sind die Dollarzeichen vorher import? +1 für die urlparse- zusammen mit httplibgeben sie den Komfort von urllib2, wenn sie mit URLs auf der Eingabeseite umgehen.
Tomasz Gandor
1

Wenn Sie die httplib verwenden (mindestens in 2.5.2), wird der Versuch, die Antwort einer HEAD-Anforderung zu lesen, blockiert (in der Readline) und schlägt anschließend fehl. Wenn Sie die Antwort nicht lesen, können Sie keine weitere Anfrage für die Verbindung senden. Sie müssen eine neue öffnen. Oder akzeptieren Sie eine lange Verzögerung zwischen Anfragen.


quelle
1

Ich habe festgestellt, dass httplib etwas schneller als urllib2 ist. Ich habe zwei Programme zeitgesteuert - eines mit httplib und das andere mit urllib2 - und HEAD-Anfragen an 10.000 URLs gesendet. Die httplib war um einige Minuten schneller. Die Gesamtstatistik von httplib war: real 6m21.334s Benutzer 0m2.124s sys 0m16.372s

Und die Gesamtstatistik von urllib2 war: real 9m1.380s Benutzer 0m16.666s sys 0m28.565s

Hat noch jemand einen Beitrag dazu?

IgorGanapolsky
quelle
Eingang? Das Problem ist E / A-gebunden und Sie verwenden blockierende Bibliotheken. Wechseln Sie zu Eventlet oder Twisted, wenn Sie eine bessere Leistung wünschen. Die von Ihnen erwähnten Einschränkungen von urllib2 sind CPU-gebunden.
Devin Jeanpierre
3
urllib2 folgt Weiterleitungen. Wenn also einige Ihrer URLs umleiten, ist dies wahrscheinlich der Grund für den Unterschied. Und httplib ist niedriger, urllib2 analysiert zum Beispiel die URL.
Marian
1
urllib2 ist nur eine dünne Abstraktionsebene über httplib. Ich wäre sehr überrascht, wenn Sie an die CPU gebunden wären, es sei denn, die URLs befinden sich in einem sehr schnellen LAN. Ist es möglich, dass einige der URLs Weiterleitungen waren? urllib2 folgt den Weiterleitungen, httplib nicht. Die andere Möglichkeit besteht darin, dass die Netzwerkbedingungen (alles, worüber Sie in diesem Experiment keine explizite Kontrolle haben) zwischen den beiden Läufen schwankten. Sie sollten mindestens 3 verschachtelte Läufe von jedem machen, um diese Wahrscheinlichkeit zu verringern
John La Rooy
0

Und noch ein anderer Ansatz (ähnlich der Antwort von Pawel):

import urllib2
import types

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

Nur um unbegrenzte Methoden auf Instanzebene zu vermeiden.

estani
quelle
-4

Wahrscheinlich einfacher: Verwenden Sie urllib oder urllib2.

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

f.info () ist ein wörterbuchähnliches Objekt, daher können Sie f.info () ['Inhaltstyp'] usw. ausführen.

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

In den Dokumenten wird darauf hingewiesen, dass httplib normalerweise nicht direkt verwendet wird.


quelle
14
Urllib führt jedoch ein GET durch und die Frage betrifft die Durchführung eines HEAD. Vielleicht möchte das Poster kein teures Dokument abrufen.
Philippe F