programing

python 요청 시간 초과.전체 응답 가져오기

yoursource 2022. 10. 22. 13:11
반응형

python 요청 시간 초과.전체 응답 가져오기

웹사이트 목록으로 통계를 수집하고 있으며, 단순화를 위해 요청을 사용하고 있습니다.코드는 다음과 같습니다.

data=[]
websites=['http://google.com', 'http://bbc.co.uk']
for w in websites:
    r= requests.get(w, verify=False)
    data.append( (r.url, len(r.content), r.elapsed.total_seconds(), str([(l.status_code, l.url) for l in r.history]), str(r.headers.items()), str(r.cookies.items())) )

나는 ㅇㅇ, ㅇㅇ를 원해.requests.get루프가 걸리지 않도록 10초 후에 타임아웃합니다.

이 질문 역시 이전에도 관심이 많았지만 답이 명확하지 않다.좋은 답변을 얻기 위해 현상금을 걸겠습니다.

리퀘스트를 사용하지 않는 것이 좋을지도 모른다고 들었습니다만, 리퀘스트의 좋은 점은 어떻게 얻을 수 있을까요?(태플에 있는 사람들)

timeout 파라미터를 설정합니다.

r = requests.get(w, verify=False, timeout=10) # 10 seconds

버전 2.25.1의 변경 사항

에 의해, 은 「Call」(콜은, 「」(콜)이 .requests.get()읽기 간 연결 또는 지연 시간이 10초 이상 걸리는 경우 타임아웃합니다.참조: https://requests.readthedocs.io/en/stable/user/advanced/ # 타임아웃

eventlet을 사용하면 어떨까요?데이터를 수신하고 있는 경우라도, 10초 후에 요구를 타임 아웃 하는 경우는, 다음의 스니펫이 유효합니다.

import requests
import eventlet
eventlet.monkey_patch()

with eventlet.Timeout(10):
    requests.get("http://ipv4.download.thinkbroadband.com/1GB.zip", verify=False)

업데이트: https://requests.readthedocs.io/en/master/user/advanced/ # 타임아웃

requests:

타임아웃에 단일 값을 지정하는 경우 다음과 같이 됩니다.

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

은 양쪽 됩니다.connectread개별적으로 는, 합니다.값을 개별적으로 설정하려면 태플을 지정합니다.

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

리모트 서버의 속도가 매우 느린 경우 None을 타임아웃 값으로 전달하고 커피 한 잔을 가져오면 응답을 영원히 대기하도록 요청자에게 지시할 수 있습니다.

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

오래된 답변(아마도 오래전에 게시된 답변):

이 문제를 해결하는 다른 방법이 있습니다.

. 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):
        connect = kwargs.get('connect', 5)
        read = kwargs.get('read', connect)
        super(MyTimeout, self).__init__(connect=connect, read=read)

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

Kevinburke가 메인 리퀘스트 프로젝트에 합병을 요청했지만 아직 수락되지 않았습니다.

timeout = int(seconds)

★★requests >= 2.4.0인수는 다음과 같이 사용할 수 있습니다.

requests.get('https://duckduckgo.com/', timeout=10)

주의:

timeout는 응답 대신 '시간 제한'입니다.exception서버가 타임아웃초 동안 응답을 발행하지 않은 경우(정확히 말하면 타임아웃초 동안 기본 소켓에서 바이트가 수신되지 않은 경우)가 발생합니다.타임아웃을 명시적으로 지정하지 않으면 요청은 타임아웃되지 않습니다.

타임아웃을 작성하려면 신호를 사용합니다.

이 사건을 해결하는 최선의 방법은 아마도

  1. 알람 신호의 핸들러로서 예외를 설정합니다.
  2. 10초 지연된 경보 신호를 호출합니다.
  3. .try-except-finally
  4. 함수가 시간 초과되면 예외 블록에 도달합니다.
  5. 마지막 블록에서 알람을 중단하면 나중에 알람이 해제되지 않습니다.

