마이크로소프트 Playwright를 사용한 웹 브라우저 자동화

마이크로소프트 Playwright를 사용하여 웹 브라우저를 자동화하는 방법에 대한 안내입니다. Playwright 설치, 브라우저 켜기, 네이버 뉴스 크롤링 등을 살펴봅니다.

• 11,911
마이크로소프트 Playwright를 사용한 웹 브라우저 자동화
목차

0. Playwright란?

Playwright는 마이크로소프트에서 개발한 오픈 소스 라이브러리로, 웹 브라우저를 자동화하기 위한 것입니다.

본래 웹 스크래핑을 위해 설계된 것은 아니지만, 브라우저와 설정을 적절히 조합하면 이 영역에서 탁월한 성능을 발휘합니다.

Node.js와 Python 등 여러 언어에서 사용할 수 있으며, 현재 Chrome, Firefox, WebKit(모바일 Safari), Electron 등 여러 브라우저를 지원합니다.

해당 포스팅에서는 Python을 사용합니다.


1. Playwright 설치

playwright 패키지 설치:

pip install playwright

필수 브라우저 설치:

playwright install

2. 브라우저 켜기

테스트로 네이버 홈페이지에 접속해보도록 하겠습니다.

# 패키지 import
import asyncio # 비동기 라이브러리
from playwright.async_api import Playwright, async_playwright

async def run(playwright: Playwright) -> None:
    # headless=False => 브라우저 GUI 모드로 실행
    browser = await playwright.chromium.launch(headless=False) # 크롬 사용
    context = await browser.new_context()  # 새 콘텍스트 생성
    page = await context.new_page()  # 새 페이지 열기
    await page.goto("<https://naver.com/>")  # 네이버 홈페이지로 이동

    await context.close() # 콘텍스트 종료
    await browser.close() # 브라우저 종료

async def main() -> None:
    async with async_playwright() as playwright:
        await run(playwright)

asyncio.run(main()) # 실행

notion image

위 코드 실행 결과, 브라우저는 '시크릿 모드'로 띄워졌고 네이버 홈페이지에 정상적으로 접속한 것을 볼 수 있습니다.


3. 네이버 뉴스 크롤링

네이버 뉴스의 검색 결과 리스트를 크롤링 해보겠습니다.

3.1. URL 구하기

URL 규칙을 찾아 본 결과는 다음과 같습니다:

f"<https://search.naver.com/search.naver?where=news&query=>{인코딩된 검색어}&sort={정렬 기준}&field=0&pd=3&start={시작 페이지}"
  • 인코딩된 검색어: quote_plus 메서드를 사용하여 검색어를 넣습니다.

  • 정렬 옵션: {"관련도순": 0, "최신순": 1, "오래된순": 2}

  • 시작 페이지: {1페이지: 1, 2페이지: 11}과 같이 페이지 당 10씩 증가합니다.

따라서, 검색 URL은 다음과 같습니다:

# 정렬 옵션("관련도순")과 시작 페이지("1")은 고정
search_url = f"<https://search.naver.com/search.naver?where=news&query={quote_plus(keyword)}&sort=0&field=0&pd=3&start=1>"

notion image

해당 URL로 접속하게 되면 입력한 키워드에 대한 네이버 뉴스 검색 결과를 볼 수 있어요.

3.2. 수집할 데이터 + xpath

  • 기사 리스트: //*[@class='list_news']/li

  • 기사 URL: .//a[@class='news_tit']의 href 속성

  • 언론사: .//a[@class='info press']

  • 작성일자: .//div[@class='info_group']/span[@class='info']

  • 제목: .//a[@class='news_tit']의 title 속성

  • 본문 요약: .//div[@class='news_dsc']

3.3. 크롤링 방법

3.3.1. xpath로 요소 선택하기

playwright에서는 다음과 같이 xpath로 요소를 가져옵니다:

title_element = await page.query_selector("xpath=//a[@class='news_tit']")

await로 query_selector 메서드가 완료될 때까지 코드 실행을 일시 중지하게 됩니다.

인자로 xpath를 넣어주되, "xpath=" 뒤에 적어주도록 합니다.

