Библиотека 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: После вашего вопроса о примере для определения вашего собственного обработчика, вот пример, который я придумал. Беспокойство в любой манипуляции с цепочкой запросов заключается в том, что мы должны быть уверены в том, что обработчик безопасен для нескольких запросов, поэтому мне неудобно просто заменять определение putheader в классе HTTPConnection напрямую.
К сожалению, поскольку внутренние компоненты 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')]