다음은 코드 예시입니다.

import signal
from time import sleep

class TimeoutException(Exception):
    """ Simple Exception to be called on timeouts. """
    pass

def _timeout(signum, frame):
    """ Raise an TimeoutException.

    This is intended for use as a signal handler.
    The signum and frame arguments passed to this are ignored.

    """
    # Raise TimeoutException with system default timeout message
    raise TimeoutException()

# Set the handler for the SIGALRM signal:
signal.signal(signal.SIGALRM, _timeout)
# Send the SIGALRM signal in 10 seconds:
signal.alarm(10)

try:    
    # Do our code:
    print('This will take 11 seconds...')
    sleep(11)
    print('done!')
except TimeoutException:
    print('It timed out!')
finally:
    # Abort the sending of the SIGALRM signal:
    signal.alarm(0)

여기에는 몇 가지 경고가 있습니다.

  1. 스레드 세이프가 아닙니다.신호는 항상 메인 스레드에 전달되기 때문에 다른 스레드에 넣을 수 없습니다.
  2. 신호의 스케줄링과 실제 코드 실행 후 약간의 지연이 있습니다.즉, 이 예에서는 sleeve 상태가 10초밖에 되지 않아도 타임아웃이 됩니다.

하지만, 이것은 모두 표준 비단뱀 라이브러리에 있습니다!sleep 기능 Import를 제외하고 Import는 1개뿐입니다.많은 장소에서 타임아웃을 사용할 경우 타임아웃을 쉽게 설정할 수 있습니다.예외, _timeout 및 함수의 싱글링.그냥 호출해 주세요.또는 데코레이터를 만들어 기능에 붙일 수 있습니다.아래 링크된 답변을 참조하십시오.

또, 이것을 「콘텍스트 매니저로서 셋업 할 수도 있습니다.이것에 의해, 이 콘텍스트 매니저는,with★★★★★★★★

import signal
class Timeout():
    """ Timeout for use with the `with` statement. """

    class TimeoutException(Exception):
        """ Simple Exception to be called on timeouts. """
        pass

    def _timeout(signum, frame):
        """ Raise an TimeoutException.

        This is intended for use as a signal handler.
        The signum and frame arguments passed to this are ignored.

        """
        raise Timeout.TimeoutException()

    def __init__(self, timeout=10):
        self.timeout = timeout
        signal.signal(signal.SIGALRM, Timeout._timeout)

    def __enter__(self):
        signal.alarm(self.timeout)

    def __exit__(self, exc_type, exc_value, traceback):
        signal.alarm(0)
        return exc_type is Timeout.TimeoutException

# Demonstration:
from time import sleep

print('This is going to take maximum 10 seconds...')
with Timeout(10):
    sleep(15)
    print('No timeout?')
print('Done')

이 콘텍스트 매니저 접근방식의 단점은 코드가 실제로 타임아웃되었는지 여부를 알 수 없다는 것입니다.

소스 및 권장 판독치:

타임아웃 및 오류 처리를 사용하여 다음 요청을 시도합니다.

import requests
try: 
    url = "http://google.com"
    r = requests.get(url, timeout=10)
except requests.exceptions.Timeout as e: 
    print e

접속 타임아웃은number of seconds요구는 클라이언트가 소켓 상의 리모트머신(connect()에 대응) 콜에 접속할 때까지 대기합니다.접속 타임아웃을 디폴트 TCP 패킷 재발송신창인 3의 배수보다 약간 크게 설정하는 것이 좋습니다.

클라이언트가 서버에 접속해 HTTP 요구를 송신하면, 판독 타임 아웃이 개시됩니다.서버가 응답을 송신할 때까지 클라이언트가 대기하는 초수입니다.(구체적으로는, 클라이언트가 서버로부터 송신되는 바이트간에 대기하는 초수입니다.99.9%의 경우, 이것은 서버가 최초의 바이트를 송신할 때까지의 시간입니다).