3.3.2. 텍스트 가져오기

HTML 요소의 텍스트는 inner_text() 메서드를 사용하여 가져옵니다.

그러나 playwright에서는 비동기로 웹 요소에 접근하므로 query_selector().inner_text()와 같이 요소를 선택하면서 텍스트를 가져올 수 없습니다.

await로 앞의 작업이 완료될 때까지 기다리도록 합니다.

# HTML 요소 선택
title_element = await page.query_selector("xpath=//a[@class='news_tit']")
# 텍스트 가져오기
title_text = await title_element.inner_text()

3.3.3. 속성 가져오기

notion image

위와 같은 HTML 요소에서 속성을 가져오는 것은 get_attribute() 함수를 사용합니다.

마찬가지로 await을 사용합니다.

# HTML 요소 선택
title_element = await page.query_selector("xpath=//a[@class='news_tit']")
# href 속성 가져오기
news_link = await title_element.get_attribute("href")
# title 속성 가져오기
title = await title_element.get_attribute("title")

3.4. 크롤링 코드

3.4.1. 패키지 Import

import re
import asyncio
from pprint import pprint
from datetime import datetime, timedelta
from urllib.parse import quote_plus
from playwright.async_api import Playwright, async_playwright

3.4.2. 작성일자 변환 함수

일반적인 케이스:

notion image

문제의 케이스:

notion image

작성일자 xpath를 .//div[@class='info_group']/span[@class='info']로 설정했을 때, 위 사진의 "16면 TOP"과 "4시간 전"의 class가 'info'로 같아 "16면 TOP"을 가져오게 되어 에러가 발생하는 케이스가 존재했습니다.

때문에 시간에 "면"이 포함된다면 에러 메시지를 return하고, 그 외의 경우에는 날짜 형식을 %Y-%m-%d 형식으로 변환하는 함수를 추가했습니다.

async def convert_write_date(raw_date):
    now = datetime.now()

    if "면" in raw_date:
        return f"[error] raw_date is not datetime form: {raw_date}"

    if "분 전" in raw_date:
        minutes = re.findall('\\d+', raw_date)[0]
        article_date = now - timedelta(minutes=float(minutes))
    elif "시간 전" in raw_date:
        hours = re.findall('\\d+', raw_date)[0]
        article_date = now - timedelta(hours=float(hours))
    elif "일 전" in raw_date:
        days = re.findall('\\d+', raw_date)[0]
        article_date = now - timedelta(days=float(days))
    else:
        article_date = datetime.strptime(raw_date, "%Y-%m-%d")

    article_date = datetime.strftime(article_date, "%Y-%m-%d")

    return article_date

3.4.3. run 함수

async def run(playwright: Playwright) -> None:
    # 파라미터 설정
    keyword = input("Keyword: ")

    # 컨텍스트 및 브라우저 설정
    browser = await playwright.chromium.launch(headless=False)
    context = await browser.new_context()
    page = await context.new_page()

    # 브라우저 이동
    search_url = f"<https://search.naver.com/search.naver?where=news&query={quote_plus(keyword)}&sort=0&field=0&pd=3&start=1>"
    await page.goto(search_url)

    # 검색 결과 리스트
    articles = await page.query_selector_all("xpath=//*[@class='list_news']/li")

    # 각 리스트에 대해 반복
    for article in articles:
        article_info = {}

        # 기사 URL, 제목
        title_element = await article.query_selector("xpath=.//a[@class='news_tit']")
        article_info["URL"] = await title_element.get_attribute("href")
        article_info["제목"] = await title_element.get_attribute("title")

        # 언론사
        press_element = await article.query_selector("xpath=.//a[@class='info press']")
        raw_press = await press_element.inner_text()
        article_info["언론사"] = raw_press.replace("언론사 선정", "")

        # 작성일자
        date_element = await article.query_selector("xpath=.//div[@class='info_group']/span[@class='info']")
        raw_date = await date_element.inner_text()
        # raw_date에 에러 메시지가 있을 경우 HTML 재선택
        if "[error]" in await convert_write_date(raw_date):
            date_element_list = await article.query_selector_all("xpath=.//div[@class='info_group']/span[@class='info']")
            date_element = date_element_list[-1] # 마지막 요소
            raw_date = await date_element.inner_text()
            if "[error]" in await convert_write_date(raw_date):
                raise # 작성일자 찾지 못해 에러 발생
            article_info["작성일자"] = await convert_write_date(raw_date)
        else:
            article_info["작성일자"] = await convert_write_date(raw_date)

        # 본문 요약
        summary_element = await article.query_selector("xpath=.//div[@class='news_dsc']")
        summary = await summary_element.inner_text()
        article_info["본문 요약"] = summary

        print("=" * 70)
        pprint(article_info)

    # 컨텍스트 및 브라우저 종료
    await context.close()
    await browser.close()

