Frage

Ich habe einen Python-Web-Client, den urllib2 verwendet. Es ist leicht genug, um HTTP-Header auf meine ausgehenden Anfragen hinzuzufügen. Ich schaffe nur ein Wörterbuch der Header ich hinzufügen möchte, und es dem Antrag initializer passieren.

Aber auch andere „Standard“ HTTP-Header der Anforderung hinzugefügt bekommen sowie die individuelle, die ich ausdrücklich hinzufügen. Als ich die Anfrage mit Wireshark schnüffeln, sehe ich Header neben denen, die ich mir selbst hinzufügen. Meine Frage ist, wie ein ich Zugang zu diesen Header bekommen? Ich mag jede Anfrage (einschließlich der voll Satz von HTTP-Header) protokollieren, und kann nicht herausfinden, wie.

alle Hinweise?

auf den Punkt:? Wie bekomme ich alle abgehenden Header einer HTTP-Anforderung von urllib2 erstellt

War es hilfreich?

Lösung

Wenn Sie die wörtliche HTTP-Anforderung, um sehen möchten, die ausgesendet wird, und deshalb jeden letzten Header genau sehen, wie sie auf dem Draht dargestellt wird, dann können Sie urllib2 sagen Sie Ihre eigene Version eines HTTPHandler zu verwenden, druckt (oder spart, oder was auch immer), um die ausgehende HTTP-Anfrage.

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/')

Das Ergebnis dieser Code ausgeführt wird:

GET / HTTP/1.1
Accept-Encoding: identity
Host: www.google.com
Connection: close
User-Agent: Python-urllib/2.6

Andere Tipps

Die urllib2 Bibliothek verwendet OpenerDirector Objekte die tatsächliche Öffnung zu handhaben. Glücklicherweise bietet die Python-Bibliothek standardmäßig so dass Sie nicht haben. Es ist jedoch diese OpenerDirector Objekte, die die zusätzlichen Header hinzufügen.

Um zu sehen, was sie sind, nachdem die Anforderung gesendet wurde (so dass Sie es anmelden können, zum Beispiel):

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)

Die unredirected_hdrs ist, wo der OpenerDirectors ihre zusätzlichen Header-Dump. Einfach bei req.headers suchen nur Ihre eigenen Header zeigen -. Die Bibliothek jene unbehelligt für Sie verlässt

Wenn Sie die Header sehen müssen, bevor Sie die Anfrage zu senden, müssen Sie den OpenerDirector, um eine Unterklasse die Übertragung abzufangen.

Ich hoffe, das hilft.

EDIT: Ich vergaß zu erwähnen, dass, sobald die Anforderung als gesendet wurde, req.header_items() wird Ihnen eine Liste von Tupeln von alle Header, sowohl mit Ihren eigenen und den von der OpenerDirector hinzugekommenen. Ich sollte das erste erwähnt haben, da es die einfachste :-) Leider ist.

EDIT 2: Nach dem Sie Ihre Frage ein Beispiel für Ihre eigenen Handler definieren, hier ist die Probe kam ich mit. Die Sorge in jedem nachäffen mit der Bitte Kette ist, dass wir müssen sicher sein, dass der Handler für mehrere Anforderungen sicher ist, weshalb ich unbequem nur direkt die Definition von putheader auf der Httpconnection-Klasse ersetzt wird.

Leider, denn die Interna von Httpconnection und den AbstractHTTPHandler sehr intern sind, haben wir viel von dem Code aus der Python-Bibliothek zu reproduzieren unser eigenes Verhalten zu injizieren. Angenommen, ich habe unten nicht gepatzt und das funktioniert so gut, wie es in meiner 5-Minuten-Tests haben, seien Sie bitte vorsichtig sein, diese Überschreibung zu überdenken, wenn Sie Ihre Python-Version auf eine Versionsnummer aktualisieren (dh: 2.5.x 2.5.y oder 2,5 bis 2,6, etc).

Ich soll deshalb erwähnen, dass ich bin auf Python 2.5.1. Wenn Sie 2.6 oder, besonders haben, 3.0, müssen Sie diese entsprechend anzupassen.

Bitte lassen Sie mich wissen, wenn dies nicht funktioniert. Ich waaaayyyy zu viel Spaß mit dieser Frage mit:

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

Wie wäre es etwa so:

import urllib2
import httplib

old_putheader = httplib.HTTPConnection.putheader
def putheader(self, header, value):
    print header, value
    old_putheader(self, header, value)
httplib.HTTPConnection.putheader = putheader

urllib2.urlopen('http://www.google.com')

Eine Low-Level-Lösung:

import httplib

