urllib2 库使用 OpenerDirector 对象来处理实际打开。幸运的是,python 库提供了默认值,因此您不必这样做。然而,正是这些 OpenerDirector 对象添加了额外的标头。
在发送请求后查看它们是什么(例如,以便您可以记录它):
req = urllib2.Request(url='http://google.com')
response = urllib2.urlopen(req)
print req.unredirected_hdrs
(produces {'Host': 'google.com', 'User-agent': 'Python-urllib/2.5'} etc)
unredirected_hdrs 是 OpenerDirectors 转储其额外标头的地方。只需查看req.headers
将仅显示您自己的标题 - 库为您保留那些不受干扰的标题。
如果您需要在发送请求之前查看标头,则需要子类化 OpenerDirector 以拦截传输。
希望有帮助。
编辑:我忘了提到,一旦发送请求,req.header_items()
将为您提供所有标头的元组列表,包括您自己的和 OpenerDirector 添加的。我应该首先提到这一点,因为它是最直接的 :-) 抱歉。
编辑2:在您对定义自己的处理程序的示例提出问题之后,这是我想出的示例。任何对请求链的关注是我们需要确保处理程序对于多个请求是安全的,这就是为什么我不喜欢直接替换 HTTPConnection 类上 putheader 的定义。
遗憾的是,由于 HTTPConnection 和 AbstractHTTPHandler 的内部结构非常内部,我们必须从 python 库中复制大部分代码来注入我们的自定义行为。假设我没有在下面犯错并且这与我在 5 分钟的测试中一样有效,如果您将 Python 版本更新为修订号(即:2.5.x 到 2.5.y 或2.5 到 2.6 等)。
因此,我应该提到我使用的是 Python 2.5.1。如果您有 2.6 或特别是 3.0,您可能需要相应地进行调整。
如果这不起作用,请告诉我。我对这个问题太感兴趣了:
import urllib2
import httplib
import socket
class CustomHTTPConnection(httplib.HTTPConnection):
def __init__(self, *args, **kwargs):
httplib.HTTPConnection.__init__(self, *args, **kwargs)
self.stored_headers = []
def putheader(self, header, value):
self.stored_headers.append((header, value))
httplib.HTTPConnection.putheader(self, header, value)
class HTTPCaptureHeaderHandler(urllib2.AbstractHTTPHandler):
def http_open(self, req):
return self.do_open(CustomHTTPConnection, req)
http_request = urllib2.AbstractHTTPHandler.do_request_
def do_open(self, http_class, req):
# All code here lifted directly from the python library
host = req.get_host()
if not host:
raise URLError('no host given')
h = http_class(host) # will parse host:port
h.set_debuglevel(self._debuglevel)
headers = dict(req.headers)
headers.update(req.unredirected_hdrs)
headers["Connection"] = "close"
headers = dict(
(name.title(), val) for name, val in headers.items())
try:
h.request(req.get_method(), req.get_selector(), req.data, headers)
r = h.getresponse()
except socket.error, err: # XXX what error?
raise urllib2.URLError(err)
r.recv = r.read
fp = socket._fileobject(r, close=True)
resp = urllib2.addinfourl(fp, r.msg, req.get_full_url())
resp.code = r.status
resp.msg = r.reason
# This is the line we're adding
req.all_sent_headers = h.stored_headers
return resp
my_handler = HTTPCaptureHeaderHandler()
opener = urllib2.OpenerDirector()
opener.add_handler(my_handler)
req = urllib2.Request(url='http://www.google.com')
resp = opener.open(req)
print req.all_sent_headers
shows: [('Accept-Encoding', 'identity'), ('Host', 'www.google.com'), ('Connection', 'close'), ('User-Agent', 'Python-urllib/2.5')]