2016-11-23 1 views
2

J'ai un morceau de code lié aux E/S qui fait essentiellement du scrap web pour un projet de recherche.Comment convertir un code qui utilise des générateurs en asyncio

Le code a commencé impératif, puis est devenu liste-compréhensions qui maintenant la plupart du temps transformés en générateurs:

if __name__ == '__main__': 
    while True: 
     with suppress(Exception): 
      page = requests.get(baseUrl).content 
     urls = (baseUrl + link['href'] for link in BeautifulSoup(page,'html.parser').select('.tournament a')) 
     resources = (scrape_host(url) for url in urls) 
     keywords = ((keywords_for_resource(referer, site_id), rid) for 
          referer, site_id, rid in resources) 
     output = (scrape(years, animals) for years, animals in keywords) 
     responses = (post_data_with_exception_handling(list(data)) for data in output) 
     for response in responses: 
      print(response.status_code) 

Ce genre de code va très bien dans ma tête, et comme il est basé sur des générateurs, sans stocker l'état beaucoup , je me suis dit que je pourrais assez facilement transformer cela en asyncio code basé:

async def fetch(session, url): 
    with async_timeout.timeout(10): 
     async with session.get(url) as response: 
      return await response.text()    
async def main(loop): 
    async with aiohttp.ClientSession(loop=loop) as session: 
     page = await fetch(session,baseUrl) 
     urls = (baseUrl + link['href'] for link in BeautifulSoup(page,'html.parser').select('.tournament a')) 
     subpages = (await fetch(session,url) for url in urls) 

Cependant en Python 3.5 ce juste retourne un Syntax error puisque l'expression await n'est pas admis à l'intérieur co Mprehensions.

Python 3.6 promet d'implémenter asynchronous generators in pep 530.

Cette fonctionnalité me permettra-t-elle de convertir facilement du code basé sur un générateur en code asyncio ou une réécriture complète est-elle nécessaire?

+0

python 3.6 a été publié :-) – Udi

Répondre

0

asyncio.as_completed() pourrait être une meilleure solution ici:

# pip install beautifulsoup4 aiohttp 
import asyncio 
from urllib.parse import urljoin 

import aiohttp 
import async_timeout 
from bs4 import BeautifulSoup 

BASE_URL = "http://www.thewebsiteyouarescraping.com/" 
SELECTOR = ".tournament a" 

async def fetch(session, url): 
    with async_timeout.timeout(10): 
     async with session.get(url) as response: 
      return url, await response.text() 


async def main(base_url, selector, loop): 
    async with aiohttp.ClientSession(loop=loop) as session: 
     _, page = await fetch(session, base_url) 
     urls = (urljoin(base_url, link['href']) for link in 
       BeautifulSoup(page, 'html.parser').select(selector)) 
     tasks = {fetch(session, url): url for url in urls} 
     for fut in asyncio.as_completed(tasks, loop=loop): 
      process(*await fut) 
     # Compare with: 
     # for fut in tasks: 
     #  process(*await fut) 


def process(url, page): 
    print(url, len(page)) 


loop = asyncio.get_event_loop() 
loop.run_until_complete(main(BASE_URL, SELECTOR, loop)) 
loop.close()