비동기를 while로 반복하는 방법 문의
1273
작성한 질문수 1
안녕하세요
알려주신 코드를 10개씩 비동기로 묶어서 while로 돌리고 싶은데 잘 안되네요
아래와 같은 코드로 했을 때 얼핏 잘 되는 것 같지만
다른 티스토리 블로그로 바꿔서 해보면 중복 데이터가 발생합니다
비동기를 while 안에 넣어서 써도 되는건지 알고 싶습니다
from bs4 import BeautifulSoup
import aiohttp
import asyncio
async def fetch(session, url, i):
async with session.get(url) as response:
html = await response.text()
soup = BeautifulSoup(html, "html.parser")
tag = soup.find("p", class_="txt_thumb") # 첫번째 글제목만
print(tag.text)
async def main(jump):
BASE_URL = "https://bjpublic.tistory.com/category/%EC%A0%84%EC%B2%B4%20%EC%B6%9C%EA%B0%84%20%EB%8F%84%EC%84%9C"
urls = [f"{BASE_URL}?page={i}" for i in range(j + 1, j + 11)]
async with aiohttp.ClientSession() as session:
await asyncio.gather(*[fetch(session, url, i) for i, url in enumerate(urls)])
if __name__ == "__main__":
j = 0
while True:
asyncio.run(main(j))
print("--------")
j = j + 10
if j == 20:
break
답변 1
0
안녕하세요, 인프런 AI 인턴이에요.
비동기 함수를 while 루프 안에서 실행시키는 것은 가능합니다. 하지만 이 경우 비동기 함수가 모두 완료되기 전에 while 루프가 계속 실행되어 중복 데이터가 발생할 수도 있습니다. 이를 방지하기 위해서는 asyncio.Queue를 사용하는 것이 좋습니다.
아래는 asyncio.Queue를 사용하여 비동기 함수를 while 루프 안에서 실행시키는 예시 코드입니다.
import asyncio
from bs4 import BeautifulSoup
import aiohttp
async def fetch(session, url):
async with session.get(url) as response:
html = await response.text()
soup = BeautifulSoup(html, "html.parser")
tag = soup.find("p", class_="txt_thumb")
return tag.text
async def worker(queue):
async with aiohttp.ClientSession() as session:
while True:
url = await queue.get()
if url is None:
break
result = await fetch(session, url)
print(result)
queue.task_done()
async def main():
BASE_URL = "https://bjpublic.tistory.com/category/%EC%A0%84%EC%B2%B4%20%EC%B6%9C%EA%B0%84%20%EB%8F%84%EC%84%9C"
queue = asyncio.Queue()
urls = [f"{BASE_URL}?page={i}" for i in range(1, 21)]
for url in urls:
queue.put_nowait(url)
workers = [asyncio.create_task(worker(queue)) for _ in range(10)]
await queue.join()
for _ in range(10):
queue.put_nowait(None)
await asyncio.gather(*workers)
if __name__ == "__main__":
asyncio.run(main())
위 코드는 크게 worker 함수와 main 함수로 나눌 수 있습니다. worker 함수는 비동기적으로 실행할 함수(fetch)를 실행하고 결과를 출력하는 역할을 합니다. main 함수는 worker를 10개 생성하여 큐에 있는 URL을 worker들이 가져가며 비동기적으로 fetch 함수를 실행합니다.
크게 두 가지만 수정을 하면 대부분의 문제가 해결됩니다. BASE_URL를 %20(공백)으로 변경해주시고 while문 내부에 있는 조건문의 비교상수를 30으로 변경해주세요. 그러면 1페이지부터 30페이지까지의 타이틀을 가져올 수 있습니다.
대규모 크롤링 시 동시 요청 수 제어 방법
0
94
2
AWS LighSail 접근 불가
0
134
1
강의상의 readme와 배포되어 있는 것이 다른 것 같아요
0
96
1
book_scraper.py 에서 import get_secret 관련 질문
0
100
1
ThreadPoolExecutor 중간에 멈추는 법
0
291
1
몽고Db 기초 질문
0
195
1
async await 문법 질문
0
237
1
멀티 스레딩 질문..
0
193
1
교안 제공은 안되나요?
0
227
1
TypeError: field Config is defined without type annotation
0
258
1
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
0
1709
1
jinja2templates
0
244
1
몽고DB 설정 관련 질문
0
242
1
비동기 함수를 동기적인 실행으로 만드는 부분 질문입니다
1
308
2
proxy 사용 질문
0
261
1
AWS Lightsail SSL handshake failed 오류 문의드립니다.
0
491
1
동시성과 병렬성
0
326
1
python select linter ? 오류
1
739
2
수업질문
1
352
1
response 객체에서 키값으로 조회 시 KeyError 발생
0
568
1
from config import get_secret 질문
0
386
1
파이썬 코루틴활용 영상 질문
0
279
1
가상환경 설정 질문
0
316
1
pydantic import error
0
1225
2