3.4.4. run 함수 실행

async def main() -> None:
    async with async_playwright() as playwright:
        await run(playwright)


asyncio.run(main())

3.5. 수집 결과

다음은 "AI"로 검색한 네이버 뉴스 검색 결과입니다:

Keyword: AI
======================================================================
{'URL': '<http://www.newsis.com/view/?id=NISX20230908_0002443154&cID=10406&pID=13100>',
 '본문 요약': '정부가 군 장병과 대학생 등을 대상으로 국방 인공지능(AI) 기술 활용 대회를 진행한다. 청년들의 AI 기술 활용 능력을 '
          "통해 국방 분야 난제 해결에 나선다는 목표다. 과학기술정보통신부와 국방부는 '2023 제2회 국방...",
 '언론사': '뉴시스',
 '작성일자': '2023-09-08',
 '제목': "과기정통부, 국방부와 '국방 AI' 경진대회 개최…총 상금 8200만원"}
======================================================================
{'URL': '<https://www.mk.co.kr/article/10825161>',
 '본문 요약': '마이크로소프트가 인공지능(AI) 기술을 이용해 암 식별 프로그램을 개발한다. MS는 7일(현지시각) 디지털 병리학 '
          '제공업체인 페이지(Paige)와 협력해 세계 최대의 이미지 기반 AI 모델을 구축하고 있다고 밝혔다. 이 AI...',
 '언론사': '매일경제',
 '작성일자': '2023-09-08',
 '제목': '“희소암까지 싹 잡아낸다”…MS, AI 기반 암 식별 프로그램 개발'}
======================================================================
{'URL': '<https://zdnet.co.kr/view/?no=20230907220708>',
 '본문 요약': '초거대 인공지능(AI)을 전산업으로 확산하기 위한 산‧학‧연 전문가 협의체가 만들어졌다. 과기정통부는 이런 목적을 가진 '
          "'AI 데이터 융합 네트워크' 발족식을 8일 서울 롯데백화점 인근 이비스 앰배서더 명동 호텔 19층...",
 '언론사': '지디넷코리아',
 '작성일자': '2023-09-08',
 '제목': '"초거대AI 전산업 확산"···AI데이터 융합 네트워크 발족'}
======================================================================
{'URL': '<https://www.news1.kr/articles/5164994>',
 '본문 요약': '박정환 문화전문기자 = 인공지능(Ai)이 국내 거주 중인 외국인과 다문화 가정 자녀들의 한국어 실력을... 열리는 '
          "'제1회 AI 한국어 말하기 대회'에서다. 제1회 AI 한국어 말하기 대회는 한글과컴퓨터는 자회사...",
 '언론사': '뉴스1',
 '작성일자': '2023-09-08',
 '제목': '예선 심사위원은 AI…외국인·다문화가정 자녀의 한국어 실력 경연대회'}
======================================================================
{'URL': '<https://www.yna.co.kr/view/AKR20230908046351017?input=1195m>',
 '본문 요약': 'AI) 기술로 진화한 플랫폼을 만들겠다는 비전을 제시했다. 카카오모빌은 8일 서울 강남구 그랜드인터컨티넨탈 '
          "서울파르나스에서 올해로 2회째를 맞는 '넥스트 모빌리티'(NEMO) 행사를 열어 '우리의 세상을 이해하는 AI...",
 '언론사': '연합뉴스',
 '작성일자': '2023-09-08',
 '제목': '카카오모빌 "내년 상반기까지 모빌리티 특화 생성AI 엔진 구축"(종합)'}
