کتابخانه Requests در پایتون (قسمت دوم)

کتابخانه Requests در پایتون (قسمت دوم)

در قسمت قبلی این مقاله در خصوص مفاهیم اولیه کتابخانه Requests و همچنین نحوه استفاده از آن توضیحاتی دادیم. در ادامه می خواهیم وارد موارد پیچیده تر شویم.

سرصفحه های سفارشی — Custom Headers

در صورتی که بخواهید صرصفحه ای را به درخواست خود اضافه کنید کافی است با استفاده از دیکشنری در پایتون و استفاده از کتابخانه Requests این کار را انجام دهید. به مثال زیر توجه کنید:

>>> url = 'https://api.github.com/some/endpoint'
>>> headers = {'user-agent': 'my-app/0.0.1'}

>>> r = requests.get(url, headers=headers)

توجه: سرصفحه های سفارشی نسبت به منابع خاص اطلاعات بیشتر اهمیت کمتری دارند. برای مثال:

  • سرصفحه هایی که جهت اعتبارسنجی هستند و با دستور header= تنظیم شده اند، در صورتی که پارامترهای اعتبارسنجی در netrc. مشخص شده باشد، لغو خواهد شد.
  • سرصفحه هایی که جهت اعتبارسنجی هستند در صورت وقوع Redirection حذف خواهد شد
  • سرصفحه هایی که جهت اعتبارسنجی با استفاده از پیوکسی هستند توسط اعتبارسنجی های موجود در پروکسی لغو و یا جلوگیری خواهد شد
  • وقتی می توانیم طول محتوا را تعیین کنیم، سرصفحه های Content-length لغو خواهند شد

علاوه بر این، Requests رفتار خود را بر اساس هر کدام از هدر های سفارشی تغییر نمی دهد. هدر ها به سادگی به درخواست نهایی منتقل می شوند.

توجه: تمام مقادیر هدر باید string, byte-string, یا Unicode باشد. با این حال که استفاده از Unicode در هدر مجاز است، توصیه می شود از ارسال مقادیر Unicode در هدر جلوگیری شود.

درخواست های POSTپیچیده تر — More complicated POST Requests

بسیاری  از اوقات، شما می خواهید برخی از داده های کد شده با فرم را ارسال کنید که بسیار شبیه یک فرم HTML است. برای انجام این کار، به سادگی دیکشنری را به آرگومان یا پارامتر data ارسال کنید. دیکشنری به صورت خودکار در هنگام درخواست ایجاد می شود:

>>> payload = {'key1': 'value1', 'key2': 'value2'}

>>> r = requests.post("https://httpbin.org/post", data=payload)
>>> print(r.text)
        {
             …
             “form”: {
                  “key2”: “value2”,
                  “key1”: “value1”
             },
             …
        }

آرگومان data می تواند به جای یک مقدار شامل چندین مقدار به ازای هر پارامتر و یا key باشد. استفاده از این قابلیت زمانی مفید است که فرم مورد نظر دارای المان های زیادی است که دارایkeyهای همنام هستند.

>> payload_tuples = [('key1', 'value1'), ('key1', 'value2')]
>>> r1 = requests.post('https://httpbin.org/post', data=payload_tuples)
>>> payload_dict = {'key1': ['value1', 'value2']}
>>> r2 = requests.post('https://httpbin.org/post', data=payload_dict)
>>> print(r1.text)
{
        …
        “form”: {
        “key1”: [
        “value1”,
        “value2”
        ]
        },

}
>>> r1.text == r2.text
True

گاهی ممکن است بخواهید داده هایی را که فرموله شده نیستند (not form-encoded) را ارسال کنید. اگر در عوض استفاده از dict از string استفاده کنید، اطلاعات مورد نظر به طور مستقیم ارسال می شوند.

به عنوان مثال، API GitHub API v3 داده های رمزگذاری POST / PATCH JSON می پذیرد:

>>> import json

>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}

>>> r = requests.post(url, data=json.dumps(payload))

به جای رمزگذاری dict، می توانید آن را مستقیما با استفاده از پارامتر json (که در نسخه ۲٫۴٫۲ اضافه شده) منتقل کنید که نتیجتا به طور خودکار رمزگذاری می شود:

>>> url = 'https://api.github.com/some/endpoint'
>>> payload = {'some': 'data'}

>>> r = requests.post(url, json=payload)

