কেন অনুরোধ.জেট () ফিরে আসে না? ডিফল্ট টাইমআউটটি কী যা অনুরোধ.জেট () ব্যবহার করে?


95

আমার স্ক্রিপ্টে, requests.getকখনই ফিরে আসে না:

import requests

print ("requesting..")

# This call never returns!
r = requests.get(
    "http://www.some-site.com",
    proxies = {'http': '222.255.169.74:8080'},
)

print(r.ok)

সম্ভাব্য কারণ (গুলি) কী হতে পারে? কোন প্রতিকার? ডিফল্ট টাইমআউট কী getব্যবহার করে?


4
@ ইউজার 2357112: এটা কি ব্যাপার? আমি সন্দেহ করি.
নওয়াজ

এটা অবশ্যই গুরুত্বপূর্ণ। আপনি যে URL টি অ্যাক্সেস করার চেষ্টা করছেন এবং যে প্রক্সি আপনি ব্যবহার করার চেষ্টা করছেন তা যদি আপনি সরবরাহ করেন তবে আমরা অনুরূপ অনুরোধগুলি প্রেরণের চেষ্টা করলে কী ঘটে তা আমরা দেখতে পাই।
ব্যবহারকারী 2357112

4
@ ব্যবহারকারী 2357112: ঠিক আছে। প্রশ্ন সম্পাদনা।
নওয়াজ

4
আপনার প্রক্সিটিও ভুল। আপনি এটা এত পছন্দ নির্দিষ্ট করতে হবে: proxies={'http': 'http://222.255.169.74:8080'}। এটি কারণ হতে পারে যে এটি কোনও সময়সীমা ছাড়াই সম্পূর্ণ হচ্ছে না।
ইয়ান স্ট্যাপলটন কর্ডাস্কো

উত্তর:


133

ব্যবহারগুলি পেতে ডিফল্ট সময়সীমা কী?

ডিফল্ট সময়সীমা হ'ল Noneযার অর্থ সংযোগটি বন্ধ না হওয়া পর্যন্ত এটি অপেক্ষা করবে (স্তব্ধ)।

আপনি একটি সময়সীমা মান পাস যখন কি?

r = requests.get(
    'http://www.justdial.com',
    proxies={'http': '222.255.169.74:8080'},
    timeout=5
)

4
আমি মনে করি আপনি ঠিক. Noneএর অর্থ অসীম (বা "সংযোগটি যতক্ষণ না অপেক্ষা করা হবে")। আমি যদি নিজেই সময়সীমা পাস করি তবে তা ফিরে আসে!
নওয়াজ

14
@User সময়সীমার HTTPS এর সাথে শুধু জরিমানা হিসাবে কাজ করে যেমন সঙ্গে HTTP করে
jaapz

গুগলিং বা অন্যথায় ডক্সে এটি পাওয়া সত্যিই কঠিন বলে মনে হচ্ছে। ডক্সে এটি কোথায় প্রদর্শিত হবে কেউ জানেন?
শব্দগুলি


ধন্যবাদ, print(requests.request.__doc__)আইপিথনে করা যদিও আমি যা খুঁজছিলাম তার বেশি। আমি ভাবছিলাম request.get()সেখানে অন্যান্য alচ্ছিক যুক্তিগুলি কী ছিল?
শব্দসুহলে

40

অনুরোধ নথি থেকে :

সময়সীমার প্যারামিটারের সাথে প্রদত্ত সংখ্যার সেকেন্ড পরে প্রতিক্রিয়াটির জন্য অপেক্ষা করা বন্ধ করতে অনুরোধগুলি বলতে পারেন:

>>> requests.get('http://github.com', timeout=0.001)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)

বিঃদ্রঃ:

