Jak wysłać żądanie HTTP HEAD w Pythonie 2?

114

To, co próbuję tutaj zrobić, to uzyskać nagłówki podanego adresu URL, aby móc określić typ MIME. Chcę mieć możliwość sprawdzenia, czy http://somedomain/foo/na przykład zwróci dokument HTML lub obraz JPEG. Dlatego muszę dowiedzieć się, jak wysłać żądanie HEAD, aby móc odczytać typ MIME bez konieczności pobierania zawartości. Czy ktoś zna łatwy sposób na zrobienie tego?

fuentesjr
źródło

Odpowiedzi:

104

edycja : Ta odpowiedź działa, ale obecnie powinieneś po prostu skorzystać z biblioteki żądań, jak wspomniano w innych odpowiedziach poniżej.


Użyj 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')]

Istnieje również, getheader(name)aby uzyskać określony nagłówek.

Eevee
źródło
2
ta odpowiedź została oznaczona jako odpowiedź, ale należy spojrzeć na żądania lib. Spójrz na odpowiedź Daliusa, która jest nieco poniżej.
Bahadir Cambel
To naprawdę fajne, ale wymaga oddzielnych wartości dla hosta i ścieżki żądania. Warto mieć urlparsepod ręką, o czym świadczą odpowiedzi o niższej randze.
Tomasz Gandor
7
Uwaga dotycząca Pythona 3; httplibzostała zmieniona na http.client.
Santosh Kumar
2
Niestety, requestsnie jest dostarczany domyślnie z Pythonem.
wieża
@rook też nie jest twoim programem :)
Eevee
109

urllib2 może służyć do wykonywania żądania HEAD. Jest to trochę przyjemniejsze niż użycie httplib, ponieważ urllib2 analizuje adres URL za Ciebie, zamiast wymagać podzielenia adresu URL na nazwę hosta i ścieżkę.

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

Nagłówki są dostępne przez response.info (), jak poprzednio. Co ciekawe, możesz znaleźć adres URL, na który zostałeś przekierowany:

>>> print response.geturl()
http://www.google.com.au/index.html
doshea
źródło
1
response.info () .__ str __ () zwróci nagłówek w formacie ciągu, na wypadek gdybyś chciał coś zrobić z uzyskanym wynikiem.
Shane
6
z wyjątkiem tego, że próbując tego z Pythonem 2.7.1 (ubuntu natty), jeśli istnieje przekierowanie, wykonuje GET w miejscu docelowym, a nie HEAD ...
eichin
1
To zaleta httplib.HTTPConnection, która nie obsługuje przekierowań automatycznie.
Ehtesh Choudhury
ale z odpowiedzią doshei. jak ustawić limit czasu? Jak radzić sobie ze złymi adresami URL, tj. Takimi, które już nie istnieją.
fanchyna 19.08.13
65

Obowiązkowy Requestssposób:

import requests

resp = requests.head("http://www.google.com")
print resp.status_code, resp.text, resp.headers
KZ
źródło
36

Uważam, że należy również wspomnieć o bibliotece Requests .

daliusd
źródło
5
Ta odpowiedź zasługuje na więcej uwagi. Wygląda na całkiem niezłą bibliotekę, która sprawia, że ​​problem jest trywialny.
Nick Retallack
3
Zgadzam się Złożenie żądań było bardzo proste: {code} żądania importu r = requests.head (' github.com' ) {code}
Luis R.,
@LuisR .: jeśli istnieje przekierowanie, następuje również GET / POST / PUT / DELETE.
jfs
@Nick Retallack: nie ma łatwego sposobu na wyłączenie przekierowań. allow_redirectsmoże wyłączyć tylko przekierowania POST / PUT / DELETE. Przykład: żądanie nagłówka bez przekierowania
jfs
@JFSebastian Odnośnik do twojego przykładu wydaje się być uszkodzony. Czy mógłbyś rozwinąć problem z następującymi przekierowaniami?
Piotr Dobrogost
17

Właśnie:

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

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

Edycja: właśnie zdałem sobie sprawę, że istnieje 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'
...

tekst linku

