在Python中使用Puppeteer

如何在Python中使用Puppeteer爬虫神器

有兴趣在 Python 中使用Puppeteer吗?幸运的是,原始 Node.js 库上有一个非官方的 Python 包装器:Pyppeteer!

在本文中,您将学习如何使用 Pyppeteer 进行网络抓取,包括:

什么是 Python 中的 Pyppeteer

Pyppeteer 是一种使用代码自动化 Chromium 浏览器的工具,允许 Python 开发人员获得JavaScript 呈现功能,以便与现代网站交互并更好地模拟人类行为。

它带有无头浏览器模式,可为您提供浏览器的全部功能,但没有图形用户界面,从而提高了速度并节省了内存。

现在,让我们从 Pyppeteer 教程开始。

如何使用 Pyppeteer

让我们回顾一下在 Python 中使用 Puppeteer 的基础知识,为此您需要安装过程才能进一步了解。

一、如何在Python中安装Pyppeteer

作为先决条件,您必须在系统上安装 Python 3.6+。如果您是新手,请查看安装指南

注意:如果需要,请随时使用我们的教程刷新您的Python 网络抓取基础。

然后,使用下面的命令安装 Pyppeteer:

pip install pyppeteer

当您第一次启动 Pyppeteer 时,如果尚未安装最新版本的 Chromium (150MB),它会下载它,因此需要更长的时间来执行。

2. 如何使用 Pyppeteer

要使用 Pyppeteer,首先要导入所需的包。

#pip install asyncio
import asyncio
from pyppeteer import launch

现在,创建一个函数来获取一个对象到ScrapeMe网站。

async def main():
   browserObj =await launch({"headless": False})
   url = await browserObj.newPage()
   await url.goto('https://scrapeme.live/shop/')


   await browserObj.close()

注意:设置headless选项以False使用 GUI 启动 Chrome 实例。我们没有使用,True因为我们正在测试。

然后,对该main()函数的异步调用使脚本生效。

asyncio.get_event_loop().run_until_complete(main())

完整代码如下所示:

import asyncio
from pyppeteer import launch


async def main():
   browserObj =await launch({"headless": False})
   url = await browserObj.newPage()
   await url.goto('https://scrapeme.live/shop/')


   ## Get HTML
    await browserObj.close()
 
asyncio.get_event_loop().run_until_complete(main())

它有效:

medium_output_scrapeme_dc7d8be1c2

3. 用 Pyppeteer 抓取页面

添加几行代码以等待页面加载、返回其 HTML 并关闭浏览器实例。

htmlContent = await url.content()
await browserObj.close()
return htmlContent

将它们添加到您的脚本并打印 HTML。

import asyncio
from pyppeteer import launch


async def main():
   browserObj =await launch({"headless": False})
   url = await browserObj.newPage()
   await url.goto('https://scrapeme.live/shop/')


   ## Get HTML
   htmlContent = await url.content()
   await browserObj.close()
   return htmlContent


response = asyncio.get_event_loop().run_until_complete(main())
print(response)

在这里你有:

medium_output_scrapeme_dc7d8be1c2

恭喜!🎉 你使用 Pyppeteer 抓取了你的第一个网页。

4. 解析 HTML 内容以提取数据

Pyppeteer 是一个非常强大的工具,它还允许解析页面的原始 HTML 以提取所需的信息。在我们的例子中,产品的标题和价格来自 ScrapeMe 商店。

让我们看一下源代码以确定我们感兴趣的元素。为此,请转到该网站,右键单击任意位置并选择“检查”。HTML 将显示在“开发人员工具”窗口中。

medium_html_elements_scrapeme_7eb817976c

仔细看上面的截图。产品标题在标签中<h2>。同样,价格在标签内<span>,具有amount等级。

回到你的代码,使用querySelectorAll()提取所有的<h2><span>元素,amount在第二种情况下使用类,感谢 CSS 选择器。然后,添加一个循环以将信息存储在 JSON 文件中。

import asyncio
from pyppeteer import launch


async def main():
    browserObj =await launch({"headless": False})
    url = await browserObj.newPage()
    await url.goto('https://scrapeme.live/shop/')
    titles = await url.querySelectorAll("h2")
    prices = await url.querySelectorAll("span .amount")
    for t,p in zip(titles,prices):
        title = await t.getProperty("textContent")
        price = await p.getProperty("textContent")
        # printing the article titles
        print(await title.jsonValue())
        print(await price.jsonValue())


response = asyncio.get_event_loop().run_until_complete(main())

运行脚本,查看结果:抓取的 HTML 输出

5.与动态页面交互

现在的许多网站,如ScrapingClub,都是动态的,这意味着JavaScript 决定其内容更改的频率。例如,社交媒体网站通常对其发布时间轴使用无限滚动。

使用 Requests 和 BeautifulSoap 库抓取此类网站是一项具有挑战性的任务。但是,Pyppeteer 可以派上用场,我们将使用它来等待事件、单击按钮并向下滚动。

等待页面加载

