- 코드 개요
- 라이브러리 임포트 분석
- 비동기 함수 구조
- Playwright 브라우저 제어
- BeautifulSoup을 활용한 HTML 파싱
- asyncio.run() 실행 메커니즘
- 코드 실행 흐름 정리
1. 코드 개요
제시된 코드는 Playwright와 BeautifulSoup 라이브러리를 결합하여
네이버 웹사이트의 HTML 콘텐츠를 가져오는 파이썬 스크립트입니다.
이 코드는 비동기 프로그래밍 방식을 사용하여 웹 페이지를 로드하고,
그 내용을 파싱하는 과정을 보여줍니다.
전체 코드는 크게 세 부분으로 나눌 수 있습니다:
라이브러리 임포트, 비동기 스크래핑 함수 정의, 그리고 함수 실행 및 결과 출력입니다.
2. 라이브러리 임포트 분석
import asyncio
from playwright.async_api import async_playwright
from bs4 import BeautifulSoup
각 라이브러리의 역할
1. asyncio: 파이썬의 표준 라이브러리로, 비동기 프로그래밍을 지원합니다.
- 코루틴(coroutine)을 실행하고 관리하는 프레임워크를 제공합니다.
- 이벤트 루프를 통해 비동기 작업을 처리합니다.
2. playwright.async_api: 웹 브라우저 자동화를 위한 라이브러리입니다.
- `async_playwright` 모듈은 Playwright의 비동기 API를 제공합니다.
- 브라우저를 제어하고 웹 페이지와 상호작용할 수 있게 해줍니다.
3. BeautifulSoup: HTML 및 XML 파일을 파싱하기 위한 라이브러리입니다.
- HTML 구조를 탐색하고 데이터를 추출하는 데 사용됩니다.
- 복잡한 HTML 문서에서 원하는 요소를 쉽게 찾을 수 있게 해줍니다.
3. 비동기 함수 구조
async def scrape_naver_async():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
await page.goto("https://www.naver.com")
await page.wait_for_load_state("networkidle")
html_content = await page.content()
await browser.close()
soup = BeautifulSoup(html_content, 'html.parser')
return soup
함수 구조 분석
1. async def scrape_naver_async():
- `async` 키워드는 이 함수가 비동기 함수임을 선언합니다.
- 비동기 함수는 `await` 키워드를 사용하여 다른 비동기 작업이 완료될 때까지 기다릴 수 있습니다.
2. async with async_playwright() as p:
- 비동기 컨텍스트 매니저를 사용하여 Playwright 인스턴스를 생성합니다.
- 컨텍스트가 종료될 때 자동으로 리소스를 정리합니다.
- `p`는 Playwright 인스턴스를 참조하는 변수입니다.
비동기 함수는 일반 함수와 달리 즉시 결과를 반환하지 않고, 코루틴 객체를 반환합니다. 이 코루틴은 나중에 실행되어 결과를 생성합니다. 비동기 함수 내에서는
await
키워드를 사용하여 다른 비동기 작업이 완료될 때까지 기다릴 수 있으며, 이 때 제어권은 이벤트 루프로 반환되어 다른 작업을 수행할 수 있게 됩니다.
4. Playwright 브라우저 제어
브라우저 시작 및 페이지 생성
browser = await p.chromium.launch(headless=True)
page = await browser.new_page()
1. browser = await p.chromium.launch(headless=True):
- `p.chromium.launch()`는 크로미움 브라우저를 시작하는 비동기 함수입니다.
- `headless=True` 매개변수는 브라우저를 화면에 표시하지 않고 백그라운드에서 실행하도록 지정합니다.
- `await` 키워드는 브라우저가 완전히 시작될 때까지 기다립니다.
2. page = await browser.new_page():
- 새로운 브라우저 페이지(탭)를 생성합니다.
- 이 페이지 객체를 통해 웹 페이지와 상호작용할 수 있습니다.
페이지 탐색 및 대기
await page.goto("https://www.naver.com")
await page.wait_for_load_state("networkidle")
1. await page.goto("https://www.naver.com"):
- 지정된 URL(네이버 홈페이지)로 페이지를 이동시킵니다.
- `await`는 페이지 이동이 완료될 때까지 기다립니다.
2. await page.wait_for_load_state("networkidle"):
- 네트워크 활동이 최소 500ms 동안 없을 때까지 기다립니다.
- 이는 페이지의 모든 리소스(이미지, 스크립트 등)가 로드되었음을 의미합니다.
- 동적 콘텐츠가 완전히 로드되도록 보장하는 중요한 단계입니다.
콘텐츠 추출 및 리소스 정리
html_content = await page.content()
await browser.close()
1. html_content = await page.content():
- 현재 페이지의 HTML 콘텐츠를 문자열로 가져옵니다.
- 이 HTML에는 JavaScript에 의해 동적으로 생성된 콘텐츠도 포함됩니다.
2. await browser.close():
- 브라우저 인스턴스를 종료하고 관련 리소스를 해제합니다.
- 메모리 누수를 방지하기 위한 중요한 단계입니다.
5. BeautifulSoup을 활용한 HTML 파싱
soup = BeautifulSoup(html_content, 'html.parser')
return soup
BeautifulSoup 객체 생성
1. soup = BeautifulSoup(html_content, 'html.parser'):
- `html_content` 문자열을 파싱하여 BeautifulSoup 객체를 생성합니다.
- 'html.parser'는 파이썬의 내장 HTML 파서를 사용하도록 지정합니다.
- BeautifulSoup 객체는 HTML 문서의 구조화된 표현을 제공합니다.
2. return soup:
- 생성된 BeautifulSoup 객체를 함수의 결과로 반환합니다.
- 이 객체를 통해 HTML 요소를 탐색하고 데이터를 추출할 수 있습니다.
Playwright는 동적 웹 페이지를 로드하고 JavaScript가 실행된 후의 HTML을 가져오는 데 뛰어나지만, HTML 파싱에는 특화되어 있지 않습니다. 반면 BeautifulSoup은 HTML 파싱과 데이터 추출에 최적화되어 있습니다. 두 라이브러리를 함께 사용함으로써, 동적 웹 페이지에서도 효과적으로 데이터를 추출할 수 있습니다.
6. asyncio.run() 실행 메커니즘
soup = asyncio.run(scrape_naver_async())
# 보기 좋게 정제된 HTML 출력
print(soup.prettify())
비동기 함수 실행
1. soup = asyncio.run(scrape_naver_async()):
- `asyncio.run()`은 비동기 함수를 실행하기 위한 최상위 레벨 함수입니다.
- 새로운 이벤트 루프를 생성하고, 지정된 코루틴(`scrape_naver_async()`)을 실행한 후, 이벤트 루프를 닫습니다.
- 코루틴의 실행이 완료되면 그 결과(BeautifulSoup 객체)를 반환합니다.
2. print(soup.prettify()):
- BeautifulSoup의 `prettify()` 메서드는 HTML을 들여쓰기가 적용된 가독성 좋은 형태로 변환합니다.
- 변환된 HTML을 콘솔에 출력합니다.
7. 코드 실행 흐름 정리
전체 코드의 실행 흐름을 단계별로 정리하면 다음과 같습니다:
실행 순서
1. asyncio.run() 함수가 호출되어 이벤트 루프를 생성하고 `scrape_naver_async()` 코루틴을 실행합니다.
2. async_playwright() 컨텍스트 매니저가 Playwright 인스턴스를 초기화합니다.
3. p.chromium.launch() 함수가 크로미움 브라우저를 헤드리스 모드로 시작합니다.
4. browser.new_page() 함수가 새 브라우저 페이지를 생성합니다.
5. page.goto() 함수가 네이버 홈페이지로 이동합니다.
6. page.wait_for_load_state() 함수가 네트워크 활동이 안정화될 때까지 기다립니다.
7. page.content() 함수가 현재 페이지의 HTML 콘텐츠를 가져옵니다.
8. browser.close() 함수가 브라우저를 종료합니다.
9. BeautifulSoup 객체가 HTML 콘텐츠를 파싱합니다.
10. 함수가 BeautifulSoup 객체를 반환하고, 이 객체가 `soup` 변수에 할당됩니다.
11. soup.prettify() 메서드가 정제된 HTML을 생성하고, 이를 콘솔에 출력합니다.
- 비동기 실행: 코드는 비동기 방식으로 실행되어 I/O 작업(웹 페이지 로딩 등) 중에 블로킹되지 않습니다.
- 헤드리스 브라우저: 시각적 인터페이스 없이 백그라운드에서 브라우저를 실행합니다.
- 네트워크 대기: 'networkidle' 상태를 기다림으로써 동적 콘텐츠가 완전히 로드되도록 보장합니다.
- 리소스 관리: 컨텍스트 매니저와 명시적인 브라우저 종료를 통해 리소스를 적절히 관리합니다.
- 도구 조합: Playwright와 BeautifulSoup의 장점을 결합하여 동적 웹 페이지에서 데이터를 효과적으로 추출합니다.
이 코드는 비동기 프로그래밍,
웹 브라우저 자동화,
HTML 파싱의 세 가지 핵심 개념을 결합하여
네이버 웹사이트의 HTML을 가져오는 효율적인 방법을 보여줍니다.
특히 JavaScript로 동적으로 생성되는 콘텐츠를 포함한 완전한 HTML을 얻을 수 있다는 점이 이 접근 방식의 큰 장점입니다.
[ 파이썬 관련 블로그 글 목록 ]
파이썬(Python) 블로그 목록
'PYTHON 웹 스크래핑' 카테고리의 다른 글
Playwright로 구현하는 YouTube 무한 스크롤 자동화 (2) | 2025.06.30 |
---|---|
Playwright를 활용한 브라우저 최대화 실행 방법: 동기식과 비동기식 접근법 (1) | 2025.06.26 |
통계청 SGIS API 사용하기 두번째 - 인구통계 데이터 조회 (1) | 2025.06.24 |
통계청 SGIS API 사용하기 첫번째 - AccessToken 발급 방법 (0) | 2025.06.23 |
공공데이터 포털 API 활용 가이드: 실시간 데이터로 서비스 개발하기 (1) | 2025.06.19 |