Paweł Prażak
źródło
Nieco nieprzyjemne, ponieważ zostawiasz get_method jako niezwiązaną funkcję, zamiast ją wiązać request. (Mianowicie, to zadziała, ale to zły styl i jeśli chcesz go użyć self- ciężko.)
Chris Morgan,
4
Czy mógłbyś opowiedzieć trochę więcej o zaletach i wadach tego rozwiązania? Nie jestem ekspertem od Pythona, jak widzisz, więc mogę skorzystać, wiedząc, kiedy może się zepsuć;) O ile rozumiem, obawa jest, że jest to hack, który może działać lub nie w zależności od zmiany implementacji?
Paweł Prażak
Ta druga wersja w tym kodzie jest jedyną, która działała dla mnie w przypadku adresu URL z zakazem 403. Inni rzucali wyjątek.
duality_
10

Aby uzyskać kompletność, odpowiedź w Pythonie3 jest równoważna zaakceptowanej odpowiedzi przy użyciu protokołu httplib .

To jest w zasadzie taki sam kod tylko że biblioteka nie jest nazywany httplib już jednak 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
źródło
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
źródło
Jakie były wcześniej znaki dolara import? +1 dla urlparse- razem z httplibnimi dają wygodę urllib2, gdy mamy do czynienia z adresami URL po stronie wejściowej.
Tomasz Gandor
1

Nawiasem mówiąc, podczas korzystania z httplib (przynajmniej w wersji 2.5.2), próba odczytania odpowiedzi na żądanie HEAD zostanie zablokowana (w readline), a następnie zakończy się niepowodzeniem. Jeśli nie odczytasz odpowiedzi, nie możesz wysłać kolejnego żądania na połączeniu, będziesz musiał otworzyć nowe. Lub zaakceptuj duże opóźnienie między żądaniami.


źródło
1

Zauważyłem, że httplib jest nieco szybszy niż urllib2. Zsynchronizowałem dwa programy - jeden używający httplib, a drugi urllib2 - wysyłający żądania HEAD do 10000 adresów URL. Protokół httplib był szybszy o kilka minut. httplib „s łączne statystyki były: real 6m21.334s 0m2.124s użytkownik SYS 0m16.372s

A łączne statystyki urllib2 to: real 9m1.380s użytkownik 0m16.666s sys 0m28.565s

Czy ktoś ma w tej sprawie jakiś wkład?

IgorGanapolsky
źródło
Wejście? Problem jest związany z IO i używasz bibliotek blokujących. Przejdź na eventlet lub twisted, jeśli chcesz mieć lepszą wydajność. Wspomniane ograniczenia urllib2 są związane z procesorem.
Devin Jeanpierre
3
urllib2 podąża za przekierowaniami, więc jeśli niektóre z twoich adresów URL przekierowują, prawdopodobnie będzie to przyczyną różnicy. A httplib jest niższy poziom, urllib2 na przykład analizuje adres URL.
Marian
1
urllib2 to tylko cienka warstwa abstrakcji na górze httplib, byłbym bardzo zaskoczony, gdybyś był powiązany z cpu, chyba że adresy URL znajdują się w bardzo szybkiej sieci LAN. Czy to możliwe, że niektóre adresy URL były przekierowaniami? urllib2 będzie podążać za przekierowaniami, podczas gdy httplib nie. Inną możliwością jest to, że warunki sieciowe (wszystko, nad czym nie masz wyraźnej kontroli w tym eksperymencie) wahały się między dwoma przebiegami. powinieneś zrobić co najmniej 3 przeplatane przebiegi każdego, aby zmniejszyć to prawdopodobieństwo
John La Rooy,
0

I jeszcze inne podejście (podobne do odpowiedzi Pawła):

import urllib2
import types

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

Tylko po to, by uniknąć nieograniczonych metod na poziomie instancji.

estani
źródło
-4

Prawdopodobnie łatwiej: użyj urllib lub urllib2.

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

f.info () jest obiektem podobnym do słownika, więc możesz wykonać f.info () ['content-type'] itd.

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

Dokumentacja zauważa, że ​​httplib nie jest zwykle używany bezpośrednio.


źródło
14
Jednak urllib wykona GET i pytanie dotyczy wykonania HEAD. Może plakat nie chce odzyskać drogiego dokumentu.
Philippe F