क्यों नहीं अनुरोध करता है। () वापसी? डिफ़ॉल्ट टाइमआउट क्या है जो request.get () का उपयोग करता है?


92

मेरी स्क्रिप्ट में, 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उपयोग करता है?


1
@ user2357112: क्या यह मायने रखता है? मुझे शक है।
नवाज

यह निश्चित रूप से मायने रखता है। यदि आप वह URL प्रदान करते हैं जिसे आप एक्सेस करने का प्रयास कर रहे हैं और जिस प्रॉक्सी का आप उपयोग करना चाह रहे हैं, हम देख सकते हैं कि जब हम समान अनुरोध भेजने का प्रयास करते हैं तो क्या होता है।
user2357112

1
@ user2357112: ठीक है। प्रश्न संपादित किया।
नवाज

2
आपका प्रॉक्सी भी गलत है। आप इसे इतना पसंद उल्लेख करना होगा: proxies={'http': 'http://222.255.169.74:8080'}। यही कारण है कि यह बिना टाइमआउट के पूरा नहीं हो सकता है।
इयान स्टैपलटन कॉर्डैस्को

जवाबों:


127

डिफ़ॉल्ट टाइमआउट क्या है जो उपयोग करता है?

डिफ़ॉल्ट टाइमआउट है None, जिसका अर्थ है कि यह कनेक्शन बंद होने तक प्रतीक्षा (लटका) करेगा।

जब आप टाइमआउट मान में पास होते हैं तो क्या होता है?

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

3
मुझे लगता है कि आप सही हैं। Noneअनंत का अर्थ है (या "जब तक कनेक्शन बंद न हो जाए" प्रतीक्षा करें)। अगर मैं खुद को टाइमआउट कर लेता हूं, तो यह वापस आ जाता है!
नवाज

14
@ उपयोगकर्ता टाइमआउट केवल https के साथ ठीक काम करता है जैसा कि http
jaapz

यह डॉक्स को खोजने के लिए वास्तव में कठिन लगता है। किसी को पता है कि यह डॉक्स में कहां दिखाई देता है?
शब्दफोर्ट वाइज


धन्यवाद, print(requests.request.__doc__)IPython में कर रहा है जो मैं के लिए देख रहा था की अधिक है। मैं सोच रहा था कि request.get()वहाँ अन्य वैकल्पिक तर्क क्या थे।
शब्दफोर्ट वाइज

39

से अनुरोध प्रलेखन :

आप टाइमआउट पैरामीटर के साथ दिए गए कुछ सेकंड के बाद प्रतिक्रिया का इंतजार करने के लिए अनुरोध कर सकते हैं:

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

ध्यान दें:

टाइमआउट संपूर्ण प्रतिक्रिया डाउनलोड पर समय सीमा नहीं है; इसके बजाय, यदि सर्वर ने टाइमआउट सेकंड के लिए कोई प्रतिक्रिया जारी नहीं की है, तो एक अपवाद उठाया जाता है (अधिक सटीक रूप से, यदि टाइमआउट सेकंड के लिए अंतर्निहित सॉकेट पर कोई बाइट्स प्राप्त नहीं हुए हैं)।

यह मेरे लिए बहुत कुछ होता है कि request.get () timeout1 सेकंड होने पर भी वापस लौटने में बहुत लंबा समय लेता है । इस समस्या को दूर करने के कुछ तरीके हैं:

1. TimeoutSauceआंतरिक वर्ग का उपयोग करें

प्रेषक: https://github.com/kennethreitz/requests/issues/1928#issuecomment-35-3511116

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

यह कोड हमें रीड टाइमआउट को कनेक्ट टाइमआउट के बराबर सेट करने का कारण बनता है, जो कि आपके Session.get () कॉल पर आपके द्वारा पास किए जाने वाले टाइमआउट मूल्य है। (ध्यान दें कि मैंने वास्तव में इस कोड का परीक्षण नहीं किया है, इसलिए इसे कुछ त्वरित डिबगिंग की आवश्यकता हो सकती है, मैंने इसे सीधे GHHHH विंडो में लिखा है।)

2. केविनबर्क से अनुरोधों के एक कांटे का प्रयोग करें: https://github.com/kevinburke/requests/tree/connect-time

इसके प्रलेखन से: 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))

नोट: परिवर्तन तब से मुख्य अनुरोध परियोजना में विलय कर दिया गया है

3. इसी तरह के प्रश्न में वर्णित evenletया signalजैसा कि पहले ही बताया जा चुका है: अजगर के अनुरोधों के लिए समय समाप्त। संपूर्ण प्रतिक्रिया


7
आपने कभी उत्तर नहीं दिया कि डिफ़ॉल्ट क्या है
उपयोगकर्ता

