파이썬 요청으로 비동기 요청


142

파이썬 요청 라이브러리 문서에 제공된 샘플을 사용해 보았습니다 .

async.map(rs)응답 코드를 얻었지만 요청 된 각 페이지의 내용을 가져오고 싶습니다. 예를 들어 이것은 작동하지 않습니다.

out = async.map(rs)
print out[0].content

어쩌면 당신이 받고있는 반응에 빈 몸이 있습니까?
Mariusz Jamro

나를 위해 작동합니다. 발생하는 전체 오류를 게시하십시오.
Chewie

오류가 없습니다. 제공된 테스트 URL에 의해 영원히 실행됩니다.
trbck February

https를 통해 URL을 사용할 때 분명히 나타납니다. HTTP는 잘 작동
trbck의

requests-threads지금 존재하는 것 같습니다 .
OrangeDog

답변:


154

노트

아래 답변은 v0.13.0 + 요청 에는 적용 되지 않습니다 . 이 질문이 작성된 후 비동기 기능이 grequests 로 이동되었습니다 . 그러나, 당신은 대체 할 수 requests와 함께 grequests아래 그것은 작동합니다.

<v0.13.0 요청 사용에 관한 원래 질문을 반영하기 위해이 답변을 그대로 두었습니다.


async.map 비동기 적으로 여러 작업을 수행하려면 다음을 수행 해야합니다.

  1. 각 객체로 수행하려는 작업 (작업)에 대한 기능 정의
  2. 요청에 이벤트 후크로 해당 기능 추가
  3. async.map모든 요청 / 조치 목록에서 전화

예:

from requests import async
# If using requests > v0.13.0, use
# from grequests import async

urls = [
    'http://python-requests.org',
    'http://httpbin.org',
    'http://python-guide.org',
    'http://kennethreitz.com'
]

# A simple task to do to each response object
def do_something(response):
    print response.url

# A list to hold our things to do via async
async_list = []

for u in urls:
    # The "hooks = {..." part is where you define what you want to do
    # 
    # Note the lack of parentheses following do_something, this is
    # because the response will be used as the first argument automatically
    action_item = async.get(u, hooks = {'response' : do_something})

    # Add the task to our list of things to do via async
    async_list.append(action_item)

# Do our list of things to do via async
async.map(async_list)

2
의견을 남길 수있는 좋은 아이디어 : 최신 요청과 grequests (요청 1.1.0의 max_retries 옵션 부족) ​​간의 호환성 문제로 인해 비동기를 검색하기 위해 요청을 다운 그레이드해야했으며 비동기 기능이 0.13 이상 버전으로 이동했습니다. ( pypi.python.org/pypi/requests )
outforawhile

1
멍청한 질문 : 단순한 요청과는 달리 grequest를 사용하는 속도는 어느 정도입니까? 요청과 관련하여 어떤 제한이 있습니까? 예를 들어 async.map에 3500 개의 요청을 입력해도 괜찮습니까?
droope

10
from grequests import async하지 작업 .. 나를 위해 일을 해봐요의 정의를 이렇게 def do_something(response, **kwargs):, 나는에서 찾을 stackoverflow.com/questions/15594015/...
앨런 망치

3
async.map 호출이 여전히 차단되면 어떻게 비동기입니까? 요청 자체가 비동기 적으로 전송되는 것 외에도 검색은 여전히 ​​동 기적입니까?
bryanph

3
나를 대신 from requests import async하여 교체 import grequests as async했습니다.
마틴 토마

80

async이제 독립 모듈 grequests입니다.

여기를 참조하십시오 : https://github.com/kennethreitz/grequests

그리고 거기에 : 파이썬을 통해 여러 HTTP 요청을 보내는 이상적인 방법은 무엇입니까?

설치:

$ pip install grequests

용법:

스택을 빌드하십시오.

import grequests

urls = [
    'http://www.heroku.com',
    'http://tablib.org',
    'http://httpbin.org',
    'http://python-requests.org',
    'http://kennethreitz.com'
]

