aiohttp 基於異步庫的請求替代品

asyncio能夠實現單線程的併發IO操做,若是僅用在客戶端,發揮的威力並不大,把asyncio用在服務端,例如WEB服務器,因爲HTTP鏈接就是IO操做,所以能夠用單線程+coroutine實現多用戶的高併發支持。html

asyncio實現了TCP、UDP、SSL等協議,aiohttp則是基於asyncio實現的HTTP框架。json

首先咱們定義一個協同程序用來獲取頁面,並打印出來。咱們使用asyncio.coroutine將一個方法裝飾成一個協同程序,aiohttp.request是一個協同程序,因此他是一個可讀方法。服務器

@asyncio.coroutine
def print_page(url):
    response = yield from aiohttp.request('GET', url)
    #close斷開的是網頁與服務器的Connection:keep-alive    
    body = yield from response.read_and_close(dcode=True)
    print(body)

如你所見,咱們可使用yield from從另外一個協程中調用一個協程。爲了從同步代碼中調用一個協程,咱們須要一個時間循環,咱們能夠經過asyncio.get_event_loop()獲得一個標準的時間循環,以後使用它的loop.run_until_complete()方法啓動協程,因此,爲了使以前的協程運行咱們只須要作:cookie

loop = asyncio.get_evemnt_loop()
loop.run_until_complete(print_page('http://xxxxx'))

一個有用的方法是asyncio.wait,經過它能夠獲取一個協程的列表,同時返回一個將它們包括在內的單獨的協程,因此咱們能夠這樣寫:session

loop.run_until_complete(asyncio.wait([print_page(url) for url in url_list]))

數據抓取

如今咱們已經知道如何作異步請求,所以咱們能夠寫一個數據抓取器,咱們僅僅還須要一些工具來解析HTML併發

import aiohttp
import asyncio

def get_content(html):
    '''
    處理HTML獲取所需信息
    '''
async def print_magnet(page):
    headers = {'key':'value'}
    cookies = {'cookies_are': 'working'}
    url = 'http://www.cnbligs.com/#p{}'.format(page)
    async with aiohttp.ClientSession(cookies=cookies) as session:
        async with session.get(url, headers=headers) as response:
            content = get_content(await response.text())
            print(await response.text())

loop = asyncio.get_event_loop()
tasks = asyncio.wait([print_magnet(page) for page in range(10)])
loop.run_until_complete(tasks)

爲了不爬蟲一次性的產生過多的請求致使帳號/IP被封能夠考慮使Semaphore控制同時的併發量,與咱們熟悉的threading模塊中的Semaphore(信號量)用法相似。框架

import aiohttp
impoer asyncio

NUMBERS = range(12)
URL = 'http://httpbin.org/get?a={}'
sema = asyncio.Semaphore(3)

async def fetch_async(a):
    async with aiohttp.request('GET', URL.format(a)) as res:
        data = await r.json()
    return data['args']['a']
    
async def print_result(a):
    with (await sema):
        r = await fetch_async(a)
        print('fetch({}) = {}'.foemat(a, r))
        

loop = asyncio.get_event_loop()
f = asyncio.wait([print_result(num) for num in NUMBERS])
loop.run_until_complete(f)

能夠到後臺看到併發受到了信號量的限制,同一時刻基本只處理三個請求。異步

相關文章
相關標籤/搜索