타임아웃에 단일 값을 지정하면 타임아웃 값이 연결 타임아웃과 읽기 타임아웃 모두에 적용됩니다.다음과 같습니다.

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

연결 및 읽기에 대한 값을 별도로 설정하려면 태플을 지정합니다.

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

리모트 서버의 속도가 매우 느린 경우 None을 타임아웃 값으로 전달하고 커피 한 잔을 가져오면 응답을 영원히 대기하도록 요청자에게 지시할 수 있습니다.

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

https://docs.python-requests.org/en/latest/user/advanced/ # 타임아웃

다른 대부분의 답변은 올바르지 않습니다.

모든 답변에도 불구하고, 나는 이 스레드가 여전히 적절한 해결책이 부족하며, 기존의 어떤 답변도 단순하고 명백해야 할 일을 하는 합리적인 방법을 제시하지 않는다고 생각한다.

일단 2022년 현재, 그것만으로는 제대로 할 수 있는 방법이 전혀 없다는 것부터 시작합시다. 그것은 도서관 개발자들의 신중한 설계 결정이다.

timeout파라미터는 단순히 의도한 바를 달성하지 못할 뿐입니다.언뜻 보기에 효과가 있는 것처럼 보이는 것은 순전히 부수적인 것입니다.

timeout파라미터는 요청의 총 실행 시간과는 전혀 관계가 없습니다.기본 소켓이 데이터를 수신할 때까지의 최대 시간을 제어할 뿐입니다.예를 들어 타임아웃이 5초인 경우 서버는 4초마다 1바이트의 데이터를 전송할 수 있습니다.그러면 문제없지만 큰 도움이 되지 않습니다.

회:로:stream ★★★★★★★★★★★★★★★★★」iter_content어느 정도 개선되었지만, 여전히 요청의 모든 것을 커버하는 것은 아닙니다..iter_content까지, 합니다.「」의 로서 1 에서도, 「1 바이트」는 같은 문제가 됩니다.iter_content 데 수 , 는, 「」로부터 수 .iter_content.

두 가지를 몇 가지 있습니다.timeout ★★★★★★★★★★★★★★★★★」stream를 기반으로 합니다.이렇게 방법을 .어떤 방법을 사용하든 모두 무기한 매달려 있습니다.

server.py

import socket
import time

server = socket.socket()

server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
server.bind(('127.0.0.1', 8080))

server.listen()

while True:
    try:
        sock, addr = server.accept()
        print('Connection from', addr)
        sock.send(b'HTTP/1.1 200 OK\r\n')

        # Send some garbage headers very slowly but steadily.
        # Never actually complete the response.

        while True:
            sock.send(b'a')
            time.sleep(1)
    except:
        pass

demo1.py

import requests

requests.get('http://localhost:8080')

demo2.py

import requests

requests.get('http://localhost:8080', timeout=5)

demo3.py

import requests

requests.get('http://localhost:8080', timeout=(5, 5))

demo4.py

import requests

with requests.get('http://localhost:8080', timeout=(5, 5), stream=True) as res:
    for chunk in res.iter_content(1):
        break

적절한 해결책

나의 접근법은 Python의 기능을 이용한다.아주 간단하다.외부 라이브러리를 사용하거나 코드를 거꾸로 할 필요가 없습니다.다른 대부분의 응답과 달리, 이것은 실제로 코드가 지정된 시간 내에 실행되도록 보장합니다.이 경우에도 다음 명령어를 지정해야 합니다.timeout로서)settrace파이썬는 외부 시스템에는 되지 않습니다.이치노settrace 이 은 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아,timeout파라미터를 지정합니다..TOTAL_TIMEOUT아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 맞다.

import requests
import sys
import time

# This function serves as a "hook" that executes for each Python statement
# down the road. There may be some performance penalty, but as downloading
# a webpage is mostly I/O bound, it's not going to be significant.