সময়সীমা পুরো প্রতিক্রিয়া ডাউনলোডের সময়সীমা নয়; পরিবর্তে, যদি সার্ভার সময়সীমা সেকেন্ডের জন্য প্রতিক্রিয়া জারি না করে তবে একটি ব্যতিক্রম উত্থাপিত হয় (আরও স্পষ্টভাবে, যদি টাইমআউট সেকেন্ডের জন্য অন্তর্নিহিত সকেটে কোনও বাইট না পাওয়া যায়)।

আমার কাছে এটি অনেক কিছু ঘটে যে অনুরোধ.জেট () timeout1 সেকেন্ড হলেও ফিরে আসতে খুব দীর্ঘ সময় নেয় । এই সমস্যাটি কাটিয়ে ওঠার কয়েকটি উপায় রয়েছে:

1. TimeoutSauceঅভ্যন্তরীণ ক্লাস ব্যবহার করুন

থেকে: https://github.com/kennethreitz/requests/issues/1928#issuecomment-35811896

import requests from requests.adapters import TimeoutSauce

class MyTimeout(TimeoutSauce):
    def __init__(self, *args, **kwargs):
        if kwargs['connect'] is None:
            kwargs['connect'] = 5
        if kwargs['read'] is None:
            kwargs['read'] = 5
        super(MyTimeout, self).__init__(*args, **kwargs)

requests.adapters.TimeoutSauce = MyTimeout

এই কোডটি আমাদের সংযোগের সময়সীমার সমান হিসাবে পঠনের সময়সীমা সেট করার কারণ হতে পারে, যা আপনার সেশন.জেট () কলটিতে পাস করা সময়সীমা মান। (মনে রাখবেন যে আমি আসলে এই কোডটি পরীক্ষা করি নি, তাই এটির জন্য কিছু দ্রুত ডিবাগিংয়ের প্রয়োজন হতে পারে, আমি কেবল এটি সরাসরি গিটহাব উইন্ডোতে লিখেছি))

২. কেভিনবার্কের কাছ থেকে অনুরোধের কাঁটাচামচ ব্যবহার করুন: https://github.com/kevinburke/requests/tree/connect- সময়সীমার

এর ডকুমেন্টেশন থেকে: https://github.com/kevinburke/requests/blob/connect-timeout/docs/user/advanced.rst

আপনি যদি সময়সীমার জন্য একটি একক মান নির্দিষ্ট করে থাকেন তবে:

r = requests.get('https://github.com', timeout=5)

সময়সীমা মান সংযুক্ত এবং পঠিত সময়সীমা উভয় প্রয়োগ করা হবে। আপনি আলাদা আলাদাভাবে মান সেট করতে চাইলে একটি টিপল উল্লেখ করুন:

r = requests.get('https://github.com', timeout=(3.05, 27))

দ্রষ্টব্য: পরিবর্তনটি মূল অনুরোধ প্রকল্পে একীভূত করা হয়েছে

৩. অনুরূপ প্রশ্নের মধ্যে ইতিমধ্যে উল্লিখিত evenletবা ব্যবহার করা signal: অজগর অনুরোধগুলির জন্য সময়সীমা.কেন্দ্রিক প্রতিক্রিয়া জানুন


8
আপনি কখনই উত্তর দেন নি ডিফল্টটি কী
ব্যবহারকারী

উদ্ধৃতি: সময়সীমার প্যারামিটারের সাথে প্রদত্ত সংখ্যার সেকেন্ড পরে প্রতিক্রিয়াটির জন্য অপেক্ষা করা বন্ধ করতে অনুরোধগুলি বলতে পারেন। প্রায় সমস্ত প্রোডাকশন কোডের প্রায় সমস্ত অনুরোধে এই প্যারামিটারটি ব্যবহার করা উচিত। এটি করতে ব্যর্থতা আপনার প্রোগ্রামকে অনির্দিষ্টকালের জন্য স্তব্ধ করতে পারে: নোটের সময়সীমা পুরো প্রতিক্রিয়া ডাউনলোডের সময়সীমা নয়; পরিবর্তে, যদি সার্ভার সময়সীমা সেকেন্ডের জন্য প্রতিক্রিয়া জারি না করে তবে একটি ব্যতিক্রম উত্থাপিত হয় (আরও স্পষ্টভাবে, যদি টাইমআউট সেকেন্ডের জন্য অন্তর্নিহিত সকেটে কোনও বাইট না পাওয়া যায়)। যদি কোনও টাইমআউট স্পষ্টভাবে নির্দিষ্ট না করা হয়, তবে অনুরোধগুলির সময় শেষ হবে না।
DDay