rs = (grequests.get(u) for u in urls)

스택을 보내

grequests.map(rs)

결과는 다음과 같습니다

[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>]

grequests는 동시 요청에 대한 제한을 설정하지 않는 것 같습니다 (예 : 여러 요청이 동일한 서버로 전송되는 경우).


11
동시 요청에 대한 제한과 관련하여 map () / imap ()을 실행할 때 풀 크기를 지정할 수 있습니다. 즉, grequests.map (rs, size = 20)으로 20 개의 동시 잡을 수 있습니다.
신디사이저 패턴

1
현재로서는 python3를 지원하지 않습니다 (gevent는 py3.4에서 v2.6을 빌드하지 못함).
saarp

1
비동기 부분을 잘 이해하지 못합니다. 내가 해주면 results = grequests.map(rs)다음은이 라인 이후의 코드는 블록을, 나는 비동기 효과를 볼 수 있습니까?
Allan Ruin

47

나는 request-futuresgrequests를 테스트 했습니다 . Grequests는 빠르지 만 원숭이 패치 및 종속성과 관련된 추가 문제가 발생합니다. requests-futures는 grequest보다 몇 배 느립니다. 나는 내 자신을 작성하고 간단하게 요청을 ThreadPoolExecutor에 래핑하기로 결정했으며 그 요청 은 거의 빠르지 만 외부 종속성은 없었습니다.

import requests
import concurrent.futures

def get_urls():
    return ["url1","url2"]

def load_url(url, timeout):
    return requests.get(url, timeout = timeout)

with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:

    future_to_url = {executor.submit(load_url, url, 10): url for url in     get_urls()}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            resp_err = resp_err + 1
        else:
            resp_ok = resp_ok + 1

여기서 어떤 유형의 예외가 가능합니까?
Slow Harry

requests.exceptions.Timeout
Hodza

2
죄송합니다. 귀하의 질문을 이해하지 못합니다. 여러 스레드에서 단일 URL 만 사용 하시겠습니까? 단 한 건의 DDoS 공격))
Hodza

1
이 답변이 왜 그렇게 많은지지를 받았는지 이해할 수 없습니다. OP 질문은 비동기 요청에 관한 것입니다. ThreadPoolExecutor는 스레드를 실행합니다. 예, 여러 스레드로 요청을 할 수는 있지만 비동기 프로그램이 될 수 없으므로 원래 질문에 대한 답변이 될 수 있습니까?
nagylzs

1
실제로, URL을 병렬로로드하는 방법에 대한 질문이었습니다. 그리고 예 스레드 풀 실행기가 가장 좋은 옵션은 아니며 비동기 io를 사용하는 것이 좋지만 Python에서 잘 작동합니다. 스레드를 비동기에 사용할 수없는 이유를 이해하지 못합니까? CPU 바운드 작업을 비동기 적으로 실행해야하는 경우 어떻게합니까?
Hodza

29

어쩌면 요청-선물은 또 다른 선택이다.

from requests_futures.sessions import FuturesSession

session = FuturesSession()
# first request is started in background
future_one = session.get('http://httpbin.org/get')
# second requests is started immediately
future_two = session.get('http://httpbin.org/get?foo=bar')
# wait for the first request to complete, if it hasn't already
response_one = future_one.result()
print('response one status: {0}'.format(response_one.status_code))
print(response_one.content)
# wait for the second request to complete, if it hasn't already
response_two = future_two.result()
print('response two status: {0}'.format(response_two.status_code))
print(response_two.content)

사무실 문서 에도 권장됩니다 . gevent를 포함하고 싶지 않다면 좋은 것입니다.


1
가장 쉬운 솔루션 중 하나입니다. 동시 요청 수는 매개 변수 max_workers을 정의하여 증가시킬 수있다
호세 Cherian

1
이 스케일의 예제를 보는 것이 좋으므로 루프 오버하기 위해 항목 당 하나의 변수 이름을 사용하지 않습니다.
user1717828

