2010-11-07 14 views
11

Tengo un código como este.¿Múltiples conexiones (asíncronas) con urllib2 u otra biblioteca 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) 

Me gustaría hacer dos o tres solicitudes al mismo tiempo para acelerar esto. ¿Puedo usar urllib2 para esto y cómo? Si no, ¿qué otra biblioteca debería usar? Gracias.

Respuesta

0
+3

bibliotecas basadas en co-rutina tener los beneficios de ambos y más simple que las discusiones y Twisted: GEvent, eventlet, concurrencia –

9

Eche un vistazo a gevent - una biblioteca de red Python basada en coroutine que usa greenlet para proporcionar una API síncrona de alto nivel en la parte superior del ciclo de evento libevent.

Ejemplo:

#!/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

tal vez usando multiprocessing y dividir a trabajar el 2 de proceso más o menos.

Aquí es un ejemplo (que no está probado)

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

Threading es la respuesta correcta, no cosas en capas complejas como Retorcido. Yo usaría threading en lugar de multiprocesamiento; el módulo de multiprocesamiento basado en procesos solo se necesita para tareas vinculadas a la CPU, no esta vinculada a E/S. –

10

Puede utilizar S asíncrona para hacer esto.

requests + gevent = grequests

GRequests le permite utilizar solicitudes con GEvent para realizar peticiones HTTP asíncronas fácilmente.

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

¿Podría detallar cómo pasar una función para procesar la respuesta? Los documentos no parecen mencionarlo – Overdrivr

+0

@Overdrivr Puede usar http://docs.python-requests.org/en/master/user/advanced/#event-hooks example: 'grequests.get (u, hooks = dict (response = print_url)) 'o puede usar' grequests.get (u, callback = print_url) ' – Chaker

1

Sé que esta pregunta es un poco viejo, pero pensé que podría ser útil para promover otra solución asincrónica basada en la biblioteca de solicitudes.

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 

La documentación está aquí: http://pythonhosted.org/simple-requests/

4

lo tanto, es de 2016 y tenemos Python 3.4+ con una función de asyncio módulo de E/S asíncrona. Podemos usar aiohttp como cliente HTTP para descargar varias URL en paralelo.

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) 

Fuente: copiar-pegar de http://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html

Cuestiones relacionadas