Bagaimana Anda mengirim permintaan HTTP HEAD dengan Python 2?

114

Apa yang saya coba lakukan di sini adalah mendapatkan header dari URL tertentu sehingga saya dapat menentukan jenis MIME. Saya ingin dapat melihat apakah http://somedomain/foo/akan mengembalikan dokumen HTML atau gambar JPEG misalnya. Oleh karena itu, saya perlu mencari cara untuk mengirim permintaan HEAD agar saya dapat membaca tipe MIME tanpa harus mengunduh konten. Adakah yang tahu cara mudah untuk melakukan ini?

fuentesjr
sumber

Jawaban:

104

edit : Jawaban ini berfungsi, tetapi saat ini Anda hanya harus menggunakan perpustakaan permintaan seperti yang disebutkan oleh jawaban lain di bawah ini.


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

Ada juga getheader(name)untuk mendapatkan tajuk tertentu.

Eevee
sumber
2
respon ini ditandai sebagai telah dijawab tetapi harus melihat permintaan lib. Lihatlah respon Dalius yang sedikit di bawah ini.
Bahadir Cambel
Ini sangat bagus, tetapi mengharuskan Anda memiliki nilai terpisah untuk host dan jalur permintaan. Ini berguna untuk dimiliki urlparse, yang ditunjukkan oleh beberapa tanggapan yang berperingkat lebih rendah.
Tomasz Gandor
7
Catatan untuk Python 3; httplibdiubah namanya menjadi http.client.
Santosh Kumar
2
Sayangnya, requeststidak dikirimkan dengan Python secara default.
Benteng
@rook juga bukan program Anda :)
Eevee
109

urllib2 dapat digunakan untuk melakukan permintaan HEAD. Ini sedikit lebih bagus daripada menggunakan httplib karena urllib2 mem-parsing URL untuk Anda alih-alih meminta Anda untuk membagi URL menjadi nama host dan jalur.

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

Header tersedia melalui response.info () seperti sebelumnya. Menariknya, Anda dapat menemukan URL tujuan Anda dialihkan:

>>> print response.geturl()
http://www.google.com.au/index.html
doshea
sumber
1
response.info () .__ str __ () akan mengembalikan format string dari header, jika Anda ingin melakukan sesuatu dengan hasil yang Anda dapatkan.
Shane
6
kecuali mencoba ini dengan python 2.7.1 (ubuntu natty), jika ada pengalihan, itu melakukan GET di tujuan, bukan KEPALA ...
eichin
1
Itulah keuntungan dari httplib.HTTPConnection, yang tidak menangani pengalihan secara otomatis.
Ehtesh Choudhury
tapi dengan jawaban doshea. bagaimana cara mengatur batas waktu? Bagaimana menangani URL yang buruk, yaitu URL yang tidak lagi hidup.
fanchyna
65

RequestsCara wajib :

import requests

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

Saya yakin pustaka Requests harus disebutkan juga.

daliusd
sumber
5
Jawaban ini perlu lebih diperhatikan. Sepertinya perpustakaan yang cukup bagus yang membuat masalah menjadi sepele.
Nick Retallack
3
Saya setuju Sangat mudah untuk membuat permintaan: {code} import request r = requests.head (' github.com' ) {code}
Luis R.
@LuisR .: jika ada redirect maka GET / POST / PUT / DELETE juga mengikuti.
jfs
@ Nick Retallack: tidak ada cara mudah untuk menonaktifkan pengalihan. allow_redirectshanya dapat menonaktifkan pengalihan POST / PUT / DELETE. Contoh: head request no redirect
jfs
@JFSebastian Tautan ke contoh Anda tampaknya rusak. Bisakah Anda menguraikan masalah terkait pengalihan berikut?
Piotr Dobrogost
17

Hanya:

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

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

Sunting: Saya baru saja menyadari ada 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'
...

teks tautan