توجه: در صورتی که اطلاعاتی که با پارامتر JSON ارسال می شود نوعی خارج از داده های ذکر شده و یا فایل باشد، قبول نشده و درخواست ignored خواهد شد.

همچنین استفاده از پارامتر JSON باعث تغییر content-type  در هدر به مقدار application/json شود.

ارسال چندین فایل رمزنگاری شده — POST a Multipart-Encoded File

با استفاده از کتابخانه Requests ارسال فایل هایی با رمزنگاری های مختلف به سادگی امکانپذیر است:

>>> url = 'https://httpbin.org/post'
>>> files = {'file': open('report.xls', 'rb')}

>>> r = requests.post(url, files=files)
>>> r.text
       {
       …
       “files”: {
       “file”: “”
       },
       …
       }

شما می توانید به صراحت نام فایل، content-type، و صرصفحه ها یا Headers را ذکر کنید:

>>> url = 'https://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}

>>> r = requests.post(url, files=files)
>>> r.text
       {
       …
       “files”: {
       “file”: “”
       },
       …
       }

همچنین می توانید برای دریافت فایل String ارسال کنید:

>>> url = 'https://httpbin.org/post'
>>> files = {'file': ('report.csv', 'some,data,to,sendnanother,row,to,sendn')}

>>> r = requests.post(url, files=files)
>>> r.text
       {
       …
       “files”: {
              “file”: “some,data,to,send\nanother,row,to,send\n”
              },
              …
       }

زمانی که در حال ارسال یک فایل بزرگ و حجیم با استفاده از multipart/form-data هستید، ممکن است بخواهید اطلاعات را به صورت stream ارسال کنید. کتابخانه Requests به صورت پیش فرض این کار را انجام نمی دهد و از این قابلیت پشتیبانی نمی کند. ولی پکیج جداگانه ای با نام requests-toolbelt در این رابطه وجود دارد. در صورت علاقه به استفاده از این پکیج لطفا اینجــــــــــــا را کلیک کنید.

هشدار!

عمیقا توصیه می شود که فایل ها را در حالت باینری باز کنید. به این دلیل که کتابخانه Requests ممکن است سعی در ارائه Content-Length در سرصفحه کند که اگر فایل را در حالت متن باز کنید، احتمال رخ دادن خطاها بسیار زیاد است.

کد وضعیت پاسخ — Response Status Codes

چک کردن کد وضعیت Response به سادگی امکان پذیر است. به مثال زیر توجه کنید:

>>> r = requests.get('https://httpbin.org/get')
>>> r.status_code
        ۲۰۰

کتابخانه Requests به صورت پیشفرض فهرستی از کدهای Response جهت تسهیل تدارک دیده است:

>>> r.status_code == requests.codes.ok
        True

در صورتی که requestهای بدی را ایجاد کردیم (۴XX برای خطاهای سمت client و ۵XX برای خطاهای سمت server) می تونیم با استفاده از دستور Response.raise_for_status آنها را اعلام کنیم:

>>> bad_r = requests.get('https://httpbin.org/status/404')
>>> bad_r.status_code
404

>>> bad_r.raise_for_status()
Traceback (most recent call last):
File “requests/models.py”, line 832, in raise_for_status
raise http_error
requests.exceptions.HTTPError: 404 Client Error

زمانی که status_code ما برابر ۲۰۰ باشد زمانی که از raise_for_status استفاده می کنید با پاسخ None رو برو خواهید شد.

سرصفحه های پاسخ — Response Headers

با استفاده از دیکشنری پایتون می توانیم سرصفحه پاسخ ارسالی از سرور را مشاهده کنیم:

>>> r.headers
{
‘content-encoding’: ‘gzip’,
‘transfer-encoding’: ‘chunked’,
‘connection’: ‘close’,
‘server’: ‘nginx/1.0.4’,
‘x-runtime’: ‘148ms’,
‘etag’: ‘”e1ca502697e5c9317743dc078f67693f”‘,
‘content-type’: ‘application/json’
}

این دیکشنری خاص است هرچند که فقط برای سرصفحه ها طراحی شده. با توجه به RFC-7230، نام ها در HTTP Header به حروف بزرگ و کوچک حساس نیستند. در نتیجه اگر بخواهیم به سرصفحه ها درسترس داشته باشیم هر نوع نگارشی قابل قبول است:

>>> r.headers['Content-Type']
        ‘application/json’