======================================================================
{'URL': '<https://www.munhwa.com/news/view.html?no=2023090801071607275001>',
 '본문 요약': '■ 카카오모빌리티‘네모2023’ 내년 상반기 생성AI 엔진 구축 이동·물류·배송분야 적용 계획 모임장소 제안서 '
          '택시호출까지 맞춤여행경로 생성서비스 제시 ‘AI랩’서 자율주행로봇 등 전시 카카오모빌리티가 내년...',
 '언론사': '문화일보',
 '작성일자': '2023-09-08',
 '제목': '“모빌리티에 특화된 생성형 AI엔진 구축”'}
======================================================================
{'URL': '<http://www.edaily.co.kr/news/newspath.asp?newsid=01420246635737824>',
 '본문 요약': '프라이빗 뱅커(PB) 1000여 명이 2차전지 다음으로 인공지능(AI)·반도체 테마 상장지수펀드(ETF)를... '
          '‘인공지능(AI)&반도체’가 335명(32%)의 선택을 받아 1위를 했다고 7일 밝혔다. 이어 249명(23%)이 '
          '△‘2차전지&전기차’...',
 '언론사': '이데일리',
 '작성일자': '2023-09-07',
 '제목': '"2차전지 다음은 AI·반도체"…PB 1000명이 주목한 이유'}
======================================================================
{'URL': '<https://www.etoday.co.kr/news/view/2282422>',
 '본문 요약': '인공지능(AI)보이스봇이 안정적으로 정착되면서, 상담사가 보다 섬세한 고객 케어에 집중할 수 있었던 결과라고 설명했다. '
          'KT는 2017년부터 준비를 시작해, 2021년 4월, 365일 24시간 상담이 가능한 AI 보이스봇 ‘지니’...',
 '언론사': '이투데이',
 '작성일자': '2023-09-08',
 '제목': 'KT, 10년 연속 우수 콜센터…AI가 응대하고 사람이 집중케어'}
======================================================================
{'URL': '<http://news.mt.co.kr/mtview.php?no=2023090810400076118>',
 '본문 요약': '월간큐브/나무는 고객의 월별 투자활동을 시각화해 보여주고 해당 월의 시황을 반영한 인공지능(AI) 음악과 함께 제공하는 '
          '서비스다. 투자자들의 즐거운 순간을 포착해 투자에 대한 긍정적인 경험을 강화하기 위해...',
 '언론사': '머니투데이',
 '작성일자': '2023-09-08',
 '제목': '내 투자가 AI 음악으로…NH투자증권, 월간큐브·월간나무 출시'}
======================================================================
{'URL': '<https://www.hankyung.com/article/202309083127i>',
 '본문 요약': '중국에서 인공지능(AI) 백가쟁명(百家爭鳴) 시대가 열렸다. 기존 중국 정보기술(IT) 업계 강호인 바이두... 다만 '
          "공산당의 사상 검열로 인해 중국산 AI가 글로벌 경쟁에서 뒤처질 경우 '그들만의 리그'가 될 수 있다는...",
 '언론사': '한국경제',
 '작성일자': '2023-09-08',
 '제목': '중국 \\'AI 백가쟁명\\' 시대 열렸다…"100개 넘는 모델이 전쟁"'}

4. 결론

사실 playwright는 웹 크롤링을 위한 것이 아니라, 웹 테스트 및 자동화를 위한 프레임워크입니다.

그러나 playwright는 웹 크롤링에서도 아주 강력한 도구입니다.

본문에서는 다루지 못했지만 다양하고 편리한 기능들을 가지고 있습니다.

Chromium, Firefox, Webkit 등 여러 브라우저를 지원하여 브라우저나 엔진에 제한되지 않은 웹 크롤링을 가능하게 하며, 특히 모던 웹 사이트에 대해 높은 호환성을 가집니다.

또한 필요 없는 이미지나 stylesheets의 로딩을 건너뛰어 크롤링 성능을 향상시킬 수도 있습니다.

