คุณส่งคำขอ HEAD HTTP ใน Python 2 ได้อย่างไร


114

สิ่งที่ฉันพยายามทำที่นี่คือรับส่วนหัวของ URL ที่กำหนดเพื่อให้ฉันสามารถระบุประเภท MIME ได้ ฉันต้องการดูว่าhttp://somedomain/foo/จะส่งคืนเอกสาร HTML หรือรูปภาพ JPEG หรือไม่ ดังนั้นฉันต้องหาวิธีส่งคำขอ HEAD เพื่อให้ฉันสามารถอ่านประเภท MIME ได้โดยไม่ต้องดาวน์โหลดเนื้อหา ไม่มีใครรู้วิธีง่ายๆในการทำเช่นนี้?

คำตอบ:


104

แก้ไข : คำตอบนี้ใช้ได้ แต่ในปัจจุบันคุณควรใช้ไลบรารีคำขอตามที่ระบุไว้ในคำตอบอื่น ๆ ด้านล่าง


ใช้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')]

นอกจากนี้ยังมีgetheader(name)เพื่อรับส่วนหัวเฉพาะ


2
คำตอบนี้ทำเครื่องหมายว่าตอบแล้ว แต่ควรดูที่คำขอ lib ดูการตอบสนองของดาเลียสที่อยู่ด้านล่างเล็กน้อย
Bahadir Cambel

นี่เป็นสิ่งที่ดีจริงๆ แต่คุณต้องมีค่าแยกกันสำหรับโฮสต์และเส้นทางของคำขอ มันมีประโยชน์ที่จะมีurlparseอยู่ในมือซึ่งแสดงโดยการตอบกลับที่มีอันดับต่ำกว่า
Tomasz Gandor

7
หมายเหตุสำหรับ Python 3; จะเปลี่ยนชื่อเป็นhttplib http.client
Santosh Kumar

2
น่าเสียดายที่requestsไม่ได้จัดส่งมาพร้อมกับ Python โดยค่าเริ่มต้น
โกง

@rook ไม่ใช่โปรแกรมของคุณ :)
Eevee

109

urllib2สามารถใช้เพื่อดำเนินการร้องขอ HEAD นี่ดีกว่าการใช้ httplib เล็กน้อยเนื่องจาก urllib2 แยกวิเคราะห์ URL ให้คุณแทนที่จะต้องให้คุณแยก URL เป็นชื่อโฮสต์และเส้นทาง

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

ส่วนหัวพร้อมใช้งานผ่าน response.info () เหมือนเดิม ที่น่าสนใจคือคุณสามารถค้นหา URL ที่คุณถูกเปลี่ยนเส้นทางไป:

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

1
response.info () .__ str __ () จะส่งคืนรูปแบบสตริงของส่วนหัวในกรณีที่คุณต้องการทำบางสิ่งกับผลลัพธ์ที่คุณได้รับ
เชน

6
ยกเว้นว่าลองใช้ python 2.7.1 (ubuntu natty) ถ้ามีการเปลี่ยนเส้นทางมันจะ GET ที่ปลายทางไม่ใช่ HEAD ...
eichin

1
นั่นเป็นข้อดีของhttplib.HTTPConnectionซึ่งไม่จัดการการเปลี่ยนเส้นทางโดยอัตโนมัติ
Ehtesh Choudhury

แต่ด้วยคำตอบของ doshea วิธีตั้งค่าระยะหมดเวลา? วิธีจัดการ URL ที่ไม่ถูกต้องเช่น URL ที่ไม่มีชีวิตแล้ว
fanchyna


36

ฉันเชื่อว่าควรกล่าวถึงไลบรารีคำขอด้วยเช่นกัน


5
คำตอบนี้สมควรได้รับความสนใจมากขึ้น ดูเหมือนห้องสมุดที่ดีที่ทำให้ปัญหาไม่สำคัญ
Nick Retallack

3
ฉันยอมรับว่าการร้องขอเป็นเรื่องง่ายมาก: {code} คำขอนำเข้า r = request.head (' github.com' ) {code}
Luis R.

@LuisR: หากมีการเปลี่ยนเส้นทางจะเป็นไปตาม GET / POST / PUT / DELETE ด้วย
jfs

@Nick Retallack: ไม่มีวิธีง่ายๆในการปิดใช้งานการเปลี่ยนเส้นทาง allow_redirectsสามารถปิดใช้งานการเปลี่ยนเส้นทาง POST / PUT / DELETE เท่านั้น ตัวอย่าง: head request no redirect
jfs

@JFSebastian ลิงก์ไปยังตัวอย่างของคุณดูเหมือนจะเสีย คุณช่วยอธิบายปัญหาเกี่ยวกับการเปลี่ยนเส้นทางต่อไปนี้ได้ไหม
Piotr Dobrogost

17

แค่:

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

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

แก้ไข: ฉันเพิ่งมารู้ว่ามี 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'
...

ข้อความลิงก์


เล็กน้อยที่น่ารังเกียจในที่คุณกำลังจะออกจาก get_method requestเป็นฟังก์ชั่นไม่ได้ผูกไว้มากกว่าผูกพันมัน (ลองใช้งานได้ แต่มันเป็นสไตล์ที่ไม่ดีและถ้าคุณต้องการใช้selfมัน - ยาก)
Chris Morgan

