Gibt es beim Drucken des Moduls requests
eine Möglichkeit, die unformatierte HTTP-Anforderung zu drucken?
Ich möchte nicht nur die Kopfzeilen, ich möchte die Anforderungszeile, die Kopfzeilen und den Inhaltsausdruck. Kann man sehen, was letztendlich aus einer HTTP-Anfrage besteht?
Since v1.2.3 Requests hat das PreparedRequest-Objekt hinzugefügt. Laut Dokumentation "enthält es die genauen Bytes, die an den Server gesendet werden".
Man kann das so benutzen, um eine Anfrage hübsch auszudrucken:
import requests
req = requests.Request('POST','http://stackoverflow.com',headers={'X-Custom':'Test'},data='a=1&b=2')
prepared = req.prepare()
def pretty_print_POST(req):
"""
At this point it is completely built and ready
to be fired; it is "prepared".
However pay attention at the formatting used in
this function because it is programmed to be pretty
printed and may differ from the actual request.
"""
print('{}\n{}\n{}\n\n{}'.format(
'-----------START-----------',
req.method + ' ' + req.url,
'\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
req.body,
))
pretty_print_POST(prepared)
was produziert:
-----------START-----------
POST http://stackoverflow.com/
Content-Length: 7
X-Custom: Test
a=1&b=2
Dann können Sie die eigentliche Anfrage mit diesem versenden:
s = requests.Session()
s.send(prepared)
Diese Links beziehen sich auf die aktuellste verfügbare Dokumentation und können sich daher im Inhalt ändern: Erweitert - Vorbereitete Anforderungen und API - Untergeordnete Klassen
Hinweis: Diese Antwort ist veraltet. Neuere Versionen von requests
unterstützen das direkte Abrufen des Anforderungsinhalts als Antwort von AntonioHerraizS documents.
Es ist nicht möglich, den true -Rohinhalt der Anforderung aus requests
zu holen, da er nur Objekte höherer Ebene behandelt, z. B. Header und Methodentyp. requests
verwendet urllib3
zum Senden von Anforderungen, aber urllib3
auch behandelt keine Rohdaten - es verwendet httplib
. Hier ist ein repräsentativer Stack-Trace einer Anfrage:
-> r= requests.get("http://google.com")
/usr/local/lib/python2.7/dist-packages/requests/api.py(55)get()
-> return request('get', url, **kwargs)
/usr/local/lib/python2.7/dist-packages/requests/api.py(44)request()
-> return session.request(method=method, url=url, **kwargs)
/usr/local/lib/python2.7/dist-packages/requests/sessions.py(382)request()
-> resp = self.send(prep, **send_kwargs)
/usr/local/lib/python2.7/dist-packages/requests/sessions.py(485)send()
-> r = adapter.send(request, **kwargs)
/usr/local/lib/python2.7/dist-packages/requests/adapters.py(324)send()
-> timeout=timeout
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py(478)urlopen()
-> body=body, headers=headers)
/usr/local/lib/python2.7/dist-packages/requests/packages/urllib3/connectionpool.py(285)_make_request()
-> conn.request(method, url, **httplib_request_kw)
/usr/lib/python2.7/httplib.py(958)request()
-> self._send_request(method, url, body, headers)
In der httplib
-Maschinerie können wir sehen, dass HTTPConnection._send_request
indirekt HTTPConnection._send_output
verwendet, der schließlich die Rohanforderung und body (falls vorhanden) erstellt und sie mit HTTPConnection.send
separat sendet. send
erreicht schließlich den Sockel.
Da es keine Haken gibt, um das zu tun, was Sie wollen, können Sie als letzten Ausweg httplib
einen Affen-Patch erstellen, um den Inhalt zu erhalten. Es ist eine fragile Lösung, die Sie möglicherweise anpassen müssen, wenn httplib
geändert wird. Wenn Sie beabsichtigen, Software mit dieser Lösung zu vertreiben, sollten Sie das Paket httplib
anstelle der Verwendung des Systems in Betracht ziehen. Dies ist einfach, da es sich um ein reines Python-Modul handelt.
Leider ohne weiteres die Lösung:
import requests
import httplib
def patch_send():
old_send= httplib.HTTPConnection.send
def new_send( self, data ):
print data
return old_send(self, data) #return is not necessary, but never hurts, in case the library is changed
httplib.HTTPConnection.send= new_send
patch_send()
requests.get("http://www.python.org")
was ergibt die Ausgabe:
GET / HTTP/1.1
Host: www.python.org
Accept-Encoding: gzip, deflate, compress
Accept: */*
User-Agent: python-requests/2.1.0 CPython/2.7.3 Linux/3.2.0-23-generic-pae
Eine noch bessere Idee ist die Verwendung der Bibliothek "request_toolbelt", die sowohl Anforderungen als auch Antworten als Zeichenfolgen für den Ausdruck an die Konsole ausgibt. Es behandelt alle heiklen Fälle mit Dateien und Kodierungen, mit denen die oben genannte Lösung nicht gut umgehen kann.
So einfach geht's:
import requests
from requests_toolbelt.utils import dump
resp = requests.get('https://httpbin.org/redirect/5')
data = dump.dump_all(resp)
print(data.decode('utf-8'))
Quelle: https://toolbelt.readthedocs.org/de/latest/dumputils.html
Sie können es einfach installieren, indem Sie Folgendes eingeben:
pip install requests_toolbelt
import requests
response = requests.post('http://httpbin.org/post', data={'key1':'value1'})
print(response.request.body)
print(response.request.headers)
Ich benutze request version 2.18.4 und Python 3
Hier ist ein Code, der dasselbe macht, jedoch mit Antwort-Headern:
import socket
def patch_requests():
old_readline = socket._fileobject.readline
if not hasattr(old_readline, 'patched'):
def new_readline(self, size=-1):
res = old_readline(self, size)
print res,
return res
new_readline.patched = True
socket._fileobject.readline = new_readline
patch_requests()
Ich habe viel Zeit damit verbracht, das zu suchen, also lasse ich es hier, wenn jemand etwas braucht.
Ich benutze die folgende Funktion, um Anfragen zu formatieren. Es ist wie bei @AntonioHerraizS, nur dass JSON-Objekte auch im Hauptteil hübsch gedruckt werden und alle Teile der Anforderung beschriftet werden.
format_json = functools.partial(json.dumps, indent=2, sort_keys=True)
indent = functools.partial(textwrap.indent, prefix=' ')
def format_prepared_request(req):
"""Pretty-format 'requests.PreparedRequest'
Example:
res = requests.post(...)
print(format_prepared_request(res.request))
req = requests.Request(...)
req = req.prepare()
print(format_prepared_request(res.request))
"""
headers = '\n'.join(f'{k}: {v}' for k, v in req.headers.items())
content_type = req.headers.get('Content-Type', '')
if 'application/json' in content_type:
try:
body = format_json(json.loads(req.body))
except json.JSONDecodeError:
body = req.body
else:
body = req.body
s = textwrap.dedent("""
REQUEST
=======
endpoint: {method} {url}
headers:
{headers}
body:
{body}
=======
""").strip()
s = s.format(
method=req.method,
url=req.url,
headers=indent(headers),
body=indent(body),
)
return s
Und ich habe eine ähnliche Funktion, um die Antwort zu formatieren:
def format_response(resp):
"""Pretty-format 'requests.Response'"""
headers = '\n'.join(f'{k}: {v}' for k, v in resp.headers.items())
content_type = resp.headers.get('Content-Type', '')
if 'application/json' in content_type:
try:
body = format_json(resp.json())
except json.JSONDecodeError:
body = resp.text
else:
body = resp.text
s = textwrap.dedent("""
RESPONSE
========
status_code: {status_code}
headers:
{headers}
body:
{body}
========
""").strip()
s = s.format(
status_code=resp.status_code,
headers=indent(headers),
body=indent(body),
)
return s