如何使用Playwright抓取网页

您需要在抓取网页时运行浏览器以与网页交互(点击按钮、填写表格……)并加载基于 JavaScript 的元素。Playwright 是一个流行的库,可以让您比其他替代方案更快地做到这一点。

让我们用 Python 和 Node.js 学习 Playwright 网页抓取!

什么是Playwright?

Playwright 是一个基于 Node.js 构建的开源框架,但与大多数流行的编程语言兼容,可帮助您自动执行 Web 浏览任务。它适用于 Google Chrome、Microsoft Edge、Firefox 和 Safari。

借助用户友好的语法,即使是编程新手也可以轻松学习该框架并实现他们的目标。

Playwright 具有无头浏览器模式,可显着缩短页面加载和数据提取时间。由于缺少图形用户界面 (GUI),它使用的内存资源也少于常规浏览器。

playwright

安装Playwright

让我们来看看 Python 和 Node.js 中的安装过程。

如何为 Python 安装和启动 Playwright

首先,playwright通过安装包pip和我们稍后将使用的必要浏览器实例。请记住,下载ChromiumWebKitFirefox可能需要一些时间。

pip install playwright 
playwright install

默认情况下,爬虫以无头模式运行,这是爬虫的首选模式。

browser = await playwright.chromium.launch(headless=False)

现在,让我们创建一个新的浏览器会话browser.new_context(),它不会与其他浏览器上下文共享内部信息(例如 cookie 或缓存)。page.goto()之后我们将使用该函数导航到任何 URL 。

最后,我们将在使用context.close()和完成 Playwright 抓取过程后关闭上下文和浏览器browser.close()

async def run(playwright: Playwright) -> None: 
    # Launch the headed browser instance (headless=False) 
    # To see the process of playwright scraping 
    # chromium.launch - opens a Chromium browser 
    browser = await playwright.chromium.launch(headless=False) 
    context = await browser.new_context() # Creates a new browser context 
    page = await context.new_page() # Open new page 
    await page.goto("https://scrapeme.live/shop/") # Go to the chosen website 
 
    # You scraping functions go here 
 
    # Turn off the browser and context once you have finished 
    await context.close() 
    await browser.close() 
 
async def main() -> None: 
    async with async_playwright() as playwright: 
        await run(playwright) 
 
asyncio.run(main())

一旦我们这样做了,我们就可以开始定义你的网络抓取工具的结构了!

对于基于 Python 的爬虫,您可以选择同步异步,而 Node.js 仅以异步方式工作。在本教程中,我们专注于异步 Playwright 网络抓取,因此我们必须将asyncioasync_playwright包与其自身一起调用playwright

# Import libraries to deploy into scraper 
import asyncio 
from playwright.async_api import Playwright, async_playwright

async通过和/或参数调用异步抓取await。它允许您一起处理多个工作流。通常,这比一个接一个地同步执行操作要高效得多。此外,await将控制线程返回到事件循环。

如何在 Node.js 中安装和启动 Playwright

使用以下命令为 Node.js 安装 Playwright 依赖项:

npm init -y 
npm install playwright

接下来,您将在指定目录中找到playwright.config.ts文件。您可以在此处设置抓取环境、确定要使用的浏览器类型等。我们已经深入介绍了 Node.js 抓取,所以让我们继续学习真正的网络抓取示例!

如何使用 Playwright 进行网页抓取

在构建 Playwright 爬虫时,我们有不同的方法:

  • 文字抓取。
  • 图像抓取。
  • CSV 导出。
  • 页面导航。
  • 截图。

让我们详细探讨一下。

第 1 步:定位元素并提取文本

在我们的第一个用例中,我们将从一些简单的事情开始,以探索ScrapeMe网站的爬行选项。

scrape_me_selector

使用 DevTools 进行页面检查

Playwright 抓取通常需要开发人员向浏览器提供所需的目标 URL,然后使用选择器访问页面上的特定 DOM 元素。

选择器的选择通常取决于目标元素的位置和页面的 Web 架构。在具有简单网络架构的页面上,可以通过其唯一标识符轻松抓取它。但是,请准备好在嵌套结构中搜索您的选择器。

在这里,我们将尝试使用搜索相应 CSS 选择器的方法来获取三个变量( productpriceimg_link)的值。element_handle.query_selector(selector)尝试选择其中一只 Pokémon 并在 DevTools 浏览器中查看其背后的数据。

<li>由于每个元素都在我们网页上的CSS 标记的范围内,具有相同的类名 ( "li.product"),我们将首先创建一个item包含所有显示项的公共变量。