কোড একটি টাইপো আছে: আমদানি অনুরোধ <এখানে নতুন লাইন> থেকে requests.adapters TimeoutSauce আমদানি
সিনান Çetinkaya

4

আমি একটি ডিফল্ট সময়সীমা সহজেই কোডের একগুচ্ছের সাথে যুক্ত করতে চেয়েছিলাম (ধরে নিলাম যে সময়সীমাটি আপনার সমস্যার সমাধান করে)

অনুরোধগুলির জন্য সংগ্রহস্থলের কাছে জমা দেওয়া টিকিট থেকে আমি এই সমাধানটি তুলেছি।

ক্রেডিট: https://github.com/kennethreitz/requests/issues/2011#issuecomment-477784399

সমাধানটি এখানে লাইনগুলির শেষ দু'টি, তবে আমি আরও ভাল প্রসঙ্গে আরও কোড দেখাই show আমি আবার চেষ্টা করার জন্য একটি সেশন ব্যবহার করতে চাই।

import requests
import functools
from requests.adapters import HTTPAdapter,Retry


def requests_retry_session(
        retries=10,
        backoff_factor=2,
        status_forcelist=(500, 502, 503, 504),
        session=None,
        ) -> requests.Session:
    session = session or requests.Session()
    retry = Retry(
            total=retries,
            read=retries,
            connect=retries,
            backoff_factor=backoff_factor,
            status_forcelist=status_forcelist,
            )
    adapter = HTTPAdapter(max_retries=retry)
    session.mount('http://', adapter)
    session.mount('https://', adapter)
    # set default timeout
    for method in ('get', 'options', 'head', 'post', 'put', 'patch', 'delete'):
        setattr(session, method, functools.partial(getattr(session, method), timeout=30))
    return session

তাহলে আপনি এই জাতীয় কিছু করতে পারেন:

