2010-11-07 9 views
11

Ho codice come questo.Connessioni multiple (asincrone) con urllib2 o altra libreria 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) 

Vorrei fare due o tre richieste allo stesso tempo per accelerare questo. Posso usare urllib2 per questo, e come? Se non quale altra libreria dovrei usare? Grazie.

risposta

0

O si individua threads oppure use Twisted (which is asynchronous).

+3

librerie coroutine a base di avere i benefici di entrambi e più semplice di discussioni e contorti: gevent, eventlet, concorso –

9

Dai uno sguardo a gevent - una libreria di rete Python basata su coroutine che utilizza greenlet per fornire un'API sincrona di alto livello sul loop di eventi libevent.

Esempio:

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

magari usando multiprocessing e dividere si lavora su 2 processi o giù di lì.

Ecco un esempio (non è testato)

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 è la risposta giusta, non complessi cose stratificate come attorcigliate. Userei il threading piuttosto che il multiprocessing; il modulo multiprocessing basato sul processo è necessario solo per le attività legate alla CPU, non per quelle con I/O. –

10

È possibile utilizzare asincrona IO per fare questo.

requests + gevent = grequests

GRequests consente di utilizzare richieste con Gevent di effettuare richieste HTTP asincrone facilmente.

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

Puoi specificare come passare una funzione per elaborare la risposta? Docs non sembra menzionarlo – Overdrivr

+0

@Overdrivr Puoi usare http://docs.python-requests.org/en/master/user/advanced/#event-hooks esempio: 'grequests.get (u, hooks = dict (response = print_url)) 'oppure puoi usare' grequests.get (u, callback = print_url) ' – Chaker

1

So che questa domanda è un po 'vecchio, ma ho pensato che potrebbe essere utile per promuovere un'altra soluzione asincrona costruita sulla libreria richieste.

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 documentazione sono qui: http://pythonhosted.org/simple-requests/

4

è così, è il 2016 e abbiamo Python 3.4+ con built-in asyncio modulo per I/O asincrono. Possiamo utilizzare aiohttp come client HTTP per scaricare più URL in parallelo.

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) 

Fonte: copia-incollato da http://pawelmhm.github.io/asyncio/python/aiohttp/2016/04/22/asyncio-aiohttp.html

Problemi correlati