def trace_function(frame, event, arg):
    if time.time() - start > TOTAL_TIMEOUT:
        raise Exception('Timed out!') # Use whatever exception you consider appropriate.

    return trace_function

# The following code will terminate at most after TOTAL_TIMEOUT + the highest
# value specified in `timeout` parameter of `requests.get`.
# In this case 10 + 6 = 16 seconds.
# For most cases though, it's gonna terminate no later than TOTAL_TIMEOUT.

TOTAL_TIMEOUT = 10

start = time.time()

sys.settrace(trace_function)

try:
    res = requests.get('http://localhost:8080', timeout=(3, 6)) # Use whatever timeout values you consider appropriate.
except:
    raise
finally:
    sys.settrace(None) # Remove the time constraint and continue normally.

# Do something with the response

응축

import requests, sys, time

TOTAL_TIMEOUT = 10

def trace_function(frame, event, arg):
    if time.time() - start > TOTAL_TIMEOUT:
        raise Exception('Timed out!')

    return trace_function

start = time.time()
sys.settrace(trace_function)

try:
    res = requests.get('http://localhost:8080', timeout=(3, 6))
except:
    raise
finally:
    sys.settrace(None)

바로 그거야!

★★stream=True를 사용합니다.r.iter_content(1024) 그렇습니다eventlet.Timeout왠지 통하지 않는 것 같아

try:
    start = time()
    timeout = 5
    with get(config['source']['online'], stream=True, timeout=timeout) as r:
        r.raise_for_status()
        content = bytes()
        content_gen = r.iter_content(1024)
        while True:
            if time()-start > timeout:
                raise TimeoutError('Time out! ({} seconds)'.format(timeout))
            try:
                content += next(content_gen)
            except StopIteration:
                break
        data = content.decode().split('\n')
        if len(data) in [0, 1]:
            raise ValueError('Bad requests data')
except (exceptions.RequestException, ValueError, IndexError, KeyboardInterrupt,
        TimeoutError) as e:
    print(e)
    with open(config['source']['local']) as f:
        data = [line.strip() for line in f.readlines()]

자세한 것은, https://redd.it/80kp1h 를 참조해 주세요.

이는 오버킬일 수 있지만 Celery 분산 태스크큐는 타임아웃을 충분히 지원합니다.

특히 프로세스에서 예외만 발생시키는 소프트 시간 제한(청소를 위해) 및 시간 제한이 초과되면 작업을 종료하는 하드 시간 제한을 정의할 수 있습니다.

여기에서는, 「전」의 투고와 같은 신호 어프로치를 사용하고 있습니다만, 보다 사용하기 쉽고 관리하기 쉬운 방법을 사용하고 있습니다.감시하고 있는 웹 사이트의 리스트가 길면, 그 주된 기능, 즉 많은 태스크의 실행을 관리하는 모든 종류의 방법을 이용할 수 있습니다.

쓰면 될 것 요.multiprocessing'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE:

import multiprocessing
import requests

def call_with_timeout(func, args, kwargs, timeout):
    manager = multiprocessing.Manager()
    return_dict = manager.dict()

    # define a wrapper of `return_dict` to store the result.
    def function(return_dict):
        return_dict['value'] = func(*args, **kwargs)

    p = multiprocessing.Process(target=function, args=(return_dict,))
    p.start()

    # Force a max. `timeout` or wait for the process to finish
    p.join(timeout)

    # If thread is still active, it didn't finish: raise TimeoutError
    if p.is_alive():
        p.terminate()
        p.join()
        raise TimeoutError
    else:
        return return_dict['value']

call_with_timeout(requests.get, args=(url,), kwargs={'timeout': 10}, timeout=60)

kwargs서버로부터의 응답을 취득하기 위한 타임아웃입니다.인수입니다.timeout완전한 응답을 얻기 위한 타임아웃입니다.