requests_session = requests_retry_session()
r = requests_session.get(url=url,...

4

সমস্ত উত্তর পর্যালোচনা করে সিদ্ধান্তে এসেছিলেন যে সমস্যাটি এখনও রয়েছে। কিছু সাইটে অনুরোধগুলি অসীমভাবে ঝুলতে পারে এবং মাল্টিপ্রসেসিং ব্যবহার করা ওভারকিল বলে মনে হচ্ছে। এখানে আমার পদ্ধতির (পাইথন 3.5++):

import asyncio

import aiohttp


async def get_http(url):
    async with aiohttp.ClientSession(conn_timeout=1, read_timeout=3) as client:
        try:
            async with client.get(url) as response:
                content = await response.text()
                return content, response.status
        except Exception:
            pass


loop = asyncio.get_event_loop()
task = loop.create_task(get_http('http://example.com'))
loop.run_until_complete(task)
result = task.result()
if result is not None:
    content, status = task.result()
    if status == 200:
        print(content)

হালনাগাদ

আপনি যদি কান_টাইমআউট এবং রিড টাইমআউটআউট ব্যবহার সম্পর্কে অবমূল্যায়নের সতর্কতা পেয়ে থাকেন তবে কীভাবে ক্লায়েন্টটাইমআউট ডেটা কাঠামো ব্যবহার করবেন সে সম্পর্কে এই রেফারেন্সের নীচের অংশটি দেখুন। উপরের মূল কোডের লিঙ্কযুক্ত রেফারেন্স অনুযায়ী এই ডেটা স্ট্রাকচার প্রয়োগ করার একটি সহজ উপায় হ'ল:

async def get_http(url):
    timeout = aiohttp.ClientTimeout(total=60)
    async with aiohttp.ClientSession(timeout=timeout) as client:
        try:
            etc.

4
@ নাওয়াজ পাইথন 3.5++ প্রশ্নের জন্য আপনাকে ধন্যবাদ, পাইথন সংস্করণ দিয়ে উত্তর আপডেট করেছেন। এটি আইনী পাইথন কোড। দয়া করে একবার দেখুন aiohttp ডকুমেন্টেশন aiohttp.readthedocs.io/en/stable/index.html
অ্যালেক্স পোলেখা

অন্য পদ্ধতিগুলি না করলে এটি আমার সমস্যার সমাধান করে। পাই 3.7। বর্ণনাকরণের কারণে, ... টাইমআউট = আইওএইচটিপি. ক্লায়েন্টটাইমআউট (মোট = 60) অ্যাসিঙ্কটি আইওএইচটিটিপি সহ। ক্লায়েন্টসেশন (টাইমআউট = টাইমআউট) ক্লায়েন্ট হিসাবে:
থম আইভেস

2

নথিভুক্ত "প্রেরণ" ফাংশনটি প্যাচ করা সমস্ত অনুরোধগুলির জন্য এটি ঠিক করে দেবে - এমনকি অনেকগুলি নির্ভরযোগ্য লাইব্রেরি এবং এসডকে-তেও। লাইবসকে প্যাচিংয়ের সময়, টাইমআউটসোস নয়, সমর্থিত / ডকুমেন্টেড ফাংশনগুলির প্যাচ করতে ভুলবেন না - অন্যথায় আপনি আপনার প্যাচের প্রভাবটি নীরবেই শেষ করতে পারেন।

import requests

DEFAULT_TIMEOUT = 180

old_send = requests.Session.send

def new_send(*args, **kwargs):
     if kwargs.get("timeout", None) is None:
         kwargs["timeout"] = DEFAULT_TIMEOUT
     return old_send(*args, **kwargs)

requests.Session.send = new_send

কোনও টাইমআউট না থাকার প্রভাবগুলি বেশ তীব্র, এবং একটি ডিফল্ট টাইমআউট ব্যবহার প্রায় কোনও কিছুই ভাঙ্গতে পারে না - কারণ টিসিপিতে নিজেও ডিফল্ট সময়সীমা থাকে।


1

আমার ক্ষেত্রে, "requests.get কখনো আয়" এর কারণ কারণ requests.get()প্রয়াস সমাধান সঙ্গে IPv6 প্রথম IP হোস্টের সাথে সংযোগ স্থাপন । যদি ipv6 আইপি সংযোগ করতে এবং আটকে যাওয়ার জন্য কোনও ভুল হয়ে থাকে তবে আমি স্পষ্টভাবে সেট এবং টাইমআউটটি আঘাত করলেই এটি আইপিভি 4 আইপি পুনরায় চেষ্টা করে timeout=<N seconds>

আমার সমাধান বানর-প্যাচিং পাইথন socketকরার IPv6 উপেক্ষা করা (অথবা IPv4 যদি IPv4 কাজ করছে না), হয় এই উত্তরটি বা এই উত্তরটি আমার জন্য কাজ করে থাকে।

curlকমান্ডটি কেন কাজ curlকরছে তা আপনি ভাবতে পারেন , কারণ আইপিভি 6 সম্পূর্ণ হওয়ার অপেক্ষা না করেই আইপিভি 4 সংযুক্ত করুন। আপনি strace -ff -e network -s 10000 -- curl -vLk '<your url>'কমান্ড সহ সকেট সিস্কেলগুলি ট্রেস করতে পারেন । পাইথনের জন্য strace -ff -e network -s 10000 -- python3 <your python script>কমান্ড ব্যবহার করা যেতে পারে।

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