문제

urllib2를 사용하는 Python 웹 클라이언트가 있습니다.나가는 요청에 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')]

이와 같은 것은 어떻습니까 :

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

저수준 솔루션 :

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()

응답. Status, Response.Reason :

1: 200 OK

응답 .request_headers :

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

응답 .request_header :

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

다른 해결책 인 Witch는 아이디어를 사용했습니다 urllib2 요청에서 기본 헤더를 어떻게 얻습니까? 그러나 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

편집 : 소스를 업데이트하십시오

urllib2.py:do_request (줄 1044 (1067)) 및 urllib2.py:do_open (줄 1073) (줄 293) self.addheaders = [( 'user-agent', client_version)를 참조하십시오. )

응답 객체의 헤더를 찾고있는 것처럼 들립니다. Connection: close, 이 헤더는 Urlopen이 반환 한 물체에 산다. 그들에게가는 것은 충분히 쉽습니다.

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

req.headers 인스턴스입니다 httplib.httpmessage

기본 HTTP 헤더를 보내야합니다 ( w3.org) 지정한 것과 함께. 당신은 같은 도구를 사용할 수 있습니다 Wireshark 당신이 그것들을 전체적으로보고 싶다면.

편집하다:

로그인하려면 사용할 수 있습니다. winpcap 특정 애플리케이션으로 전송 된 패킷을 캡처합니다 (귀하의 경우 Python). 패킷의 유형 및 기타 여러 세부 사항을 지정할 수도 있습니다.

-남자

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top