如何在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())
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)
恭喜!🎉 你使用 Pyppeteer 抓取了你的第一个网页。
4. 解析 HTML 内容以提取数据
Pyppeteer 是一个非常强大的工具,它还允许解析页面的原始 HTML 以提取所需的信息。在我们的例子中,产品的标题和价格来自 ScrapeMe 商店。
让我们看一下源代码以确定我们感兴趣的元素。为此,请转到该网站,右键单击任意位置并选择“检查”。HTML 将显示在“开发人员工具”窗口中。
仔细看上面的截图。产品标题在标签中<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())
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()
方法交互。在下图中,您看到我们单击了初始目标底部的链接。然后,我们等待标题加载到次要目标上以抓取标题。
让我们看看如何使用 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()
方法在每次滚动时等待两秒钟,以确保页面正确加载内容。
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 中设置自定义用户代理。