Paweł Prażak
sumber
Sedikit buruk karena Anda membiarkan get_method sebagai fungsi tidak terikat daripada mengikatnya request. (Viz, itu akan berhasil tetapi itu gaya yang buruk dan jika Anda ingin menggunakannya self- sulit.)
Chris Morgan
4
Bisakah Anda menjelaskan lebih banyak tentang pro dan kontra dari solusi ini? Saya bukan ahli Python seperti yang Anda lihat, jadi saya bisa mendapatkan keuntungan mengetahui kapan itu bisa menjadi buruk;) Sejauh yang saya pahami, kekhawatirannya adalah bahwa ini adalah peretasan yang mungkin atau mungkin tidak berfungsi tergantung pada perubahan implementasi?
Paweł Prażak
Versi kedua dalam kode ini adalah satu-satunya yang berfungsi untuk saya untuk URL dengan 403 Forbidden. Yang lainnya membuat pengecualian.
dualitas_
10

Untuk kelengkapan, memiliki jawaban Python3 yang setara dengan jawaban yang diterima menggunakan httplib .

Ini pada dasarnya adalah kode yang sama hanya saja pustaka tidak lagi disebut httplib tetapi 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)
Oktavianus A. Damiean
sumber
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
sumber
Apa tanda dolar sebelumnya import? 1 untuk urlparse- bersama-sama dengan httplibmereka memberikan kenyamanan urllib2, ketika berurusan dengan URL di sisi masukan.
Tomasz Gandor
1

Sebagai tambahan, saat menggunakan httplib (setidaknya di 2.5.2), mencoba membaca respon dari permintaan HEAD akan memblokir (di readline) dan kemudian gagal. Jika Anda tidak mengeluarkan bacaan pada tanggapan, Anda tidak dapat mengirim permintaan lain pada koneksi, Anda harus membuka yang baru. Atau terima penundaan yang lama di antara permintaan.


sumber
1

Saya telah menemukan bahwa httplib sedikit lebih cepat dari urllib2. Saya menghitung waktu dua program - satu menggunakan httplib dan yang lainnya menggunakan urllib2 - mengirim permintaan HEAD ke 10.000 URL. Yang httplib lebih cepat beberapa menit. Statistik total httplib adalah: real 6m21.334s pengguna 0m2.124s sys 0m16.372s

Dan statistik total urllib2 adalah: real 9m1.380s user 0m16.666s sys 0m28.565s

Apakah ada orang lain yang punya masukan tentang ini?

IgorGanapolsky
sumber
Memasukkan? Masalahnya terikat dengan IO dan Anda menggunakan pustaka pemblokiran. Beralih ke eventlet atau twisted jika Anda menginginkan kinerja yang lebih baik. Batasan urllib2 yang Anda sebutkan terikat dengan CPU.
Devin Jeanpierre
3
urllib2 mengikuti pengalihan, jadi jika beberapa URL Anda mengalihkan, itu mungkin menjadi alasan perbedaannya. Dan, httpplib lebih rendah levelnya, urllib2 mengurai url misalnya.
Marian
1
urllib2 hanyalah lapisan tipis abstraksi di atas httplib, saya akan sangat terkejut jika Anda terikat cpu, kecuali jika url berada di LAN yang sangat cepat. Apakah mungkin beberapa url adalah pengalihan? urllib2 akan mengikuti arahan ulang sedangkan httplib tidak. Kemungkinan lainnya adalah kondisi jaringan (apa pun yang tidak Anda miliki kontrol eksplisitnya dalam eksperimen ini) berfluktuasi di antara 2 proses. Anda harus melakukan setidaknya 3 putaran interleaved masing-masing untuk mengurangi kemungkinan ini
John La Rooy
0

Dan pendekatan lain (mirip dengan jawaban Pawel):

import urllib2
import types

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

Hanya untuk menghindari metode tak terbatas di tingkat instance.

estani
sumber
-4

Mungkin lebih mudah: gunakan urllib atau urllib2.

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

f.info () adalah objek mirip kamus, jadi Anda bisa melakukan f.info () ['content-type'], dll.

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

Catatan dokumen bahwa httplib biasanya tidak digunakan secara langsung.


sumber
14
Namun, urllib akan melakukan GET dan pertanyaannya adalah tentang melakukan HEAD. Mungkin si pengepos tidak ingin mengambil dokumen mahal.
Philippe F