web-dev-qa-db-ja.com

なぜrequests.get()が返らないのですか? requests.get()が使用するデフォルトのタイムアウトは何ですか?

私のスクリプトでは、requests.getは決して返しません:

import requests

print ("requesting..")

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

print(r.ok)

考えられる理由は何ですか?救済策はありますか? getが使用するデフォルトのタイムアウトは何ですか?

75
Nawaz

Getが使用するデフォルトのタイムアウトは何ですか?

デフォルトのタイムアウトはNoneです。つまり、接続が閉じられるまで待機(ハング)します。

タイムアウト値を渡すとどうなりますか?

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

ドキュメントのリクエスト から:

タイムアウトパラメータを使用して、指定された秒数後に応答の待機を停止するようにリクエストに指示できます。

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

注意:

タイムアウトは、応答ダウンロード全体の時間制限ではありません。むしろ、サーバーがタイムアウト秒の間応答を発行しなかった場合(より正確には、タイムアウト秒の間、基礎となるソケットでバイトが受信されなかった場合)、例外が発生します。

timeoutが1秒であっても、requests.get()が返されるまでに非常に長い時間がかかることはよく起こります。この問題を解決する方法はいくつかあります。

1。 TimeoutSauce内部クラスを使用します

From: 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

このコードにより、接続タイムアウトと同等の読み取りタイムアウトが設定されます。これは、Session.get()呼び出しで渡すタイムアウト値です。 (このコードは実際にはテストしていないため、簡単なデバッグが必要になる場合があります。GitHubウィンドウに直接書き込みました。)

2。 kevinburkeからのリクエストのフォークを使用します:https://github.com/kevinburke/requests/tree/connect-timeout

そのドキュメントから: 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))

注: 変更はメインのRequestsプロジェクトにマージされました

3。 evenletまたはsignalを使用して、同様の質問で既に述べたように:python requests.get応答全体のタイムアウト

31
Hieu

すべての回答を確認し、問題がまだ存在するという結論に達しました。一部のサイトでは、リクエストが無限にハングすることがあり、マルチプロセッシングの使用は過剰であるようです。これが私のアプローチです(Python 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)
2
Alex Polekha

デフォルトのタイムアウトを簡単に多くのコードに追加したかった(タイムアウトが問題を解決すると仮定)

これは、リクエストのリポジトリに送信されたチケットから選択したソリューションです。

クレジット: 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,...
0
Tim Richardson