스터디/Python

Python 비동기 asyncio 사용기 + bs4(파싱)

Dalmangyi 2022. 9. 14.

비동기 파싱을 사용하는 이유

 

여러 url을 for문을 돌며 parsing을 하기엔 너무 오랜 시간이 걸립니다. 

(1방문->1파싱->2방문->2파싱->....n방문->n파싱)

 

 

모든 사이트의 응답이 빠르지 않기 때문이기도하고, parsing하는데 오랜시간이 걸려버립니다.

멀티로 동작할 수 있는 컴퓨터의 자원을 이용해서 이 시간을 줄일 수 있습니다. 

 

사이트에 방문하고 parsing하는 일을 1개의 작업(Task)으로 묶어놓고, 여러개의 작업을 동시에 처리하면 됩니다. 

(1방문->1파싱)

-> (2방문->2파싱)

....

-> (n방문->n파싱)

 

 

이러한 동시 작업은 thread, process가 아닌 asyncio(코루틴)를 이용해서 파싱을 해보려고 합니다. 

코루틴은 비동기(async) 함수와 실행(run), 기다리기(await) 를 대표로 사용합니다. 

 

 

 

 

 

 

0. 임포트

import asyncio
import aiohttp
from bs4 import BeautifulSoup

 

 

1. 이벤트 루프 만들기

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

새로운 이벤트 루프를 만들고, 시스템에서 사용하는 이벤트 루프로 등록합니다.

 

 
 

2. url 접근해서 내용을 가져오는 함수를 작성합니다.

async def get_text_from_url(url):  

    async with aiohttp.ClientSession() as sess:
        async with sess.get(url, headers={'user-agent': 'Mozilla/5.0'}) as res:
            res_html = await res.text()
            status = res.status
   
    if status != 200:
        return Response(-1, '추적에 실패하였습니다(-1)')


    result_soup = BeautifulSoup(res_html, 'lxml')
	contents = result_soup.select_one('body')
    
    return contents
 
코루틴으로 동시에 실행되는 함수를 만들기 위해, def 앞에 async를 입력합니다.
input/output이 될때 컴퓨터에서는 블럭킹 되기 때문에, 블럭이 안되는 aiohttp를 이용해서 사이트의 html을 가져옵니다. 
 
가져온 html은 beatifulsoap를 이용해서 파싱합니다. (*lxml을 이용하기 위해선 패키지를 따로 설치해야합니다)
 
 
 

3. 실행은 하지 않아요

futures = [asyncio.ensure_future(get_text_from_url(url)) for url in url_list]
group1 = asyncio.gather(*futures)​
async로 만들어진 함수를 asyncio.ensure_future함수를 통해서 future로 만들어 놓습니다. 
future는 아직 실행되지 않고, 실행을 암시하는 저수준의 어웨이터블(awaitable, await + able) 객체 입니다. 
asyncio.gather를 이용해서 futures 어레이를 그룹화 해줍니다.
 
 
 

4. 그룹을 모두 실행해 줍니다.

results1 = loop.run_until_complete(group1)
 
비동기 함수들을 모두 실행하고, 끝날때까지 기다렸다가, results1 변수에 결과를 저장합니다. 
 
 
 

5. 모든 비동기가 끝나면 loop를 닫아서 메모리에서 해지시켜줍니다.

loop.close()
 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글