내 스크립트에서 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
사용 하는 기본 제한 시간은 무엇입니까 ?
답변
사용되는 기본 시간 제한은 무엇입니까?
기본 시간 제한은 None
연결이 닫힐 때까지 대기 (중단)됨을 의미합니다.
시간 초과 값을 전달하면 어떻게됩니까?
r = requests.get(
'http://www.justdial.com',
proxies={'http': '222.255.169.74:8080'},
timeout=5
)
답변
에서 요청 문서 :
timeout 매개 변수를 사용하여 지정된 시간 (초) 후에 응답 대기를 중지하도록 Requests에 지시 할 수 있습니다.
>>> 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 초 동안 응답을 발행하지 않은 경우 예외가 발생합니다 (더 정확하게는 timeout 초 동안 기본 소켓에 수신 된 바이트가없는 경우).
requests.get () timeout
이 1 초라도 반환하는 데 시간이 너무 오래 걸리는 일이 많이 발생합니다 . 이 문제를 극복하는 몇 가지 방법이 있습니다.
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
이 코드는 우리가 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))
참고 : 이후 변경 사항이 기본 요청 프로젝트에 병합되었습니다 .
3. 유사한 질문에서 이미 언급했듯이 evenlet
또는 사용 signal
:
python requests.get 전체 응답에 대한 시간 초과
답변
나는 기본 시간 초과를 코드 묶음에 쉽게 추가하고 싶었습니다 (시간 초과가 문제를 해결한다고 가정)
이것이 요청 저장소에 제출 된 티켓에서 선택한 솔루션입니다.
크레딧 : 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,...
답변
모든 답변을 검토하고 문제가 여전히 존재한다는 결론에 도달했습니다. 일부 사이트에서는 요청이 무한히 멈출 수 있으며 다중 처리를 사용하는 것은 과도한 것 같습니다. 내 접근 방식 (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)
최신 정보
conn_timeout 및 read_timeout 사용에 대한 사용 중단 경고를 받으면 THIS 참조 하단 에서 ClientTimeout 데이터 구조를 사용하는 방법을 확인하십시오 . 위의 원본 코드에 연결된 참조별로이 데이터 구조를 적용하는 간단한 방법은 다음과 같습니다.
async def get_http(url):
timeout = aiohttp.ClientTimeout(total=60)
async with aiohttp.ClientSession(timeout=timeout) as client:
try:
etc.
답변
문서화 된 “send”함수를 패치하면 많은 종속 라이브러리와 SDK에서도 모든 요청에 대해이 문제가 해결됩니다. libs를 패치 할 때 TimeoutSauce가 아닌 지원 / 문서화 된 기능을 패치해야합니다. 그렇지 않으면 패치의 효과를 잃을 수 있습니다.
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
시간 초과가없는 경우의 영향은 매우 심각하며 기본 시간 초과를 사용하면 TCP 자체에도 기본 시간 초과가 있기 때문에 거의 아무것도 중단 할 수 없습니다.
답변
제 경우에는 “requests.get never returns”의 이유 는 호스트requests.get()
에 연결 하려는 시도가 먼저 ipv6 ip로 해결 되었기 때문 입니다. 해당 ipv6 ip를 연결하는 데 문제가 발생하여 중단 되면 명시 적으로 설정 timeout=<N seconds>
하고 시간 초과에 도달 한 경우에만 ipv4 ip를 재 시도 합니다.
내 솔루션은 원숭이 패치 파이썬을 socket
위해 IPv6를 무시 하거나, (또는 IPv4의 IPv4를 작동하지 않는 경우) 이 답변 또는 이 대답은 나를위한 작품이다.
ipv6이 완료 될 때까지 기다리지 않고 ipv4를 연결 curl
하기 때문에 명령이 작동하는 이유가 궁금 할 수 있습니다 curl
. strace -ff -e network -s 10000 -- curl -vLk '<your url>'
명령을 사용 하여 소켓 시스템 호출을 추적 할 수 있습니다 . 파이썬의 경우 strace -ff -e network -s 10000 -- python3 <your python script>
명령을 사용할 수 있습니다.