PYTHON 웹 스크래핑

Playwright와 BeautifulSoup을 활용한 네이버 웹 스크래핑 코드 분석

나루하루001 2025. 6. 27. 23:06
반응형
📑 목차
  1. 코드 개요
  2. 라이브러리 임포트 분석
  3. 비동기 함수 구조
  4. Playwright 브라우저 제어
  5. BeautifulSoup을 활용한 HTML 파싱
  6. asyncio.run() 실행 메커니즘
  7. 코드 실행 흐름 정리



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 요소를 탐색하고 데이터를 추출할 수 있습니다.

💡 BeautifulSoup과 Playwright의 조합
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) 블로그 목록
반응형