我有一个使用urllib2的Python Web客户端.向我的传出请求添加HTTP标头很容易.我只是创建一个我想要添加的标题的字典,并将其传递给Request初始化程序.
但是,其他"标准"HTTP标头会添加到请求以及我明确添加的自定义HTTP标头中.当我使用Wireshark嗅探请求时,除了我自己添加的标题之外,我还会看到标题.我的问题是我如何访问这些标题?我想记录每个请求(包括完整的HTTP标头集),并且无法弄清楚如何.
任何指针?
简而言之:如何从urllib2创建的HTTP请求中获取所有传出标头?
如果你想看到发出的文字HTTP请求,并因此看到每个最后一个标题完全按照它在线上的表示,那么你可以告诉你urllib2
使用自己的版本HTTPHandler
打印出来(或保存,或其他)传出的HTTP请求.
import httplib, urllib2 class MyHTTPConnection(httplib.HTTPConnection): def send(self, s): print s # or save them, or whatever! httplib.HTTPConnection.send(self, s) class MyHTTPHandler(urllib2.HTTPHandler): def http_open(self, req): return self.do_open(MyHTTPConnection, req) opener = urllib2.build_opener(MyHTTPHandler) response = opener.open('http://www.google.com/')
运行此代码的结果是:
GET / HTTP/1.1 Accept-Encoding: identity Host: www.google.com Connection: close User-Agent: Python-urllib/2.6
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')]