요청에 대한 질문입니다만, pycurl CURLOPT_TIMEOUT 또는 CURLOPT_TIMEOUT_MS에서는 매우 쉽게 할 수 있습니다.

스레드화 또는 시그널링 불필요:

import pycurl
import StringIO

url = 'http://www.example.com/example.zip'
timeout_ms = 1000
raw = StringIO.StringIO()
c = pycurl.Curl()
c.setopt(pycurl.TIMEOUT_MS, timeout_ms)  # total timeout in milliseconds
c.setopt(pycurl.WRITEFUNCTION, raw.write)
c.setopt(pycurl.NOSIGNAL, 1)
c.setopt(pycurl.URL, url)
c.setopt(pycurl.HTTPGET, 1)
try:
    c.perform()
except pycurl.error:
    traceback.print_exc() # error generated on timeout
    pass # or just pass if you don't want to print the error

stream=True이치노

r = requests.get(
    'http://url_to_large_file',
    timeout=1,  # relevant only for underlying socket
    stream=True)

with open('/tmp/out_file.txt'), 'wb') as f:
    start_time = time.time()
    for chunk in r.iter_content(chunk_size=1024):
        if chunk:  # filter out keep-alive new chunks
            f.write(chunk)
        if time.time() - start_time > 8:
            raise Exception('Request took longer than 8s')

이 솔루션에는 신호나 멀티프로세싱이 필요하지 않습니다.