उद्धरण: आप टाइमआउट पैरामीटर के साथ दिए गए कुछ सेकंड के बाद प्रतिक्रिया के लिए प्रतीक्षा करना बंद करने का अनुरोध कर सकते हैं। लगभग सभी अनुरोधों में लगभग सभी उत्पादन कोड को इस पैरामीटर का उपयोग करना चाहिए। ऐसा करने में विफलता आपके कार्यक्रम को अनिश्चित काल तक लटकाए जाने का कारण बन सकती है: नोट टाइमआउट संपूर्ण प्रतिक्रिया डाउनलोड पर एक समय सीमा नहीं है; इसके बजाय, यदि सर्वर ने टाइमआउट सेकंड के लिए कोई प्रतिक्रिया जारी नहीं की है, तो एक अपवाद उठाया जाता है (अधिक सटीक रूप से, यदि टाइमआउट सेकंड के लिए अंतर्निहित सॉकेट पर कोई बाइट्स प्राप्त नहीं हुए हैं)। यदि कोई टाइमआउट स्पष्ट रूप से निर्दिष्ट नहीं किया गया है, तो अनुरोधों का समय समाप्त नहीं होता है।
डीडीए

कोड में एक टाइपो है: आयात अनुरोध <नई लाइन यहां> request.adapters आयात टाइमआउट से
सिनान

4

मैं कोड के एक समूह में आसानी से डिफ़ॉल्ट टाइमआउट चाहता था (यह मानते हुए कि टाइमआउट आपकी समस्या हल करता है)

यह वह समाधान है जिसे मैंने अनुरोध के लिए भंडार में प्रस्तुत टिकट से उठाया था।

श्रेय: https://github.com/kennethreitz/requests/issues/2011#issuecomment-477784399

समाधान यहाँ लाइनों की अंतिम जोड़ी है, लेकिन मैं बेहतर संदर्भ के लिए अधिक कोड दिखाता हूं। मैं रिट्रीट व्यवहार के लिए एक सत्र का उपयोग करना पसंद करता हूं।

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)

अपडेट करें

यदि आप con_timeout और read_timeout का उपयोग करने के बारे में एक पदावनति चेतावनी प्राप्त करते हैं, तो क्लाइंट टाइमआउट डेटा संरचना का उपयोग करने के लिए इस संदर्भ के निचले भाग के पास की जाँच करें । ऊपर दिए गए मूल कोड से जुड़े संदर्भ के अनुसार इस डेटा संरचना को लागू करने का एक सरल तरीका होगा:

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

2
@ नवाज़ पायथन 3.5+। सवाल के लिए धन्यवाद, पायथन संस्करण के साथ उत्तर को अपडेट किया। यह कानूनी पायथन कोड है। कृपया aiohttp प्रलेखन aiohttp.readthedocs.io/en/stable/index.html
एलेक्स पोलेखा

यह मेरे मुद्दों को हल किया जब अन्य तरीके नहीं होगा। Py 3.7। Deprication के कारण, का उपयोग करना पड़ा ... समयबाह्य = aiohttp.ClientTimeout (कुल = 60) async के साथ aiohttp.ClientSession (समयबाह्य = समयबाह्य) ग्राहक के रूप में:
Thom Ives

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

किसी भी टाइमआउट के न होने के प्रभाव काफी गंभीर हैं, और एक डिफ़ॉल्ट टाइमआउट का उपयोग लगभग कभी भी कुछ भी नहीं तोड़ सकता है - क्योंकि टीसीपी में ही डिफ़ॉल्ट टाइमआउट है।


0

मेरे मामले में, "request.get कभी नहीं लौटता" का कारण यह है क्योंकि पहले ipv6 आईपी के साथ हल किए गए होस्टrequests.get() से कनेक्ट करने का प्रयास । अगर उस ipv6 ip को जोड़ने और अटकने के लिए कुछ गलत हुआ, तो यह ipv4 ip को केवल तभी हटाता है जब मैंने स्पष्ट रूप से सेट किया timeout=<N seconds>और टाइमआउट मारा।

मेरे समाधान है बंदर-पैच अजगर socketको आईपीवी 6 की अनदेखी (या IPv4 अगर आईपीवी 4 काम नहीं कर रहा), या तो इस सवाल का जवाब या क्या यह उत्तर मेरे लिए काम करता है कर रहे हैं।

आप सोच रहे होंगे कि curlकमांड क्यों काम कर रहा है, क्योंकि curlipv4 को ipv6 के पूरा होने तक इंतजार किए बिना कनेक्ट करें। आप strace -ff -e network -s 10000 -- curl -vLk '<your url>'कमांड के साथ सॉकेट syscalls का पता लगा सकते हैं । अजगर के लिए, strace -ff -e network -s 10000 -- python3 <your python script>कमांड का उपयोग किया जा सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.