items = await page.query_selector_all("li.product") 
 
for i in items: 
    scraped_element = {} 
 
    # Product name 
    el_title = await i.query_selector("h2") 
    scraped_element["product"] = await el_title.inner_text() 
     
    # Product price 
    el_price = await i.query_selector("span.woocommerce-Price-amount") 
    scraped_element["price"] = await el_price.text_content()

然后,仔细观察选择器,您会发现每个变量都分配了自己的标识符,例如"h2"for product"span.woocommerce-Price-amount"productpricea.woocommerce-LoopProduct-link.woocommerce-loop-product__linkURL image。这就是为什么我们将再次调用查询选择方法来查找和提取我们正在分析的数据值。

有趣的是,有时对于基于 JavaScript 的网站,抓取工具可能会在页面完全加载之前很久就返回数据。但是,实施await,我们保证这不会发生。Playwright 网络抓取工具仅在指定元素已完全加载时才会工作。

# Import libraries to deploy into scraper 
import asyncio 
from playwright.async_api import Playwright, async_playwright 
 
# Start with playwright scraping here: 
async def scrape_data(page): 
    scraped_elements = [] 
    items = await page.query_selector_all("li.product") 
 
    # Pick the scraping item 
    for i in items: 
        scraped_element = {} 
 
        # Product name 
        el_title = await i.query_selector("h2") 
        scraped_element["product"] = await el_title.inner_text() 
 
        # Product price 
        el_price = await i.query_selector("span.woocommerce-Price-amount") 
        scraped_element["price"] = await el_price.text_content() 
 
        scraped_elements.append(scraped_element) 
    return scraped_elements 
 
 
async def run(playwright: Playwright) -> None: 
    # Launch the headed browser instance (headless=False) 
    # To see the process of playwright scraping 
    # chromium.launch - opens a Chromium browser 
    browser = await playwright.chromium.launch(headless=False) 
 
    # Creates a new browser context 
    context = await browser.new_context() 
 
    # Open new page 
    page = await context.new_page() 
 
    # Go to the chosen website 
    await page.goto("https://scrapeme.live/shop/") 
    data = await scrape_data(page) 
 
    print(data) 
 
    await context.close() 
    # Turn off the browser once you finished 
    await browser.close() 
 
 
async def main() -> None: 
    async with async_playwright() as playwright: 
        await run(playwright) 
 
 
asyncio.run(main())

第 2 步:使用 Playwright 抓取图像

如何提取产品图片?您需要获取图像属性,该属性通常用 HTML 代码编写为"src".

你可以这样做:

# Start with playwright scraping here: 
async def scrape_data(page): 
    scraped_elements = [] 
    items = await page.query_selector_all("li.product") 
 
    # Pick the scraping item 
    for i in items: 
        # ... same as before 
 
        # Product image 
        image = await i.query_selector( 
            "a.woocommerce-LoopProduct-link.woocommerce-loop-product__link > img" 
        ) 
        scraped_element["img_link"] = await image.get_attribute("src") 
        scraped_elements.append(scraped_element) 
    return scraped_elements 

到目前为止,我们用例的最终输出将包含产品名称、价格和图像资产的链接:

[ 
    { 
        "product": "Bulbasaur", 
        "price": "63.00", 
        "img_link": "https://scrapeme.live/wp-content/uploads/2018/08/001-350x350.png", 
    }, 
    { 
        "product": "Ivysaur", 
        "price": "87.00", 
        "img_link": "https://scrapeme.live/wp-content/uploads/2018/08/002-350x350.png", 
    }, 
    { 
        "product": "Venusaur", 
        "price": "105.00", 
        "img_link": "https://scrapeme.live/wp-content/uploads/2018/08/003-350x350.png", 
    }, 
]

第 3 步:将数据导出到 CSV

现在,当我们看到我们成功地抓取数据时,让我们将其保存在 CSV 中。为此,首先csv在代码顶部导入库。

# import a csv package to output the cleaned data to a .csv file 
import csv

之后,在一个新的 Python 函数中编写数据映射逻辑:

# Optionally, you might want to store output data in a .csv format 
def save_as_csv(data): 
    with open("scraped_data.csv", "w", newline="") as csvfile: 
        fields = ["product", "price", "img_link"] 
        writer = csv.DictWriter(csvfile, fieldnames=fields, quoting=csv.QUOTE_ALL) 
        writer.writeheader() 
        writer.writerows(data)

不要忘记在代码末尾调用指定的函数:

save_as_csv(data) # Save the retried data to csv

现在您可以欣赏 Playwright 抓取时获得的元素表:

scraped_data

以 CSV 格式呈现的抓取数据

第 4 步:页面导航

我们的工作不仅限于抓取单个网页,因为网站经常将产品目录组织到多个页面中。

由于 Playwright 的目标之一是自动化,我们可以轻松地将分页抓取添加到我们的代码中,只需一个额外的周期。使用 DevTools,我们需要搜索下一个链接的 ID,然后将此值插入到函数中page.locator

page.locator()方法将输出元素定位器,我们可以进一步将其用于单击、点击或填充功能。这样,我们将 CSS 选择器传递给 location 函数,并在元素完全加载后立即page.locator("text=→").nth(1)单击它。.click()page.wait_for_selector("li.product")

# Go through different pages 
for i in range(2): 
    await page.locator("text=→").nth(1).click() 
    data.extend(await scrape_data(page)) 
    await page.wait_for_selector("li.product")

第 5 步:使用 Playwright 截图

amazon_product

通过 Playwright Python 抓取器截取屏幕截图

让我们通过截取产品页面的屏幕截图来为我们的数据提取添加视觉效果。对于这个 Playwright 示例,我们将以一个流行的在线零售商为目标:亚马逊

在我们以无头模式启动 Chromium 浏览器并根据选择器定义元素后,我们将启动 Playwright 的屏幕截图 API。

使用page.screenshot()方法,您可以捕获:

  1. 全屏:page.screenshot({ path: 'screenshot.png', fullPage: true }).
  2. 页面的单个元素:page.locator('.header').screenshot({ path: 'screenshot.png' }).

然后将最终截图保存到指定目录。

from playwright.sync_api import sync_playwright 
 
with sync_playwright() as p: 
    browser = p.chromium.launch() 
    page = browser.new_page() 
    page.goto("https://www.amazon.com/dp/B00B7NPRY8/") 
 
    # Create a dictionary with the scraped data 
    item = { 
        "item_title": page.query_selector("#productTitle").inner_text(), 
        "author": page.query_selector(".contributorNameID").inner_text(), 
        "price": page.query_selector(".a-size-base.a-color-price.a-color-price").inner_text(), 
    } 
 
    print(item) 
 
    page.screenshot(path="item.png") 
    browser.close()

之后,您应该在终端中看到以下输出,以及保存在工作目录中的页面的 .png 文件。

{"item_title": "Dune", "author": "Frank Herbert", "price": "$9.99"}

Playwright vs. Puppeteer vs. Selenium

Playwright 与 Selenium 和 Puppeteer 这两个最流行的网络抓取无头浏览器相比如何?

headless_browsers

Selenium、Playwright 和 Puppeteer 框架的比较

Playwright可以使用单个 API 跨多个浏览器无缝运行,并提供大量文档来帮助您入门。它允许使用不同的编程语言,如 Python、Node.js、Java 和 .NET,但不允许使用 Ruby。

同时,Selenium与 Ruby 一起使用时具有更广泛的语言兼容性,但它需要第三方附加组件来并行执行和视频录制。

另一方面,Puppeteer是一种更受限制的工具,但比 Selenium 快约 60%,比 Playwright 略快。

我们来看看这张对比表:

headless_browsers_comparison

Playwright vs. Selenium v​​s. puppeteer

如您所见,Playwright 无疑赢得了大多数用例的竞争。但如果您仍然不相信,这里有一个要考虑的 Playwright 功能摘要:

  • 它具有跨浏览器、跨平台和跨语言的支持
  • Playwright可以为您运行的每个测试或抓取循环隔离浏览器上下文。您可以在每个上下文的基础上自定义 cookie、代理和 JavaScript 等设置,以定制浏览器体验。
  • 它的自动等待功能决定上下文何时准备好进行交互。通过补充await page.click()Playwright API(例如await page.waitForSelector()await page.waitForFunction()方法),您的抓取工具将提取所有数据。
  • Playwright 使用代理服务器来帮助开发人员伪装他们的 IP 地址。这样,您就可以绕过反抓取拦截器
  • 也可以通过阻塞资源来降低带宽

如果您想深入挖掘,我们写了一些直接比较:Playwright vs. SeleniumPuppeteer vs. SeleniumPlaywright vs. Puppeteer

结论

我们使用 Playwright 构建了一个爬虫,涵盖了最常见的场景,例如文本和图像提取。现在,您已准备好迎接新的挑战!

类似文章