В моем сценарии 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
используется?
python
get
python-requests
Наваз
источник
источник
proxies={'http': 'http://222.255.169.74:8080'}
. Возможно, поэтому он не завершается без тайм-аута.Ответы:
Тайм-аут по умолчанию -
None
это означает, что он будет ждать (зависать), пока соединение не будет закрыто.Что происходит, когда вы передаете значение тайм-аута?
r = requests.get( 'http://www.justdial.com', proxies={'http': '222.255.169.74:8080'}, timeout=5 )
источник
None
означает бесконечно (или «ждать, пока соединение не закроется»). Если я сам пропущу таймаут, он вернется!print(requests.request.__doc__)
в IPython - это больше того, что я искал. Мне было интересно, какие еще необязательные аргументыrequest.get()
были.Из запросов документации :
У меня часто бывает, что request.get () очень долго возвращается, даже если
timeout
это 1 секунда. Есть несколько способов решить эту проблему:1. Используйте
TimeoutSauce
внутренний классОт: https://github.com/kennethreitz/requests/issues/1928#issuecomment-35811896
2. Используйте форк запросов от kevinburke: https://github.com/kevinburke/requests/tree/connect-timeout
Из его документации: https://github.com/kevinburke/requests/blob/connect-timeout/docs/user/advanced.rst
ПРИМЕЧАНИЕ. С тех пор изменение было внесено в основной проект запросов .
3. Использование
evenlet
или,signal
как уже упоминалось в аналогичном вопросе: Тайм-аут для запросов python. Получить весь ответисточник
Я хотел, чтобы тайм-аут по умолчанию легко добавлялся в кучу кода (при условии, что тайм-аут решает вашу проблему)
Это решение, которое я взял из заявки, отправленной в репозиторий для запросов.
кредит: 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
тогда вы можете сделать что-то вроде этого:
источник
Просмотрел все ответы и пришел к выводу, что проблема все еще существует. На некоторых сайтах запросы могут зависать бесконечно, и использование многопроцессорной обработки кажется излишним. Вот мой подход (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, проверьте в нижней части ЭТОЙ справки, как использовать структуру данных ClientTimeout. Один простой способ применить эту структуру данных в соответствии со связанной ссылкой на исходный код выше:
async def get_http(url): timeout = aiohttp.ClientTimeout(total=60) async with aiohttp.ClientSession(timeout=timeout) as client: try: etc.
источник
Исправление задокументированной функции «send» исправит это для всех запросов - даже во многих зависимых библиотеках и SDK. При установке исправлений для библиотек убедитесь, что вы исправляете поддерживаемые / документированные функции, а не 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 никогда не возвращается», заключается в том, что
requests.get()
попытка подключения к хосту сначала разрешена с помощью ipv6 ip . Если что-то пошло не так, чтобы подключить этот ipv6 ip и застрять, он повторяет ipv4 ip только в том случае, если я явно установилtimeout=<N seconds>
и нажал тайм-аут.Мое решение - обезьяна исправляет питон,
socket
чтобы игнорировать ipv6 (или ipv4, если ipv4 не работает), либо этот ответ, либо этот ответ работает для меня.Вы можете спросить, почему
curl
команда работает, потому чтоcurl
подключайтесь к ipv4, не дожидаясь завершения ipv6. Вы можете отслеживать системные вызовы сокета с помощьюstrace -ff -e network -s 10000 -- curl -vLk '<your url>'
команды. Для pythonstrace -ff -e network -s 10000 -- python3 <your python script>
можно использовать команду.источник