使用微软 Playwright 进行网页浏览器自动化

这是有关使用微软 Playwright 自动化 Web 浏览器的指南。我们将介绍 Playwright 的安装、打开浏览器、以及爬取 Naver 新闻等内容。

9
使用微软 Playwright 进行网页浏览器自动化

0. 什么是Playwright?

Playwright是由微软开发的开源库,用于自动化Web浏览器。

虽然最初并非为Web抓取而设计,但通过适当地组合浏览器和设置,它在这个领域表现出色。

可以在Node.js和Python等多种语言中使用,目前支持Chrome、Firefox、WebKit(移动Safari)、Electron等多个浏览器。

本文中将使用Python。


1. 安装Playwright

安装playwright包:

pip install playwright

安装必要的浏览器:

playwright install

2. 打开浏览器

让我们尝试访问Naver首页进行测试。

# 패키지 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

上述代码运行结果,浏览器以“隐私模式”打开,并成功访问了Naver首页。


3. 爬取Naver新闻

让我们尝试爬取Naver新闻的搜索结果列表。

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,您将看到与输入关键字相关的Naver新闻搜索结果。

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中,由于异步访问Web元素,无法同时选择元素并获取文本。

请使用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 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',会导致错误。

因此,如果时间包含“面”,则返回错误消息,否则添加一个函数将日期格式转换为%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”后的Naver新闻搜索结果:

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并不是用于Web抓取的工具,而是用于Web测试和自动化的框架。

然而,Playwright在Web抓取方面也是一个非常强大的工具。

虽然本文未涉及,但它具有多样且方便的功能。

支持Chromium、Firefox、WebKit等多种浏览器,使得可以进行不受限于浏览器或引擎的Web抓取,特别是对于现代网站具有高度兼容性。

此外,还可以跳过不必要的图像或样式表加载,从而提高抓取性能。

在进行Web抓取时,我们几乎总是使用bs4或selenium。尽管这些都是出色的库,但如果尝试使用Playwright,您可能会感受到更多优势。

也可以阅读这篇文章:

数据收集,现在自动化

无需编码,5分钟即可开始 · 5000多个网站抓取经验

免费开始 →

Comments

Add Comment

Your email won't be published and will only be used for reply notifications.

继续阅读

Get notified of new posts

We'll email you when 해시스크래퍼 기술 블로그 publishes new content.

Your email will only be used for new post notifications.