또 하나의 솔루션(http://docs.python-requests.org/en/master/user/advanced/ #syslog-syslog에서 입수)

업로드하기 전에 콘텐츠 크기를 확인할 수 있습니다.

TOO_LONG = 10*1024*1024  # 10 Mb
big_url = "http://ipv4.download.thinkbroadband.com/1GB.zip"
r = requests.get(big_url, stream=True)
print (r.headers['content-length'])
# 1073741824  

if int(r.headers['content-length']) < TOO_LONG:
    # upload content:
    content = r.content

그러나 송신자는 '콘텐츠 길이' 응답 필드에 잘못된 값을 설정할 수 있습니다.

timeout =(연결 시간 초과, 데이터 읽기 시간 초과) 또는 단일 인수 제공(timeout=1)

import requests

try:
    req = requests.request('GET', 'https://www.google.com',timeout=(1,1))
    print(req)
except requests.ReadTimeout:
    print("READ TIME OUT")

이 코드는 socketError 11004 및 10060에서 작동합니다...

# -*- encoding:UTF-8 -*-
__author__ = 'ACE'
import requests
from PyQt4.QtCore import *
from PyQt4.QtGui import *


class TimeOutModel(QThread):
    Existed = pyqtSignal(bool)
    TimeOut = pyqtSignal()

    def __init__(self, fun, timeout=500, parent=None):
        """
        @param fun: function or lambda
        @param timeout: ms
        """
        super(TimeOutModel, self).__init__(parent)
        self.fun = fun

        self.timeer = QTimer(self)
        self.timeer.setInterval(timeout)
        self.timeer.timeout.connect(self.time_timeout)
        self.Existed.connect(self.timeer.stop)
        self.timeer.start()

        self.setTerminationEnabled(True)

    def time_timeout(self):
        self.timeer.stop()
        self.TimeOut.emit()
        self.quit()
        self.terminate()

    def run(self):
        self.fun()


bb = lambda: requests.get("http://ipv4.download.thinkbroadband.com/1GB.zip")

a = QApplication([])

z = TimeOutModel(bb, 500)
print 'timeout'

a.exec_()

이 페이지에서 많은 솔루션을 시도했지만 여전히 불안정, 랜덤 행업, 접속 성능 저하에 직면했습니다.

현재 Curl을 사용하고 있습니다.이 기능은 "최대 시간" 기능과 글로벌 퍼포먼스에 매우 만족하고 있습니다.설령 구현이 서툴러도 마찬가지입니다.

content=commands.getoutput('curl -m6 -Ss "http://mywebsite.xyz"')

여기에서는 연결과 전송 시간을 모두 포함하는 최대 6초 파라미터를 정의했습니다.

만약 당신이 phythonic 구문을 고수하고 싶다면, Curl은 훌륭한 python 바인딩을 가지고 있다고 확신합니다.

python 함수의 타임아웃에 사용할 수 있는 timeout-decorator라는 패키지가 있습니다.

@timeout_decorator.timeout(5)
def mytest():
    print("Start")
    for i in range(1,10):
        time.sleep(1)
        print("{} seconds have passed".format(i))

여기에서는, 몇개의 회답이 제안하는 신호 어프로치를 사용하고 있습니다.또는 신호 대신 멀티 프로세싱을 사용하도록 지시할 수 있습니다(예: 멀티 스레드 환경에 있는 경우).

이 경우 10초 후에 요청의 내부 상태를 혼란시키는 워치독스레드를 만듭니다.다음은 예를 제시하겠습니다.

  • 기본 소켓을 닫고 이상적으로는
  • 요구가 조작을 재시도할 경우 예외를 트리거합니다.

시스템 라이브러리에 따라 DNS 해결 기한을 설정하지 못할 수 있습니다.

요청 2.2.1을 사용하고 있는데 eventlet이 작동하지 않았습니다.대신 gevent 타임아웃을 사용할 수 있었습니다. gevent는 gunicorn을 위해 제 서비스에 사용되기 때문입니다.

import gevent
import gevent.monkey
gevent.monkey.patch_all(subprocess=True)
try:
    with gevent.Timeout(5):
        ret = requests.get(url)
        print ret.status_code, ret.content
except gevent.timeout.Timeout as e:
    print "timeout: {}".format(e.message)

gevent.timeout이라는 점에 .일반적인 예외 처리에서는 타임아웃이 검출되지 않습니다.으로 캐치하거나 둘 중 를 잡았거나.gevent.timeout.Timeout하기도 합니다.with gevent.Timeout(5, requests.exceptions.Timeout):단, 이 예외가 발생해도 메시지는 전달되지 않습니다.

큰 수 , 「」는 「」라고 하는 입니다.requests패키지가 너무 오래 대기하여 프로그램의 나머지 부분을 차단합니다.

몇 가지 방법이 있습니다만, 요청과 비슷한 오넬리너를 찾아보니 아무것도 없었습니다.그래서 제가 의뢰를 중심으로 래퍼를 만든 겁니다reqto(' timeout : "display timeout" ('display timeout')의 모든 requests.

pip install reqto

구문이 요청과 동일합니다.

import reqto

response = reqto.get(f'https://pypi.org/pypi/reqto/json',timeout=1)
# Will raise an exception on Timeout
print(response)

게다가 커스텀 타임 아웃 기능을 설정할 수 있습니다.

def custom_function(parameter):
    print(parameter)


response = reqto.get(f'https://pypi.org/pypi/reqto/json',timeout=5,timeout_function=custom_function,timeout_args="Timeout custom function called")
#Will call timeout_function instead of raising an exception on Timeout
print(response)

중요한 점은 Import 라인이

import reqto

백그라운드에서 실행되는 monkey_discloss로 인해 요청, 스레드화 등을 처리하는 다른 모든 Import보다 빨리 Import해야 합니다.

나는 분명히 추악하지만 진짜 문제를 해결하는 보다 직접적인 해결책을 생각해냈다.약간은 다음과 같습니다.

resp = requests.get(some_url, stream=True)
resp.raw._fp.fp._sock.settimeout(read_timeout)
# This will load the entire response even though stream is set
content = resp.content

자세한 설명은 이쪽에서 보실 수 있습니다.

언급URL : https://stackoverflow.com/questions/21965484/timeout-for-python-requests-get-entire-response

반응형