>>> r.headers.get('content-type')
        ‘application/json’

جالب است که سرور می تواند یک هدر را چندین بار با مقادیر مختلف ارسال کند، اما کتابخانه Requests  آنها را ترکیب می کند

کوکی ها — Cookies

در صورتی که پاسخ دریافتی شامل کوکی باشد به سادگی می توانید به آن دسترسی پیدا کنید:

>>> url = 'http://example.com/some/cookie/setting/url'
>>> r = requests.get(url)

>>> r.cookies['example_cookie_name']
'example_cookie_value'

برای ارسال کوکی دلخواه خود به سرور می بایست از پارامتر cookies استفاده کنید:

>>> url = 'https://httpbin.org/cookies'
>>> cookies = dict(cookies_are='working')

>>> r = requests.get(url, cookies=cookies)
>>> r.text
        ‘{“cookies”: {“cookies_are”: “working”}}’

کوکی ها در RequestsCookieJar بر می گردند و به صورت dict رق=فتار می کنند، ولی همچنین اینترفیس بسیار کامل تری را ارائه می دهند. برای استفاده در حوزه ها و دامنه های مختلف مناسب هستند. کوکی های jar هم می توانند با استفاده از کتابخانه Requests ارسال شوند:

>>> jar = requests.cookies.RequestsCookieJar()
>>> jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
>>> jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
>>> url = 'https://httpbin.org/cookies'
>>> r = requests.get(url, cookies=jar)
>>> r.text
       ‘{“cookies”: {“tasty_cookie”: “yum”}}’

تغییر مسیر و تاریخچه — Redirection and History

به طور پیش فرض کتابخانه Requests این قابلیت را دارد که مسیریابی آدرس ها را برای تمام اجزا به جز HEAD انجام داد.
همچنین می توانیم از ویژگی History شی Response برای ردیابی مسیرها استفاده کنیم.
لیست Response.history شامل اشیاء Response است که برای تکمیل درخواست ها ایجاد شده است. این لیست به ترتیب تاریخ از قدیمیترین تا جدید ترین تاریخ مرتب است.

به عنوان مثال، GitHub همه درخواستهای HTTP را به HTTPS هدایت می کند:

>>> r = requests.get('http://github.com/')

>>> r.url
       ‘https://github.com/’

>>> r.status_code
       ۲۰۰

>>> r.history
       []

در صورتی که از GET, OPTIONS, POST, PUT, PATCH or DELETE استفاده می کنید، با استفاده از پارامتر allow_redirects می توانید قابلیت مسیریابی یا ریدایرکشن را غیرفعال کنید:

>>> r = requests.get('http://github.com/', allow_redirects=False)

>>> r.status_code
       ۳۰۱

>>> r.history
       []

درصورتی که از HEAD استفاده می کنید می توانید از قابلیت مسیریابی بخوبی استفاده کنید:

>>> r = requests.head('http://github.com/', allow_redirects=True)

>>> r.url
       ‘https://github.com/’

>>> r.history
       []

زمان انتظار — Timeouts

شما با استفاده پارامتر timeout می توانید تعیین کنید که کتابخانه Requests چند ثانیه در انتظار دریافت پاسخ بماند. شما تقریبا می بایست از این پارامتر در تمامی درخواستهایی خود استفاده کنید. عدم تنطیم و یا استفاده از این پارامتر می تواند باعث شود برنامه شما به طور نامحدود متوقف شود:

>>> requests.get('https://github.com/', timeout=0.001)
       Traceback (most recent call last):
       File “”, line 1, in
      requests.exceptions.Timeout: HTTPConnectionPool(host=’github.com’, port=80): Request        timed out. (timeout=0.001)

توجه:

timeout محدودیت زمانی را در زمان دانلود اعمال نمی کند در عوض، اگر سرور پاسخی برای ثانیه های زمانی تنظیم شده  ارسال نکند خطا رخ خواهد داد (به طور دقیقتر، اگر هیچ بایتی برای مدت زمانی تعریف شده دریافت نشود خطا رخ خواهد داد). اگر صراحتا مدت زمان timeout مشخص نشده است، Requests متوقف نخواهد شد.

 

تا به اینجا با قابلیت های کلیدی و نسبتا کاملی از کتابخانه Requests آشنا شده اید. شاید در مقالات بعدی به معرفی قابلیت ها پیشرفته این کتابخانه بپردازیم.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *