puppeteer 是什么?
点进这篇文章的你,相信已经知道 puppeteer 是什么东西了,如果你不知道,在这里我简单的介绍一下:
- puppeteer 是一个操作浏览器的工具包
- 常见的就两个用途:爬虫、端到端测试。除此之外做SSR同构渲染也可能会用到。
其他平台也有类似的软件,比如支持 python、java、.Net 的 playwright。这种工具一般叫做 RPA,也就是计算机自动化辅助工具。
puppeteer 等工具,支持最好的是 chromium(或者说 chrome)
这篇文章主要说爬虫,或者换个说法,我如何去控制浏览器,拿到网页中的元素、控制网页做事?
下面我以 puppeteer 和 chrome 为例说明,其他的可以参照文档,playwright 的 API 和 puppeteer 差不多
速查表
要想控制浏览器,首先和浏览器要建立连接关系,
- 可以使用
puppeteer.connect
连接一个已经启动的 chrome - 也可以使用
puppeteer.launch
启动新的 chrome 实例,各种启动参数都可以指定
这两个方法的返回值都是浏览器 browser
实例,获取到实例后可以控制打开想要爬取的页面
打开爬取页面分两步
- 使用
browser.newPage
打开新的标签页,或者在browser.pages
数组中找到并复用已经打开的标签页 - 使用
page.goto(url)
跳转到想要打开的地址
什么时候页面加载完成了呢?执行 wait
开头的方法,等就行了
有这些比较常用的方法:
方法 | 描述 |
---|---|
page.waitForTimeout | 等待你指定的一段时间 |
page.waitForFunction | 执行一个方法,等待方法返回真值 |
page.waitForSelector | 使用 selector 查找元素,等待出现 |
page.waitForXPath | 使用 xpath 查找元素,等待元素出现 |
等页面加载完了,或者等你想要的内容出来了,或者是我就想等10s,完成了就可以操作了
那如何操作页面做事?
- 可以通过
page.exposeFunction
将方法注入到浏览器,甚至可以暴露 node 内部的方法给浏览器端执行。
比如说我想将日志传递到node记录,
就可以在控制端执行暴露方法
page.exposeFunction('$log', (...args) => winLogger.info(...args))
在被控端就能在全局window中拿到这个方法执行
$log('hello world')
- 可以在 node 端调用
page.evaluate
,调用浏览器内的方法、获取浏览器端全局作用域里的变量
比如说浏览器 window 对象有个方法
window.someFunction = (a) => doSomething(a)
在node端调用就可以
await page.evaluate((a) => {
window.someFunction(a)
}, {a: somedata})
evaluate 方法第一个参数是执行函数,第二个参数是需要传入函数的值
执行阶段可能遇到的问题
- 大小
puppeteer 和 chrome 之间通过 cdp 协议通信,默认是 websocket,受到默认 websocket 配置参数的限制,超过80M左右的大数据没法传输到浏览器。
什么时候会传递数据呢?比如说 page.evaluate
方法第二个参数传递值
怎么办?大数据量分片传递,或者使用其他方法,比如将大数据写入本地文件或放到oss,在浏览器端调用读文件方法或者从oss拉取,绕过直接传递通信
- 只能传递可序列化的值
object 和 function 是没法传递的,如果你想传递 function,可以转换成 string 传递,然后在内部使用 new Function 转换成函数
下一步
我写完这个速查表之后,才发现站里有个四年前的文章写得很全了。刚入门推荐看这个,能知道边界在哪里 # 结合项目来谈谈 Puppeteer