class HTTPConnection2(httplib.HTTPConnection):
    def __init__(self, *args, **kwargs):
        httplib.HTTPConnection.__init__(self, *args, **kwargs)
        self._request_headers = []
        self._request_header = None

    def putheader(self, header, value):
        self._request_headers.append((header, value))
        httplib.HTTPConnection.putheader(self, header, value)

    def send(self, s):
        self._request_header = s
        httplib.HTTPConnection.send(self, s)

    def getresponse(self, *args, **kwargs):
        response = httplib.HTTPConnection.getresponse(self, *args, **kwargs)
        response.request_headers = self._request_headers
        response.request_header = self._request_header
        return response

Beispiel:

conn = HTTPConnection2("www.python.org")
conn.request("GET", "/index.html", headers={
    "User-agent": "test",
    "Referer": "/",
})
response = conn.getresponse()

Response.Status, response.reason:

1: 200 OK

response.request_headers:

[('Host', 'www.python.org'), ('Accept-Encoding', 'identity'), ('Referer', '/'), ('User-agent', 'test')]

response.request_header:

GET /index.html HTTP/1.1
Host: www.python.org
Accept-Encoding: identity
Referer: /
User-agent: test

Eine andere Lösung, verwendet Hexe die Idee von Wie Sie Standard Header in einem urllib2 Anfrage erhalten Aber nicht kopiert Code aus std-lib:?

class HTTPConnection2(httplib.HTTPConnection):
    """
    Like httplib.HTTPConnection but stores the request headers.
    Used in HTTPConnection3(), see below.
    """
    def __init__(self, *args, **kwargs):
        httplib.HTTPConnection.__init__(self, *args, **kwargs)
        self.request_headers = []
        self.request_header = ""

    def putheader(self, header, value):
        self.request_headers.append((header, value))
        httplib.HTTPConnection.putheader(self, header, value)

    def send(self, s):
        self.request_header = s
        httplib.HTTPConnection.send(self, s)


class HTTPConnection3(object):
    """
    Wrapper around HTTPConnection2
    Used in HTTPHandler2(), see below.
    """
    def __call__(self, *args, **kwargs):
        """
        instance made in urllib2.HTTPHandler.do_open()
        """
        self._conn = HTTPConnection2(*args, **kwargs)
        self.request_headers = self._conn.request_headers
        self.request_header = self._conn.request_header
        return self

    def __getattribute__(self, name):
        """
        Redirect attribute access to the local HTTPConnection() instance.
        """
        if name == "_conn":
            return object.__getattribute__(self, name)
        else:
            return getattr(self._conn, name)


class HTTPHandler2(urllib2.HTTPHandler):
    """
    A HTTPHandler which stores the request headers.
    Used HTTPConnection3, see above.

    >>> opener = urllib2.build_opener(HTTPHandler2)
    >>> opener.addheaders = [("User-agent", "Python test")]
    >>> response = opener.open('http://www.python.org/')

    Get the request headers as a list build with HTTPConnection.putheader():
    >>> response.request_headers
    [('Accept-Encoding', 'identity'), ('Host', 'www.python.org'), ('Connection', 'close'), ('User-Agent', 'Python test')]

    >>> response.request_header
    'GET / HTTP/1.1\\r\\nAccept-Encoding: identity\\r\\nHost: www.python.org\\r\\nConnection: close\\r\\nUser-Agent: Python test\\r\\n\\r\\n'
    """
    def http_open(self, req):
        conn_instance = HTTPConnection3()
        response = self.do_open(conn_instance, req)
        response.request_headers = conn_instance.request_headers
        response.request_header = conn_instance.request_header
        return response

EDIT: die Quelle Aktualisieren

siehe urllib2.py:do_request (Linie 1044 (1067)) und urllib2.py:do_open (Linie 1073) (Linie 293) self.addheaders = [( 'User-agent', client_version)] (nur 'User-agent' hinzugefügt)

Es klingt für mich wie Sie für die Header der Antwort Objekt suchen, die Connection: close umfassen usw. Diese Header in dem Objekt durch urlopen zurück leben. bei ihnen zu bekommen ist einfach genug:

from urllib2 import urlopen
req = urlopen("http://www.google.com")
print req.headers.headers

req.headers ist eine Instanz von httplib.HTTPMessage

Es sollte die Standard-HTTP-Header (wie angegeben von w3.org ) neben denen, die Sie angeben. Sie können ein Tool wie Wireshark , wenn Sie möchten, dass sie in ihrer Gesamtheit sehen.

Edit:

Wenn Sie sie anmelden möchten, können Sie WinPcap Pakete zu erfassen, indem spezifische Anwendungen gesendet ( in Ihrem Fall, python). Sie können auch die Art der Pakete und viele andere Details angeben.

-Johannes

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top