우리는 웹 크롤링을 할 때 거의 bs4 또는 selenium을 사용하게 됩니다. 이는 이미 훌륭한 라이브러리이지만, playwright도 사용해보면서 위와 같은 장점을 느껴보면 더욱 좋을 것 같습니다.

이 글도 함께 읽어보세요:

데이터 수집, 이제 자동화하세요

코딩 없이 5분이면 시작 · 5,000개+ 웹사이트 크롤링 경험

무료로 시작하기 →

댓글 2개

댓글 작성

이메일은 공개되지 않으며, 답글 알림에만 사용됩니다.

안녕하세요. 정품 인증 <a href="https://ktown.koreadaily.com/ad_market/marketview_normal?data=48408">✓ 남성 에너지의 지속성을 중요하게 생각한다면 클릭이동</a>건강 전문몰, 파워약국입니다. ✩✩ 잊고 있던 열정을 다시. 중요한 순간에 더 높은 만족을 기대하신다면. 특별한 순간을 보다 자신 있게 즐기고 싶으신가요? 자세한 정보 확인 ⇒ https://boma59.store 파워약국은 신뢰를 바탕으로 한 정품 유통을 원칙으로 합니다. 고객 만족을 최우선으로 서비스를 운영합니다. 파워약국 추천 제품 – 아이코스 드래곤 (ICOS DRAGON) 아이코스 드래곤은 한방 비아그라로 불리는 천연 성분 기반의 남성 활력제입니다. 기존 아이코스 시리즈를 기반으로 개발된 제품입니다. 보다 안정적인 체감을 목표로 설계된 제품입니다. 정품 유통 보장 천연 성분 기반 빠른 체감 효과 꾸준한 재구매율 1위 자세한 정보는 아래 링크를 통해 확인하실 수 있습니다. 게스트 10월 19일 19:49

안녕하세요. 정품 인증 남성건강 전문몰, 파워약국입니다. ✩✩ 잊고 있던 열정을 다시. 중요한 순간에 더 높은 만족을 기대하신다면. 특별한 순간을 보다 자신 있게 즐기고 싶으신가요? 자세한 정보 확인 ⇒ https://boma59.store 파워약국은 신뢰를 바탕으로 한 정품 유통을 원칙으로...

안녕하세요. 파워약국은 남성건강 전문 온라인 약국입니다. ✩✩ 자신감 있는 순간을 위해. 중요한 순간에 더 높은 만족을 기대하신다면. 특별한 순간을 보다 자신 있게 즐기고 싶으신가요? 공식 홈페이지 ⇒ https://zomd12.com 파워약국은 남성의 자신감과 건강한 관계를 위해 정품만을 취급합니다. 고객이 중요한 순간을 보다 편안하게 즐길 수 있도록 돕습니다. 파워약국 대표 남성 활력 관리 제품, 아이코스 드래곤 (ICOS DRAGON) 아이코스 드래곤은 천연 성분을 중심으로 구성된 남성 건강 관리 제품입니다. 아이코스 라인업 중 상위 버전으로 분류됩니다. 황금빛 용의 이미지처럼 강력함과 지속력을 강조합니다. 정품 유통 보장 자연 유래 성분 중심 빠른 체감 효과 반복 구매 사례가 많은 제품 자세한 내용은 공식 사이트를 참고하시기 바랍니다. Look at my web site <a href="https://linktr.ee/hermed95">HERMED임신중절약 정보 여기클릭</a> 게스트 10월 18일 13:38

안녕하세요. 파워약국은 남성건강 전문 온라인 약국입니다. ✩✩ 자신감 있는 순간을 위해. 중요한 순간에 더 높은 만족을 기대하신다면. 특별한 순간을 보다 자신 있게 즐기고 싶으신가요? 공식 홈페이지 ⇒ https://zomd12.com 파워약국은 남성의 자신감과 건강한 관계를 위해 정품만을...

이어서 읽어보세요

새 글 알림 받기

해시스크래퍼 기술 블로그의 새 글이 발행되면 이메일로 알려드립니다.

이메일은 새 글 알림에만 사용됩니다.