পাইথন অনুরোধ - পুরো HTTP অনুরোধ মুদ্রণ (কাঁচা)?


197

requestsমডিউলটি ব্যবহার করার সময় , কাঁচা এইচটিটিপি অনুরোধটি প্রিন্ট করার কোনও উপায় আছে?

আমি কেবল শিরোনাম চাই না, আমি অনুরোধ লাইন, শিরোনাম এবং সামগ্রী প্রিন্টআউট চাই। এইচটিটিপি অনুরোধ থেকে শেষ পর্যন্ত কী নির্মিত হয় তা দেখা সম্ভব?


9
@ রিকিএ তিনি অনুরোধের সামগ্রীর বিষয়ে জিজ্ঞাসা করছেন, প্রতিক্রিয়া নয়
goncalopp

2
এটা একটা ভালো প্রশ্ন. উত্সটি দেখলে মনে হয় না যে প্রস্তুত অনুরোধের কাঁচামাল পাওয়ার কোনও উপায় আছে এবং এটি কেবল পাঠানো হলেই সিরিয়াল করা হয়। এটি দেখে মনে হচ্ছে এটি একটি ভাল বৈশিষ্ট্য হবে।
টিম পিয়ার্স

ঠিক আছে, আপনি তারটি শুরু করতে পারেন এবং সেভাবে দেখতে পারেন।
রিকিয়া

@ কিউআরটি এটির requestsবৈশিষ্ট্য হিসাবে এটি সংহত করা কঠিন হবে , কারণ এর অর্থ পুনর্লিখন / বাইপাসিং urllib3এবং httplib। নীচে স্ট্যাক ট্রেস দেখুন
goncalopp

এটি আমার জন্য কাজ করেছে - stackoverflow.com/questions/10588644/…
অজয়

উত্তর:


213

যেহেতু v1.2.3 অনুরোধগুলি প্রস্তুতিগ্রহীত বস্তুটি যুক্ত করেছে। ডকুমেন্টেশন অনুসারে "এটিতে হুবহু বাইট রয়েছে যা সার্ভারে প্রেরণ করা হবে"।

একটি অনুরোধ প্রিন্ট করতে কেউ এটি ব্যবহার করতে পারে, এর মতো:

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{}\r\n{}\r\n\r\n{}'.format(
        '-----------START-----------',
        req.method + ' ' + req.url,
        '\r\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
        req.body,
    ))

pretty_print_POST(prepared)

যা উত্পাদন করে:

-----------START-----------
POST http://stackoverflow.com/
Content-Length: 7
X-Custom: Test

a=1&b=2

তারপরে আপনি এটি সহ প্রকৃত অনুরোধটি প্রেরণ করতে পারেন:

s = requests.Session()
s.send(prepared)

এই লিঙ্কগুলি সর্বশেষতম ডকুমেন্টেশনের উপলভ্য, তাই এগুলি সামগ্রীতে পরিবর্তিত হতে পারে: উন্নত - প্রস্তুত অনুরোধ এবং এপিআই - নিম্ন স্তরের শ্রেণি classes


2
এটি আমার বানরের প্যাচিং পদ্ধতির চেয়ে অনেক বেশি দৃust়। আপগ্রেড requestsকরা সহজবোধ্য, তাই আমি মনে করি এটি গ্রহণযোগ্য উত্তর হয়ে উঠবে
goncalopp

69
আপনি সহজ ব্যবহার করেন তাহলে response = requests.post(...)(অথবা requests.getঅথবা requests.put, ইত্যাদি) পদ্ধতি, আপনি আসলে পেতে পারেন PreparedResponseমাধ্যমে response.request। এটি ম্যানুয়ালি ম্যানিপুলেটিংয়ের কাজটি সংরক্ষণ করতে পারে requests.Requestএবং requests.Sessionযদি কোনও প্রতিক্রিয়া পাওয়ার আগে আপনার যদি কাঁচা HTTP ডেটা অ্যাক্সেস করার প্রয়োজন না হয়।
গেরশম

2
ভাল উত্তর. তবে আপনি যে জিনিসটি আপডেট করতে চাইতে পারেন তা হ'ল এইচটিটিপিতে লাইন বিরতি কেবল \ n নয় \ r \ n হওয়া উচিত।
ltc

