2010-11-07 2 views
11

У меня есть код вроде этого.Несколько (асинхронных) соединений с urllib2 или другой http-библиотекой?

for p in range(1,1000): 
    result = False 
    while result is False: 
     ret = urllib2.Request('http://server/?'+str(p)) 
     try: 
      result = process(urllib2.urlopen(ret).read()) 
     except (urllib2.HTTPError, urllib2.URLError): 
      pass 
    results.append(result) 

Я хотел бы сделать два или три запроса одновременно, чтобы ускорить это. Могу ли я использовать urllib2 для этого и как? Если нет, какую другую библиотеку я должен использовать? Благодарю.

ответ

0

Либо вы выясните threads, либо вы use Twisted (which is asynchronous).

+3

сопрограмм на основе библиотек имеют преимущество как и проще, чем потоки и Twisted: GEvent, eventlet, Совпадение –

9

Посмотрите на gevent - сетевую библиотеку Python на основе сопрограмм, которая использует зеленую оболочку для предоставления высокоуровневого синхронного API поверх цикла событий libevent.

Пример:

#!/usr/bin/python 
# Copyright (c) 2009 Denis Bilenko. See LICENSE for details. 

"""Spawn multiple workers and wait for them to complete""" 

urls = ['http://www.google.com', 'http://www.yandex.ru', 'http://www.python.org'] 

import gevent 
from gevent import monkey 

# patches stdlib (including socket and ssl modules) to cooperate with other greenlets 
monkey.patch_all() 

import urllib2 


def print_head(url): 
    print 'Starting %s' % url 
    data = urllib2.urlopen(url).read() 
    print '%s: %s bytes: %r' % (url, len(data), data[:50]) 

jobs = [gevent.spawn(print_head, url) for url in urls] 

gevent.joinall(jobs) 
0

возможно с помощью multiprocessing и раздели вы работаете на 2 процесса или около того.

Вот пример (это не тестировалось)

import multiprocessing 
import Queue 
import urllib2 


NUM_PROCESS = 2 
NUM_URL = 1000 


class DownloadProcess(multiprocessing.Process): 
    """Download Process """ 

    def __init__(self, urls_queue, result_queue): 

     multiprocessing.Process.__init__(self) 

     self.urls = urls_queue 
     self.result = result_queue 

    def run(self): 
     while True: 

      try: 
       url = self.urls.get_nowait() 
      except Queue.Empty: 
       break 

      ret = urllib2.Request(url) 
      res = urllib2.urlopen(ret) 

      try: 
       result = res.read() 
      except (urllib2.HTTPError, urllib2.URLError): 
        pass 

      self.result.put(result) 


def main(): 

    main_url = 'http://server/?%s' 

    urls_queue = multiprocessing.Queue() 
    for p in range(1, NUM_URL): 
     urls_queue.put(main_url % p) 

    result_queue = multiprocessing.Queue() 

    for i in range(NUM_PROCESS): 
     download = DownloadProcess(urls_queue, result_queue) 
     download.start() 

    results = [] 
    while result_queue: 
     result = result_queue.get() 
     results.append(result) 

    return results 

if __name__ == "__main__": 
    results = main() 

    for res in results: 
     print(res) 
+0

Резьбонарезные правильный ответ, а не сложные слоистые вещи, как Витая. Я бы использовал потоки, а не многопроцессорную обработку; многопроцессорный модуль на основе процесса необходим только для задач с привязкой к ЦП, а не для связанного с ним ввода-вывода. –

10

Вы можете использовать асинхронный IO, чтобы сделать это.

requests + gevent = grequests

GRequests позволяет использовать запросы с GEvent делать асинхронные HTTP запросы легко.

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

Не могли бы вы подробно описать, как передать функцию для обработки ответа? Документы, похоже, не упоминают его. – Overdrivr

+0

@Overdrivr. Вы можете использовать http://docs.python-requests.org/en/master/user/advanced/#event-hooks пример: 'grequests.get (u, hooks = dict (response = print_url)) 'или вы можете использовать' grequests.get (u, callback = print_url) ' – Chaker

1

Я знаю, что этот вопрос немного старый, но я думал, что это может быть полезным для продвижения другого асинхронного решения, построенное на библиотеке запросов.

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/

4

Таким образом, это 2016 и у нас есть Python 3.4+ со встроенным asyncio модуля для асинхронного ввода/вывода. Мы можем использовать aiohttp в качестве HTTP-клиента для одновременного скачивания нескольких URL-адресов.

import asyncio 
from aiohttp import ClientSession 

async def fetch(url): 
    async with ClientSession() as session: 
     async with session.get(url) as response: 
      return await response.read() 

async def run(loop, r): 
    url = "http://localhost:8080/{}" 
    tasks = [] 
    for i in range(r): 
     task = asyncio.ensure_future(fetch(url.format(i))) 
     tasks.append(task) 

    responses = await asyncio.gather(*tasks) 
    # you now have all response bodies in this variable 
    print(responses) 

loop = asyncio.get_event_loop() 
future = asyncio.ensure_future(run(loop, 4)) 
loop.run_until_complete(future) 

Источник: копия-вставили из http://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html