요청 당 하나의 스레드를 갖는 것은 자원 낭비입니다! 예를 들어 500 개의 요청을 동시에 수행 할 수 없으면 CPU가 종료됩니다. 이것은 좋은 해결책으로 간주되어서는 안됩니다.
Corneliu Maftuleac

@CorneliuMaftuleac 좋은 지적입니다. 스레드 사용과 관련하여 반드시주의해야하며 라이브러리는 스레딩 풀 또는 처리 풀을 활성화하는 옵션을 제공합니다. ThreadPoolExecutor(max_workers=10)
Dreampuf

@Dreampuf 처리 풀 더 나쁘다고 생각합니까?
Corneliu Maftuleac

12

게시 된 대부분의 답변에 많은 문제가 있습니다. 제한된 기능으로 포팅 된 더 이상 사용되지 않는 라이브러리를 사용하거나 요청 실행에 너무 많은 마술을 제공하여 오류 처리가 어렵습니다. 위의 카테고리 중 하나에 속하지 않으면 타사 라이브러리이거나 더 이상 사용되지 않습니다.

일부 솔루션은 순수하게 http 요청에서 정상적으로 작동하지만 솔루션은 다른 종류의 요청에 대해서는 부족합니다. 여기에는 고도로 맞춤화 된 솔루션이 필요하지 않습니다.

파이썬 내장 라이브러리를 사용하면 asyncio모든 유형의 비동기 요청을 수행하기에 충분할뿐만 아니라 복잡하고 사용 사례 별 오류 처리에 충분한 유동성을 제공 할 수 있습니다.

import asyncio

loop = asyncio.get_event_loop()

def do_thing(params):
    async def get_rpc_info_and_do_chores(id):
        # do things
        response = perform_grpc_call(id)
        do_chores(response)

    async def get_httpapi_info_and_do_chores(id):
        # do things
        response = requests.get(URL)
        do_chores(response)

    async_tasks = []
    for element in list(params.list_of_things):
       async_tasks.append(loop.create_task(get_chan_info_and_do_chores(id)))
       async_tasks.append(loop.create_task(get_httpapi_info_and_do_chores(ch_id)))

    loop.run_until_complete(asyncio.gather(*async_tasks))

작동 방식은 간단합니다. 비동기 적으로 발생하는 일련의 작업을 만든 다음 해당 작업을 실행하고 완료되면 종료하도록 루프를 요청합니다. 추가 라이브러리는 유지 관리 부족, 기능 부족이 필요하지 않습니다.


2
올바르게 이해하면 GRPC 및 HTTP 호출을 수행하는 동안 이벤트 루프가 차단됩니까? 이러한 통화가 완료되는 데 몇 초가 걸리면 전체 이벤트 루프가 몇 초 동안 차단됩니까? 이를 피하려면 GRPC 또는 HTTP 라이브러리 인을 사용해야 async합니다. 그런 다음 예를 들어 할 수 있습니다 await response = requests.get(URL). 아니?
코더 Nr 23

불행히도이 작업을 시도 할 때 래퍼를 만드는 것이 requestsURL 목록을 동기식으로 호출하는 것보다 훨씬 빠릅니다 (어떤 경우에는 느리다). 예를 들어, 위의 전략을 사용하여 10 번 응답하는 데 3 초가 걸리는 엔드 포인트를 요청하는 데 약 30 초가 소요됩니다. 진정한 async성능 을 원한다면 과 같은 것을 사용해야합니다 aiohttp.
DragonBobZ

@DragonBobZ 제 경우에는 ~ 40 %의 시간 단축을 보았습니다. 주요 이점은 다음 전화를 기다리는 동안 필요한 집안일을 수행 할 수 있다는 것입니다. 내 데이터 세트에서 수백 건의 호출을 수행했기 때문에 스케일도 고려할 수 있습니다.
arshbot