使用以编程方式控制的浏览器时,您必须等待当前页面的内容加载完毕才能继续下一个活动,实现此目的的两种最流行的方法是waitFor()waitForSelector()

waitfor()

waitFor()函数等待以毫秒为单位指定的时间

以下示例在 Chromium 中打开页面并在关闭之前等待 4000 毫秒。

import asyncio
from pyppeteer import launch


async def main():
   browserObj =await launch({"headless": False})
   url = await browserObj.newPage()




   await url.goto('https://scrapingclub.com/exercise/list_infinite_scroll/')
   await url.waitFor(4000)
   await browserObj.close()


asyncio.get_event_loop().run_until_complete(main())
等待选择器()

waitForSelector() 在继续之前等待特定元素出现在页面上。

例如,以下脚本<div>在继续下一步之前等待一些出现。

import asyncio
from pyppeteer import launch

async def main():
   browserObj =await launch({"headless": False})
   url = await browserObj.newPage()
   await url.goto('https://scrapingclub.com/exercise/list_infinite_scroll/')
   await url.waitForSelector('div .alert', {'visible': True})
   await browserObj.close()

asyncio.get_event_loop().run_until_complete(main())

waitForSelector()方法接受两个参数:一个指向所需元素的 CSS 选择器和一个可选的options字典。在我们上面的例子中,options{visible: True}等待<div>元素变得可见。

单击一个按钮

您可以使用 Pyppeteer Python 单击网页上的按钮或其他元素。您需要做的就是使用选择器找到该特定元素并调用该click()方法。

您接下来看到的示例将按照路径单击页面页脚处的链接body > footer > div > p > a

import asyncio
from pyppeteer import launch

async def main():
   browserObj =await launch({"headless": False})
   url = await browserObj.newPage()
   await url.goto('https://scrapingclub.com/exercise/list_infinite_scroll/')
   await url.click('body > footer > div > p > a')
   await browserObj.close()
   
asyncio.get_event_loop().run_until_complete(main())

如前所述,网络抓取开发人员在进一步交互之前等待页面加载,例如与click()方法交互。在下图中,您看到我们单击了初始目标底部的链接。然后,我们等待标题加载到次要目标上以抓取标题。

medium_click_wait_scrape_819a57e740

让我们看看如何使用 Pyppeteer 做到这一点:

import asyncio
from pyppeteer import launch
 
async def main():
    
    browserObj =await launch({"headless": True})
    url = await browserObj.newPage()
    await url.goto('https://scrapingclub.com/exercise/list_infinite_scroll/')
    
    await url.waitForSelector('body > footer > div > p > a')
    await url.click('body > footer > div > p > a')
    
    await url.waitForSelector('a[title="MichaelYin Blog')
    
    success_message = await url.querySelector('a[title="MichaelYin Blog"]')
    text = await success_message.getProperty("textContent")
    print (await text.jsonValue())
    await browserObj.close()

asyncio.get_event_loop().run_until_complete(main())

输出如下:

MichaelYin Blog

请注意,我们合并了该waitForSelector()方法以增加代码的健壮性。

滚动页面

Pyppeteer 对于使用无限滚动来加载内容的现代网站很有用,该evaluate()功能在这种情况下会有所帮助。查看下面的代码以了解如何操作。

import asyncio
from pyppeteer import launch
 
async def main():
    browserObj =await launch({"headless": False})
    url = await browserObj.newPage()
    await url.setViewport({'width': 1280, 'height': 720})
    await url.goto('https://scrapingclub.com/exercise/list_infinite_scroll/')
    await url.evaluate("""{window.scrollBy(0, document.body.scrollHeight);}""")
    await url.waitFor(5000)
    await browserObj.close()
 
asyncio.get_event_loop().run_until_complete(main())

我们创建了一个浏览器对象(带有一个url选项卡)并设置浏览器窗口的视口大小(它是网页的可见区域并影响它在屏幕上的呈现方式)。该脚本会将浏览器窗口滚动一个屏幕。

您可以使用此滚动来加载所有数据并抓取它。例如,假设您想从无限滚动页面中获取所有产品名称:

import asyncio
from pyppeteer import launch
 
async def main():
    
    browserObj =await launch({"headless": False})
    url = await browserObj.newPage()
    await url.setViewport({'width': 1280, 'height': 720})
    await url.goto('https://scrapingclub.com/exercise/list_infinite_scroll/')

    # Get the height of the current page
    current_height = await url.evaluate('document.body.scrollHeight')
    
    while True:
        # Scroll to the bottom of the page
        await url.evaluate('window.scrollBy(0, document.body.scrollHeight)')

        # Wait for the page to load new content
        await url.waitFor(2000)

        # Update the height of the current page
        new_height = await url.evaluate('document.body.scrollHeight')

        # Break the loop if we have reached the end of the page
        if new_height == current_height:
            break

        current_height = new_height
    
    #Scraping in Action
    all_product_tags = await url.querySelectorAll("div > h4 > a")
    for a in all_product_tags:
        product_name = await a.getProperty("textContent")
        print(await product_name.jsonValue())

    await browserObj.close()

