Puppeteer简介

原文:Introduction to Puppeteer

Puppeteer使用真实浏览器测试JavaScript应用,是非常好的工具。

Puppeteer是谷歌官方支持的用Node.js控制Chrome的库。你可以从Node.js打开Chrome、跳转到谷歌、搜索点什么、然后查看结果。你也可以用无头模式运行Puppeteer,让它在后台运行。

例如,你可以用Puppeteer和Node.js让Chrome加载谷歌的首页:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const puppeteer = require('puppeteer');

run().then(() => console.log('Done')).catch(error => console.log(error));

async function run() {
// 设置`headless: false`可以打开浏览器窗口
// 这样可以看到实际操作
const browser = await puppeteer.launch({ headless: false });

// 打开新页面,跳转到google.com
const page = await browser.newPage();
await page.goto('https://google.com');

// 等5秒钟
await new Promise(resolve => setTimeout(resolve, 5000));

// 关闭浏览器,退出脚本
await browser.close();
}

输出结果类似下图:

Puppeteer操作Chrome

执行JavaScript

Puppeteer的页面有一个好用的evaluate()函数,可以在Chrome窗口中执行JavaScript。evaluate()函数是Puppeteer最灵活的交互方式,因为它允许你使用浏览器API控制Chrome,例如document.querySelector()

以下示例脚本在谷歌搜索了“JavaScript”,获取了前10个结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const puppeteer = require('puppeteer');

// 后台运行(无头模式)
const browser = await puppeteer.launch({ headless: true });

// 跳转到谷歌
const page = await browser.newPage();
await page.goto('https://google.com');

// 搜索框输入"JavaScript"
await page.evaluate(() => {
document.querySelector('input[name="q"]').value = 'JavaScript';
});

// 点击搜索按钮,等待页面加载
await Promise.all([
page.waitForNavigation(),
page.evaluate(() => {
document.querySelector('input[value="Google Search"]').click();
})
]);

// 获取所有搜索结果
const links = await page.evaluate(function getUrls() {
return Array.from(document.querySelectorAll('a cite').values()).
map(el => el.innerHTML);
});

await browser.close();

在本地Web服务器使用Puppeteer

因为Node.js使用事件循环,在同一个脚本启动express服务器并连接到Puppeteer是非常方便的。这意味着很容易用Puppeteer测试Vue页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
const express = require('express');
const puppeteer = require('puppeteer');

// 启动express,渲染一个计数器的Vue页面
const app = express();
app.get('/', function(req, res) {
res.send(`
<html>
<body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="content"></div>

<script type="text/javascript">
const app = new Vue({
data: () => ({ count: 0 }),
template: \`
<div>
<div id="count">
Count: {{count}}
</div>
<button v-on:click="++count">Increment</button>
</div>
\`
});
app.$mount('#content');
</script>
</body>
</html>
`);
});
const server = await app.listen(3000);

// 后台运行(无头模式)
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto('http://localhost:3000');

// 加载当前计数
let count = await page.evaluate(() => {
return document.querySelector('#count').innerHTML.trim();
});
count; // 'Count: 0'

// count递增,检查计数器是否增长
await page.evaluate(() => {
document.querySelector('button').click();
});

count = await page.evaluate(() => {
return document.querySelector('#count').innerHTML.trim();
});
count; // 'Count: 1'

await browser.close();
await server.close();