@ CoderNr23 누군가이 문제를 해결할 수는 있지만 iirc는 해당 구문을 사용하여 작업을 실행하는 것이 기본적으로 동기됩니다. 파이썬에서는 시작과 같이 실행될 동기 실행 트리를 패키징하는 것뿐입니다 run_until_complete. 스레드 모듈을 사용하지 않으면 OS 계층에 비동기를 위임합니다. 자세한 내용은 파이썬에서 GIL 문제를 읽어보십시오
arshbot

8

나는 이것이 한동안 폐쇄되었다는 것을 알고 있지만 요청 라이브러리에 구축 된 다른 비동기 솔루션을 홍보하는 것이 유용 할 수 있다고 생각했습니다.

list_of_requests = ['http://moop.com', 'http://doop.com', ...]

from simple_requests import Requests
for response in Requests().swarm(list_of_requests):
    print response.content

문서는 다음과 같습니다. http://pythonhosted.org/simple-requests/


@YSY 문제를 게시하십시오 : github.com/ctheiss/simple-requests/issues ; 나는 문자 그대로이 라이브러리를 하루에 수천 번 사용합니다.
Monkey Boson

보스턴, 404/500 오류를 어떻게 처리합니까? https URL은 어떻습니까? 수천 개의 URL을 지원하는 스니핑에 감사드립니다. 예를 붙여 주시겠습니까? 감사합니다
YSY

@YSY 기본적으로 404/500 오류는 예외를 발생시킵니다. 이 동작은 무시 될 수 있습니다 ( pythonhosted.org/simple-requests/… 참조 ). HTTPS URL은 gevent에 의존하기 때문에 까다 롭습니다. 현재 gevent에 대한 버그가 높습니다 ( github.com/gevent/gevent/issues/477 ). 이 실행할 수있는 티켓 심이지만, 여전히 SNI 서버에 대한 경고가 발생합니다 (그러나이 됩니다 일). 저격에 관해서는, 나는 모든 사용이 회사에 있고 닫히는 것을 두려워합니다. 그러나 수십 개의 작업에 대해 수천 건의 요청을 실행합니다.
Monkey Boson

도서관은 상호 작용 측면에서 매끄럽게 보입니다. Python3 +를 사용할 수 있습니까? 죄송합니다. 언급이 없습니다.
아이작 필립

@Jethro는 기본적으로 Python 3에서는 기본 기술이 상당히 다르기 때문에 라이브러리를 완전히 다시 작성해야합니다. 현재 라이브러리는 "완료"상태이지만 Python 2에서만 작동합니다.
Monkey Boson

4
threads=list()

for requestURI in requests:
    t = Thread(target=self.openURL, args=(requestURI,))
    t.start()
    threads.append(t)

for thread in threads:
    thread.join()

...

def openURL(self, requestURI):
    o = urllib2.urlopen(requestURI, timeout = 600)
    o...

4
이것은 스레드에서 "정상적인"요청입니다. 구매가 주제를 벗어난 사례가 아닙니다.
Nick



2

사용할 수 있습니다 httpx.

import httpx

async def get_async(url):
    async with httpx.AsyncClient() as client:
        return await client.get(url)

urls = ["http://google.com", "http://wikipedia.org"]

# Note that you need an async context to use `await`.
await asyncio.gather(*map(get_async, urls))

기능적인 구문을 원한다면 gamla lib가 이것을로 습니다 get_async.

그럼 넌 할 수있어


await gamla.map(gamla.get_async(10), ["http://google.com", "http://wikipedia.org"])

10초 제한 시간입니다.

(면책 조항 : 나는 저자입니다)


그리고 respx조롱 / 테스트 :)

0

나는 파이썬에서 비동기 메소드를 사용하여 몇 가지를 시도했지만 비동기 프로그래밍을 위해 트위스트를 사용하는 것이 훨씬 더 운이 좋았습니다. 문제가 적으며 문서화가 잘되어 있습니다. 여기 당신이 꼬이려고하는 것에 simmilar 무언가의 링크가 있습니다.

http://pythonquirks.blogspot.com/2011/04/twisted-asynchronous-http-request.html


트위스트는 구식입니다. 대신 HTTPX를 사용하십시오.
AmirHossein
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.