3
ইউআরএল পরে ঠিক এইচটিটিপি প্রোটোকল সংস্করণ অংশ সম্পর্কে কি? 'HTTP / 1.1' এর মতো? আপনার সুন্দর প্রিন্টার ব্যবহার করে প্রিন্ট আউট করার সময় এটি খুঁজে পাওয়া যায় না।
সাজুউক

1
সিআরএলএফ ব্যবহারের জন্য আপডেট হয়েছে, যেহেতু আরএফসি 2616 এর জন্য এটি প্রয়োজন, এবং এটি খুব কঠোর পার্সারদের জন্য একটি সমস্যা হতে পারে
20:38

55
import requests
response = requests.post('http://httpbin.org/post', data={'key1':'value1'})
print(response.request.body)
print(response.request.headers)

আমি অনুরোধ সংস্করণ 2.18.4 এবং পাইথন 3 ব্যবহার করছি


44

দ্রষ্টব্য: এই উত্তরটি পুরানো। অ্যান্টোনিওহাইরাইজস এর উত্তর নথি requests হিসাবে সরাসরি অনুরোধের সামগ্রী পাওয়া সমর্থনের নতুন সংস্করণগুলি

অনুরোধের সত্যিকারের কাঁচামাল পাওয়া সম্ভব নয় requests, কারণ এটি কেবল উচ্চ স্তরের বস্তুগুলির যেমন শিরোনাম এবং পদ্ধতির ধরণের সাথে সম্পর্কিতrequestsব্যবহারসমূহ urllib3অনুরোধ পাঠাতে, কিন্তু urllib3 এছাড়াও কাঁচা ডেটা সাথে মোকাবিলা করে না - এটি ব্যবহার করে httplib। একটি অনুরোধের একটি প্রতিনিধি স্ট্যাক ট্রেস এখানে:

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

httplibযন্ত্রের অভ্যন্তরে , আমরা HTTPConnection._send_requestঅপ্রত্যক্ষভাবে ব্যবহারগুলি দেখতে পাই HTTPConnection._send_outputযা শেষ পর্যন্ত কাঁচা অনুরোধ এবং শরীর তৈরি করে (যদি এটি বিদ্যমান থাকে) এবং HTTPConnection.sendসেগুলি পৃথকভাবে প্রেরণের জন্য ব্যবহার করে। sendঅবশেষে সকেটে পৌঁছে যায়।

আপনি যা চান তা করার কোনও হুক নেই, তাই শেষ উপায় হিসাবে আপনি httplibসামগ্রীটি পেতে বানর প্যাচ করতে পারেন p এটি একটি ভঙ্গুর সমাধান এবং httplibপরিবর্তিত হলে আপনাকে এটি খাপ খাইয়ে নিতে হতে পারে । যদি আপনি এই সমাধানটি ব্যবহার করে সফ্টওয়্যার বিতরণ করতে চান তবে আপনি httplibসিস্টেমটির ব্যবহারের পরিবর্তে প্যাকেজিং বিবেচনা করতে পারেন , এটি সহজ, কারণ এটি খাঁটি অজগর মডিউল।

হায়রে, সমাধান ছাড়াও:

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

যা আউটপুট দেয়:

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

হাই goncalopp, আমি যদি প্যাচ_সেন্ড () পদ্ধতিটি দ্বিতীয় বার (দ্বিতীয় অনুরোধের পরে) কল করি, তবে এটি দ্বিগুণ তথ্য প্রিন্ট করে (তাই উপরে দেখানো মত আউটপুট থেকে 2x গুণ)? সুতরাং, আমি যদি তৃতীয় অনুরোধটি করি তবে এটি 3x বার প্রিন্ট করবে এবং আরও একবার ... কীভাবে একবারে আউটপুটটি কীভাবে পাবেন? আগাম ধন্যবাদ.
অপটলজ

@ ওস্টলজ আপনার patch_sendএকাধিকবার কল করা উচিত নয় , একবার আমদানি করার পরেhttplib
goncalopp

40

এর চেয়ে আরও ভাল ধারণা হ'ল অনুরোধগুলি_ টুবেল্ট লাইব্রেরিটি ব্যবহার করা যা আপনার কনসোলে মুদ্রণের জন্য অনুরোধ এবং প্রতিক্রিয়া উভয়ই স্ট্রিং হিসাবে ফেলে দিতে পারে। এটি ফাইলগুলি এবং এনকোডিংগুলির সাথে সমস্ত জটিল ক্ষেত্রে পরিচালনা করে যা উপরের সমাধানটি ভালভাবে পরিচালনা করে না।