asyncio.get_event_loop().run_until_complete(main())

上面的 Pyppeteer 脚本导航到页面并获取当前滚动高度,然后迭代地垂直滚动页面直到不再发生滚动。该waitFor()方法在每次滚动时等待两秒钟,以确保页面正确加载内容。

最后,如该部分输出片段所示,打印所有加载产品的名称。small_output_scroll_scrape_with_wait_d558d5d02d

6. 使用 Pyppeteer 截图

观察刮板在做什么会很方便,对吧?但是您在生产环境中看不到任何实时 GUI。

幸运的是,Pyppeteer 的截图功能可以帮助调试。以下代码打开一个网页,截取整个页面的屏幕截图并以“web_screenshot.png”名称保存在当前目录中。

import asyncio
from pyppeteer import launch
async def main():
   browserObj =await launch({"headless": True})
   url = await browserObj.newPage()
   await url.goto('https://scrapingclub.com/exercise/list_infinite_scroll/')
   await url.screenshot({'path': 'web_screenshot.png'})
   await browserObj.close()
asyncio.get_event_loop().run_until_complete(main())

7. 使用 Pyppeteer 的代理

在进行网页抓取时,您需要使用代理以避免被目标网站阻止。但这是为什么呢?

如果您访问一个每天有数百或数千个请求的网站,该网站可能会将您的 IP 列入黑名单,您将无法再抓取内容。

代理充当您和目标网站之间的中介,为您提供新的 IP。一些网络抓取代理提供商,如 ZenRows,具有默认的 IP 轮换机制,以防止地址被禁止,从而节省资金。

查看以下代码片段,了解在启动方法中将代理与 Pyppeteer 集成。

import asyncio
from pyppeteer import launch

async def main():
   browserObj =await launch({'args': ['--proxy-server=address:port'], "headless": False})
   url = await browserObj.newPage()
   await url.authenticate({'username': 'user', 'password': 'passw'})
   await url.goto('https://scrapeme.live/shop/')
   await browserObj.close()
   
asyncio.get_event_loop().run_until_complete(main()

注意:如果代理需要用户名和密码,您可以使用该authenticate()方法设置凭据。

8. 使用 Pyppeteer 登录

有时你可能想在登录后抓取内容,Pyppeteer 可以在这方面提供帮助。

转到Quotes网站,您可以在其中看到Login屏幕右上角的 。


单击登录链接会将您重定向到登录页面,其中包含用户名和密码的输入字段以及一个submit按钮。
注意:由于本网站用于测试,您可以使用“admin”作为用户名和“12345”作为密码。

让我们看看这些元素的 HTML。

下面的脚本输入用户凭据,然后使用 Pyppeteer单击登录按钮。之后,它等待五秒钟让下一页完全加载。最后对页面进行截图,测试是否登录成功。

import asyncio
from pyppeteer import launch

async def main():
   browserObj =await launch()
   url = await browserObj.newPage()
   await url.goto('http://quotes.toscrape.com/login')
   await url.type('#username', 'admin');
   await url.type('#password', '12345');
   await url.click('body > div > form > input.btn.btn-primary')
   await url.waitFor(5000);
   await url.screenshot({'path': 'quotes.png'})
   ## Get HTML
   await browserObj.close()

asyncio.get_event_loop().run_until_complete(main())

 您已成功登录。

注意:这个网站很简单,只需要用户名和密码,但有些网站实施了更高级的安全措施。阅读我们的指南,了解如何使用 Python 抓取登录信息以了解更多信息。

解决常见错误

您在设置 Pyppeteer 时可能会遇到一些错误,所以如果出现这些错误,请在此处找到解决方法。

错误:未安装 Pyppeteer

在安装 Pyppeteer 时,您可能会遇到“无法安装 Pyppeteer”错误。

您系统上的 Python 版本是根本原因,因为 Pyppeteer 仅支持 Python 3.6+ 版本。所以,如果你有一个旧版本,你可能会遇到这样的安装错误。解决方案是升级 Python 并重新安装 Pyppeteer。

错误:Pyppeteer 浏览器意外关闭

假设您在安装后第一次执行 Pyppeteer Python 脚本但遇到此错误:pyppeteer.errors.BrowserError: Browser closed unexpectedly

这意味着并非所有 Chromium 依赖项都已完全安装。解决方案是使用以下命令手动安装 Chrome 驱动程序:

pyppeteer-install

结论

Pyppeteer 是经典 Node.js Puppeteer 库的非官方 Python 端口。它是一个设置友好、轻量级且快速的软件包,适用于 Web 自动化和动态网站抓取。

本教程介绍了如何使用 Python 的 Puppeteer 执行基本的无头 Web 抓取,以及如何处理 Web 登录和高级动态交互。此外,您现在知道如何将代理与 Pyppeteer 集成。

如果您需要更多功能,请查看官方手册,例如在 Pyppeteer 中设置自定义用户代理。

类似文章