4
คุณช่วยอธิบายเพิ่มเติมเกี่ยวกับข้อดีข้อเสียของโซลูชันนี้ได้ไหม ฉันไม่ใช่ผู้เชี่ยวชาญ Python อย่างที่คุณเห็นดังนั้นฉันจะได้รับประโยชน์เมื่อรู้ว่ามันจะเปลี่ยนไปเมื่อไหร่) ตามที่ฉันเข้าใจว่ามันเป็นแฮ็กที่อาจได้หรือไม่ได้ขึ้นอยู่กับการเปลี่ยนแปลงการใช้งาน?
PawełPrażak

เวอร์ชันที่สองในรหัสนี้เป็นเวอร์ชันเดียวที่ใช้ได้กับฉันสำหรับ URL ที่มี 403 Forbidden คนอื่น ๆ ก็โยนข้อยกเว้น
duality_

10

เพื่อความสมบูรณ์ที่จะมีคำตอบที่เทียบเท่า Python3 เพื่อคำตอบที่ได้รับการยอมรับโดยใช้httplib

โดยพื้นฐานแล้วเป็นรหัสเดียวกันกับที่ไลบรารีไม่ได้เรียกว่าHTTplibอีกต่อไป แต่เป็น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

อะไรคือสัญญาณดอลลาร์ก่อนหน้านี้import? +1 สำหรับurlparse- ร่วมกับhttplibพวกเขาให้ความสะดวกสบายurllib2เมื่อจัดการกับ URL ที่ด้านอินพุต
Tomasz Gandor

1

นอกจากนี้เมื่อใช้ HTTplib (อย่างน้อยใน 2.5.2) การพยายามอ่านการตอบสนองของคำขอ HEAD จะบล็อก (ใน readline) และล้มเหลวในภายหลัง หากคุณไม่ได้อ่านคำตอบคุณจะไม่สามารถส่งคำขออื่นเกี่ยวกับการเชื่อมต่อได้คุณจะต้องเปิดคำขอใหม่ หรือยอมรับความล่าช้าเป็นเวลานานระหว่างคำขอ


1

ฉันพบว่า httplib เร็วกว่า urllib2 เล็กน้อย ฉันจับเวลาสองโปรแกรม - โปรแกรมหนึ่งใช้ HTTplib และอีกโปรแกรมใช้ urllib2 - ส่งคำขอ HEAD ไปยัง 10,000 URL HTTplib หนึ่งเร็วขึ้นหลายนาที httplib 's สถิติรวมทั้งสิ้น: จริง 0m2.124s ใช้ 6m21.334s SYS 0m16.372s

และสถิติทั้งหมดของurllib2คือผู้ใช้จริง 9m1.380s 0m16.666s sys 0m28.565s

มีใครให้ข้อมูลเกี่ยวกับเรื่องนี้อีกไหม?


การป้อนข้อมูล? ปัญหาคือ IO-bound และคุณกำลังใช้การบล็อกไลบรารี เปลี่ยนเป็นเหตุการณ์เล็ก ๆ หรือบิดถ้าคุณต้องการประสิทธิภาพที่ดีขึ้น ข้อ จำกัด ของ urllib2 ที่คุณพูดถึงคือ CPU-bound
Devin Jeanpierre

3
urllib2 ตามการเปลี่ยนเส้นทางดังนั้นหาก URL บางส่วนของคุณเปลี่ยนเส้นทางนั่นอาจเป็นสาเหตุของความแตกต่าง และ HTTplib เป็นระดับต่ำกว่า urllib2 จะแยกวิเคราะห์ url เช่น
Marian

1
urllib2 เป็นเพียงชั้นบาง ๆ ของนามธรรมที่อยู่ด้านบนของ HTTplib ฉันจะแปลกใจมากถ้าคุณถูกเชื่อมต่อกับซีพียูเว้นแต่ว่า URL จะอยู่บน LAN ที่เร็วมาก เป็นไปได้หรือไม่ที่ URL บางส่วนถูกเปลี่ยนเส้นทาง urllib2 จะทำตามการเปลี่ยนเส้นทางในขณะที่ HTTplib จะไม่ทำ ความเป็นไปได้อื่น ๆ ก็คือเงื่อนไขของเครือข่าย (สิ่งที่คุณไม่มีการควบคุมอย่างชัดเจนในการทดสอบนี้) มีความผันผวนระหว่างการรัน 2 ครั้ง คุณควรทำอย่างน้อย 3 ครั้งต่อเนื่องกันเพื่อลดโอกาสนี้
John La Rooy

0

และอีกวิธีหนึ่ง (คล้ายกับคำตอบของ Pawel):

import urllib2
import types

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

เพียงเพื่อหลีกเลี่ยงการมีเมธอดที่ไม่ถูกผูกมัดในระดับอินสแตนซ์


-4

อาจง่ายกว่า: ใช้ urllib หรือ urllib2

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

f.info () เป็นอ็อบเจกต์ที่เหมือนพจนานุกรมดังนั้นคุณสามารถทำ f.info () ['content-type'] ฯลฯ

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

เอกสารระบุว่าโดยปกติไม่ได้ใช้ HTTplib โดยตรง


14
อย่างไรก็ตาม urllib จะทำ GET และคำถามเกี่ยวกับการแสดง HEAD บางทีผู้โพสต์ไม่ต้องการดึงเอกสารราคาแพง
Philippe F
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.