15

urllib2 を使用する Python Web クライアントがあります。発信リクエストに HTTP ヘッダーを追加するのは簡単です。追加したいヘッダーのディクショナリを作成し、それを Request イニシャライザに渡します。

ただし、明示的に追加したカスタム HTTP ヘッダーだけでなく、他の「標準」HTTP ヘッダーもリクエストに追加されます。Wireshark を使用してリクエストをスニッフィングすると、自分で追加したヘッダー以外のヘッダーが表示されます。私の質問は、これらのヘッダーにアクセスするにはどうすればよいですか? すべてのリクエスト ( HTTP ヘッダーの完全なセットを含む) をログに記録したいのですが、方法がわかりません。

ポインタはありますか?

一言で言えば: urllib2 によって作成された HTTP リクエストからすべての送信ヘッダーを取得するにはどうすればよいですか?

4

8 に答える 8

10

送信されたリテラルの 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
于 2010-10-27T14:36:54.197 に答える
5

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など)。

したがって、私はPython2.5.1を使用していることに言及する必要があります。2.6、特に3.0を使用している場合は、それに応じて調整する必要があります。

これがうまくいかない場合はお知らせください。私はこの質問でwaaaayyyyをとても楽しんでいます:

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')]
于 2009-03-02T20:57:21.153 に答える
2

このようなものはどうですか:

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')
于 2009-03-02T20:58:53.847 に答える
2

低レベルのソリューション:

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

例:

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
于 2011-08-09T10:09:50.703 に答える
2

別の解決策として、魔女はHow do you get default headers in a urllib2 Request?のアイデアを使用しました。しかし、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

編集:ソースを更新

于 2011-08-09T13:16:27.890 に答える
0

urllib2.py:do_request (1044 行 (1067)) および urllib2.py:do_open (1073 行) (293 行) を参照してください。 self.addheaders = [('User-agent', client_version)] ('User-agent' のみが追加されました)

于 2009-03-02T20:46:02.037 に答える
0

などを含む応答オブジェクトのヘッダーを探しているようにConnection: close思えます。これらのヘッダーは、urlopen によって返されるオブジェクトに存在します。それらを取得するのは簡単です:

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

req.headershttplib.HTTPMessageのインスタンスです

于 2010-10-27T14:49:24.677 に答える
-1

指定したものと一緒にデフォルトの http ヘッダー ( w3.orgで指定) を送信する必要があります。全体を見たい場合は、 WireSharkなどのツールを使用できます。

編集:

それらをログに記録したい場合は、WinPcapを使用して、特定のアプリケーション (この場合は python) から送信されたパケットをキャプチャできます。パケットのタイプやその他の多くの詳細を指定することもできます。

-ジョン

于 2009-03-02T20:48:15.697 に答える