웹 페이지 크롤링은 정적 HTML 데이터를 다루는 requests나 BeautifulSoup만으로도 충분한 경우가 많습니다. 하지만 JavaScript로 동적으로 렌더링되는 콘텐츠를 스크래핑하려면 추가적인 도구가 필요합니다. 여기서 Playwright가 강력한 해결책으로 등장합니다.
최근에 뉴스를 스크래핑할일이 있어서 파이썬으로 구현하려 하는데, request로 받아오니 이게뭐야! 암것도 못받아오더라고요? 급하게 print를 여기저기 찍어봤는데, requestbody가 아래처럼 javascript로 찍여있더라고요.
이렇게 javascript로 가져와서 브라우저에서 렌더하는 Client Side Render형 페이지들은 requests + bs4 라이브러리 만으로 안될때가 많죠 보통 많은 분들이 셀레니움을 많이들 사용하시는데, 브라우저를 빌리는 셀레니움의 방식 대신, 직접 브라우저를 사용하는 Playwright를 한번 사용해보시면 좋을 것 같습니다.
이 글에서는 Playwright를 사용하여 JavaScript로 로드된 콘텐츠를 크롤링하고, MSN 뉴스 기사를 저장하는 프로그램을 예제로 구현해보겠습니다.
Playwright란?
Playwright는 Microsoft에서 개발한 브라우저 자동화 도구로, 최신 브라우저의 모든 기능을 활용해 웹 애플리케이션과 상호작용할 수 있습니다. 특히 Selenium보다 간단하고 빠르며, 최신 브라우저와의 호환성이 뛰어납니다.
코드 구현
아래는 Playwright를 사용하여 MSN 뉴스 기사를 크롤링하고 내용을 마크다운 파일로 저장하는 프로그램입니다.
전체 코드
from playwright.sync_api import sync_playwright
import os
from datetime import datetime
class MSNNewsScraper:
def __init__(self):
self.browser = None
def scrape_article(self, url):
try:
if not url.startswith(('http://', 'https://')):
return "올바른 URL 형식이 아닙니다."
# Playwright를 사용하여 브라우저 실행
with sync_playwright() as p:
browser = p.chromium.launch(headless=False) # headless=True로 브라우저 숨김 실행
page = browser.new_page()
page.goto(url)
# JavaScript 렌더링이 완료될 때까지 대기
page.wait_for_timeout(3000) # 3초 대기 (필요 시 조정 가능)
# 제목 추출
title_element = page.query_selector('h1')
if not title_element:
return "기사 제목을 찾을 수 없습니다."
title = title_element.inner_text().strip()
# 본문 추출
article_body_element = page.query_selector('.article-body')
if not article_body_element:
return "기사 본문을 찾을 수 없습니다."
article_text = article_body_element.inner_text().strip()
if not article_text:
return "기사 본문이 비어있습니다."
# 브라우저 닫기
browser.close()
# 마크다운 형식으로 포맷팅
markdown_content = f"# {title}\n\n{article_text}"
return markdown_content
except Exception as e:
return f"오류 발생: {e}"
def save_to_markdown(self, content, url):
try:
# 저장할 디렉토리 생성
if not os.path.exists('articles'):
os.makedirs('articles')
# 파일명 생성 (현재 시간 기준)
filename = f"articles/article_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
# 마크다운 파일 저장
with open(filename, 'w', encoding='utf-8') as f:
f.write(f"원본 URL: {url}\n\n")
f.write(content)
return filename
except IOError as e:
return f"파일 저장 중 오류가 발생했습니다: {e}"
except Exception as e:
return f"예상치 못한 오류가 발생했습니다: {e}"
# 사용 방법
if __name__ == "__main__":
scraper = MSNNewsScraper()
try:
while True:
try:
news_url = input("MSN 뉴스 기사 URL을 입력하세요 (종료하려면 'q' 입력): ").strip()
if news_url.lower() == 'q':
print("프로그램을 종료합니다.")
break
if not news_url:
print("URL을 입력해주세요.")
continue
article_content = scraper.scrape_article(news_url)
if article_content and not article_content.startswith(("기사 본문을", "오류 발생")):
print("\n스크래핑 성공:\n", article_content)
saved_file = scraper.save_to_markdown(article_content, news_url)
print(f"\n기사가 저장되었습니다: {saved_file}")
else:
print(article_content)
except KeyboardInterrupt:
print("\n프로그램을 종료합니다.")
break
except Exception as e:
print(f"예상치 못한 오류가 발생했습니다: {e}")
except Exception as e:
print(f"프로그램 실행 중 오류 발생: {e}")
코드 설명
Playwright 초기화:Playwright는 Chromium, Firefox, WebKit을 지원하며, 여기서는 chromium을 사용합니다. headless=False를 설정하면 브라우저 창을 열어 동작을 확인할 수 있습니다.
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
페이지 로드:goto 메서드로 URL을 로드하고, JavaScript가 실행되기를 기다립니다.
page.goto(url)
page.wait_for_timeout(3000)
콘텐츠 추출:CSS 선택자를 이용해 제목과 본문을 추출합니다.
title_element = page.query_selector('h1')
article_body_element = page.query_selector('.article-body')
결과 저장:스크래핑된 기사를 마크다운형식으로 저장합니다.
filename = f"articles/article_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
with open(filename, 'w', encoding='utf-8') as f:
f.write(f"원본 URL: {url}\n\n")
f.write(content)
실행 방법
- Playwright 설치:
pip install playwright playwright install
- 스크립트 실행:
python msn\_scraper\_playwright.py
- 결과 확인:
- 프로그램이 실행되면 뉴스 기사 URL을 입력받습니다.
- 결과는 articles 폴더에 마크다운 파일로 저장됩니다.
Playwright는 JavaScript로 동적으로 로드된 웹 콘텐츠를 다룰 때 강력한 도구입니다. 이 글에서는 MSN 뉴스 기사를 예제로 Playwright를 사용해 JavaScript 렌더링 및 스크래핑을 구현했습니다.
JavaScript로 로드된 데이터를 크롤링해야 할 때, Playwright를 적극적으로 활용해보세요! 😊
'코딩' 카테고리의 다른 글
SchedAI 개발기 ep 7. Nextjs14. AISDK로 Chatgpt와 Gemini연동과 Stream응답 (0) | 2025.02.13 |
---|---|
SchedAI 개발기 ep 6. NextAuth v5 & GoogleAPI "Insufficient Permission"에러 (1) | 2025.01.19 |
Google ImageFx(Imagen3) 사용 후기 : 인물묘사 최강 이커머스 자동화 이메진3 (5) | 2025.01.18 |
SchedAI 개발기 ep 5. Nextjs14) GoogleCalendar에 Event 추가하기 (3) | 2025.01.18 |
SchedAI 개발기 ep 4. 오늘의 뻘짓 AccessToken, RefreshToken (0) | 2025.01.17 |