এটি এর মতো সহজ:

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

সূত্র: https://toolbelt.readthedocs.org/en/latest/dumputils.html

আপনি কেবল টাইপ করে এটি ইনস্টল করতে পারেন:

pip install requests_toolbelt

2
এটি অনুরোধটি প্রেরণ না করেই ডাম্প করবে বলে মনে হচ্ছে না।
ডাবিস ভান্ডারমির

1
ডাম্প_ল ঠিকঠাকভাবে কাজ করতে দেখা যাচ্ছে না কারণ আমি "টাইপ এরির: কলটি থেকে 'স্ট্রিং' এবং 'ইউইউডি' অবজেক্টগুলিকে একত্রিত করতে পারি না।
rtaft

@ আর্টাফ্ট: দয়া করে এটি তাদের গিথুব
এমিল স্টেনস্ট্রোম

এটি> এবং <লক্ষণগুলি দিয়ে ডাম্প মুদ্রণ করে, তারা কি প্রকৃত অনুরোধের অংশ?
জে

1
@ জায়ে দেখে মনে হচ্ছে তারা প্রকৃত অনুরোধ / প্রতিক্রিয়ার প্রতি দায়িত্বে রয়েছেন ( github.com/requests/toolbelt/blob/master/requests_toolbelt/… ) এবং অনুরোধ_প্রিফিক্স = বি '{কিছু_আরেকুস্ট_প্রিফিক্স passing', প্রতিক্রিয়া_প্রিফিক্স = পাশ করে নির্দিষ্ট করা যেতে পারে খ '{some_response_prefix}' dump_all (থেকে github.com/requests/toolbelt/blob/master/requests_toolbelt/... )
খ্রিস্টান Reall-Fluharty

7

এখানে একটি কোড রয়েছে যা একই করে তবে প্রতিক্রিয়া শিরোনাম সহ:

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

আমি এটি অনুসন্ধান করার জন্য অনেক সময় ব্যয় করেছি, তাই কারও প্রয়োজন হলে আমি এটি এখানে রেখে চলেছি।


4

অনুরোধগুলির ফর্ম্যাট করতে আমি নীচের ফাংশনটি ব্যবহার করি। এটি @ অ্যান্টোনিওহেরাইজএসের মতো এটির পাশাপাশি এটি শরীরে জেএসওএন অবজেক্টগুলিও প্রিন্ট করবে এবং এটি অনুরোধের সমস্ত অংশকে লেবেল করে।

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

এবং প্রতিক্রিয়াটি ফর্ম্যাট করার জন্য আমার অনুরূপ ফাংশন রয়েছে:

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

1

requestsতথাকথিত ইভেন্ট হুক সমর্থন করে (২.২৩ পর্যন্ত আসলে কেবল responseহুক রয়েছে)। কার্যকর ইউআরএল, শিরোনাম এবং সংস্থা সহ পুরো অনুরোধ-প্রতিক্রিয়া জুটির ডেটা প্রিন্ট করার অনুরোধে এই হুক ব্যবহার করা যেতে পারে:

import textwrap
import requests

def print_roundtrip(response, *args, **kwargs):
    format_headers = lambda d: '\n'.join(f'{k}: {v}' for k, v in d.items())
    print(textwrap.dedent('''
        ---------------- request ----------------
        {req.method} {req.url}
        {reqhdrs}

        {req.body}
        ---------------- response ----------------
        {res.status_code} {res.reason} {res.url}
        {reshdrs}

        {res.text}
    ''').format(
        req=response.request, 
        res=response, 
        reqhdrs=format_headers(response.request.headers), 
        reshdrs=format_headers(response.headers), 
    ))

requests.get('https://httpbin.org/', hooks={'response': print_roundtrip})

এটি চালনা করে:

---------------- request ----------------
GET https://httpbin.org/
User-Agent: python-requests/2.23.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: keep-alive

None
---------------- response ----------------
200 OK https://httpbin.org/
Date: Thu, 14 May 2020 17:16:13 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 9593
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

<!DOCTYPE html>
<html lang="en">
...
</html>

আপনি পরিবর্তন করতে পারেন res.textথেকে res.contentযদি প্রতিক্রিয়া বাইনারি হয়।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.