python aiohttpを利用して非同期爬虫類を作る

4256 ワード

まず、一般的な方法で実装されている爬虫類、すなわち同期方法を見てみましょう.完全なPythonコードは以下の通りです.
同時方式でベストセラーになる図書情報を這い出す
import time
import requests
import pandas as pd
from bs4 import BeautifulSoup
'''
       ?Python     :821460695      ,          ,      !
'''
# table          
table = []

#     
def download(url):
    html = requests.get(url).text

    #   BeautifulSoup          HTML
    soup = BeautifulSoup(html, "lxml")
    #            
    book_list = soup.find('ul', class_="bang_list clearfix bang_list_mode")('li')

    for book in book_list:
        info = book.find_all('div')

        #           ,  ,   ,  ,   
        rank = info[0].text[0:-1]
        name = info[2].text
        comments = info[3].text.split(' ')[0]
        author = info[4].text
        date_and_publisher = info[5].text.split()
        publisher = date_and_publisher[1] if len(date_and_publisher) >= 2 else ''

        #               table 
        table.append([rank, name, comments, author, publisher])


#     
urls = ['http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-recent7-0-0-1-%d' % i for i in range(1, 26)]

#           
print('#' * 50)
t1 = time.time()  #     

for url in urls:
    download(url)

#  table   pandas  DataFrame    CSV     
df = pd.DataFrame(table, columns=['rank', 'name', 'comments', 'author', 'publisher'])
df.to_csv('E://douban/dangdang.csv', index=False)

t2 = time.time()  #     
print('      ,    :%s' % (t2 - t1))
print('#' * 50)

出力結果は次のとおりです.
##################################################
      ,    :23.522345542907715
##################################################

プログラムは23.5秒実行され、500冊の本の情報を取得しましたが、効率はまあまあです.
次にaiohttpで作成した非同期爬虫類の効率を見てみましょう.完全なソースコードは以下の通りです.
import time
import aiohttp
import asyncio
import pandas as pd
from bs4 import BeautifulSoup

# table          
table = []

#     (    )
async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text(encoding='gb18030')

#     
async def parser(html):
    
    #   BeautifulSoup          HTML
    soup = BeautifulSoup(html, "lxml")
    #            
    book_list = soup.find('ul', class_="bang_list clearfix bang_list_mode")('li')

    for book in book_list:
        
        info = book.find_all('div')

        #           ,  ,   ,  ,   
        rank = info[0].text[0:-1]
        name = info[2].text
        comments = info[3].text.split(' ')[0]
        author = info[4].text
        date_and_publisher = info[5].text.split()
        publisher = date_and_publisher[1] if len(date_and_publisher) >=2 else ''

        #               table 
        table.append([rank,name,comments,author,publisher])
        
#         
async def download(url):
    async with aiohttp.ClientSession() as session:
        html = await fetch(session, url)
        await parser(html)

#     
urls = ['http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-recent7-0-0-1-%d'%i for i in range(1,26)]

#           
print('#' * 50)
t1 = time.time() #     

#   asyncio      IO  
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(download(url)) for url in urls]
tasks = asyncio.gather(*tasks)
loop.run_until_complete(tasks)

#  table   pandas  DataFrame    CSV     
df = pd.DataFrame(table, columns=['rank','name','comments','author','publisher'])
df.to_csv('E://douban/dangdang.csv',index=False)
    
t2 = time.time() #     
print('  aiohttp,    :%s' % (t2 - t1))
print('#' * 50)

この爬虫類は従来の一般的な方法の爬虫類の考え方や処理方法とほぼ一致しているが,HTTPリクエストを処理する際にaiohttpモジュールを用い,ページを解析する際に関数がコヒーレントになりaysncioを再利用して同時処理を行うことで爬虫類の効率を向上させることは間違いない.実行結果は次のとおりです.
##################################################
  aiohttp,    :2.405137538909912
##################################################

以上から,同期法と非同期法で作製した爬虫類の効率は大きく異なることが分かるので,実際に爬虫類を作製する過程で,aysncio,aiohttpのような非同期モジュールを多く利用することも考えられる.また、aiohttpは3.5.3以降のPythonバージョンのみサポートされています.