puppeteer常见api
安装
cnpm i puppeteer
- 因为要使用到async, await异步处理方法,所以最好是把nodejs升级到7.6.0以上
几个常用的API
-
puppeteer.launch([options])
-
options <Object>
启动浏览器时的配置,可能存在如下字段:-
ignoreHTTPSErrors <boolean>
是否忽略在导航阶段 HTTPS引发的错误,默认为false -
headless <boolean>
是否以一种headless mode
的模式来启动浏览器。 只要devtools 选项不为true,那么此选项的默认值就是 true -
executablePath <string> Chromium
或Chrome
的运行路径而不是安装路径。 如果executablePath
是一个相对目录, 那么它应该是相对于current working directory
。 -
slowMo <number>
通过改变此值来减缓Puppeteer
的操作速度,单位是毫秒,当你想知道具体发生了什么情况的时候,此参数将会比较有用。 -
args <Array<string>>
传递给浏览器实例的额外参数,这些参数的可选列表可见与此 -
ignoreDefaultArgs <boolean>
将会使puppeteer.defaultArgs()
失效。 属于比较危险的选项,需要小心使用。默认为false
-
handleSIGINT <boolean>
程序终止信号,通过按下Ctrl-C
来关闭浏览器进程,默认为true
-
handleSIGTERM <boolean>
程序结束信号,当接收到程序结束信号时,关闭浏览器进程,默认为true
。 -
timeout <number>
等待浏览器实例启动的超时时间,单位为ms
,默认是30000 (30秒)
,设置为0
标识禁用此选项。 -
devtools <boolean>
是否为每个标签页自动打开DevTools
面板,如果为true
, 那么headless
选项将被设置为false
-
-
//打开浏览器并设置浏览器为有头模式,并且减慢操作时间为150ms
const browser = await puppeteer.launch({headless:false,slowMo:150})
2. browser.newPage()
returns: <Promise<Page>>
- 返回一个新的
Page Promise
对象,Page将在一个默认的浏览器上下文中创建。
const page = await browser.newPage();
- 返回一个新的
创建一个page对象,后面就用这个对象进行操作
3. page.goto(url, options)
-
url <string>
目标页面的url. url
中应该包含协议头,例如https://
。-
timeout <number>
连接超时时间,单位毫秒, 默认是 30秒, 如果设置为 0则表示禁用此选项。 此值也可以被 page.setDefaultNavigationTimeout(timeout) 方法修改。 -
waitUntil <string|Array<string>>
确认navigation
成功的条件, 默认是load
。如果给定的值是一个事件组成的数组,那么只有当数组中的所有事件全部被触发后才会认为navigation
成功,可选的事件列表如下: -
load
- 当load
事件触发时,则认为navigation
导航结束。 -
domcontentloaded
- 当DOMContentLoaded
事件触发时,则认为navigation
导航结束。 -
networkidle0
- 如果在 500ms内发起的http请求数为0,则认为导航结束。 -
networkidle2
- 如果在 500ms内发起的http请求数为不超过 2条,则认为导航结束。
-
// 页面跳转到12306的登录页
await page.goto('https://kyfw.12306.cn/otn/login/init')
4 page.type(selector, text[, options])
-
selector <string>
文本框(包括texarea
和input
)的选择器。如果选择器匹配出了多个元素,则只会选择第一个匹配的元素上。 -
text <string>
将要输入到文本框内的文字。 -
options <Object>
-
delay <number>
按键输入的间隔速度,单位为ms
。默认为0
. -
returns: <Promise>
-
Sends a keydown, keypress/input, and keyup event for each character in the text.
-
效果等同于
page.click()
await page.type('#username', 'yourtelephone')
await page.type('#password', 'yourpassword')
<input id="username" tabindex="1" name="loginUserDTO.user_name" type="text" class="inptxt w200" style="color: rgb(153, 153, 153); width: 309px;">
//上面这段是从12306网站登录页截取下来的,这里的`#username`就是html元素中的id标识,所以我们只要在网站中去找到这个唯一标识,然后获取它就可以给他赋值了
page.waitForNavigation(options)
-
options <Object> Navigation
参数,允许存在以下属性 -
timeout <number> navigation
超时时间(ms),默认是 30 seconds, 取值 0则表示禁用此选项。也可以使用page.setDefaultNavigationTimeout(timeout)
方法来改变默认值。 -
waitUntil <string|Array<string>> navigation
导航成功的界限, 默认是 load. 如果给定的值是一个事件名称组成的数组,那么只有当数组中的所有事件全部被触发后才会认为navigation
成功,可选的事件列表如下: -
load
- 当 load 事件触发时,则认为navigation
导航结束。 -
domcontentloaded
- 当DOMContentLoaded
事件触发时,则认为navigation
导航结束。 -
networkidle0
- 如果在 500ms内发起的http
请求数为0,则认为导航结束。 -
networkidle2
- 如果在 500ms内发起的http
请求数为不超过 2条,则认为导航结束。 -
returns: <Promise<Response>> Promise which resolves to the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.
适应于当页面重定向到一个新的url或者reload的场景,例如,当执行了一段可能间接导致页面跳转的代码:
await page.waitForNavigation({
waitUntil: 'domcontentloaded'
})
console.log(page.url())
console.log('填写验证码后登录')
await page.waitForNavigation({
waitUntil: 'load'
})
这里因为是手动输入图片验证码,所以设置一个等待函数,在点击登录按钮后直接跳转。
page.waitForSelector(selector[, options])
-
selector <string>
被等待的元素的选择器selector
-
options <Object>
可选参数: -
visible <boolean>
出现在DOM
中的元素必须是可见的(visible)
,例如,不能有 display: none 或者 visibility: hidden CSS 属性。默认是 false。 -
hidden <boolean>
元素不存在于DOM中(包括一开始就不存在,或者存在了又被移除掉),或者是被隐藏了, 例如, 具有display: none
或者visibility: hidden CSS
属性。默认是false
. -
timeout <number>
最大等待时间(ms)
。默认是30000 (30 秒)
。取值为的0
则表示禁用此参数。 -
returns: <Promise<ElementHandle>> 当在 DOM中找到 selector指定的元素时,Promise 将会 resolves 这个元素的ElementHandle。
等到 selector选择器选择的元素出现在页面中,如果在调用此方法的同时选择器选取的元素就已经存在于页面中了,
则此方法将会立即返回结果,如果超过了最大等待时间 timeout之后,选择器还没有匹配到元素,则将会抛出错误。
demo中需要等待预定车票的元素出现才会点击跳转:
await page.waitForSelector('#selectYuding,#my12306page')
await page.goto('https://kyfw.12306.cn/otn/leftTicket/init')
7 page.evaluate(pageFunction, …args)
-
pageFunction <function|string>
将在page context
中执行的函数 -
...args <…Serializable|JSHandle>
传递给pageFunction
的参数 -
returns: <Promise<Serializable>> Promise which resolves to the return value of pageFunction
-
如果传递给 page.evaluate的 pageFunction函数返回一个 Promise,则page.evaluate将会等待得到resolve后,才会返回它自己的值。
-
如果传递给 page.evaluate的 pageFunction函数返回一个 non-Serializable的值,则page.evaluate将会返回 undefined。
await page.evaluate(() => {
document.querySelector('#fromStation').value = "SHH";
document.querySelector('#toStation').value = "TJP";
})
// const fromStationText = await page.$("#fromStationText");
// await fromStationText.click();
// await page.keyboard.type("BJP");
// const toStationText = await page.$("#toStationText");
// await toStationText.click();
// await page.keyboard.type("SHH");
await page.tap('#date_icon_1');
//填写表单
console.log('开始填写日期');
await page.evaluate((month, day) => {
let cals = document.querySelectorAll('.cal');
let target = Array.from(cals).filter((cal) => cal.querySelector('.month input').value === month)[0];
let days = target.querySelectorAll('.cal-cm .cell')
let theDay = Array.from(days).filter(dayel => dayel.innerText === day + '\n')[0];
theDay.click()
}, month, day)
这里有个坑需要避开,就是12306的输入出发地和到达站时候,如果你直接给他的输入框赋值是不能成功的,因为他有两个input框,一个能看见,一个隐藏的,当你在input框输入你的到达地时候必须要选择一下才能成功赋值,并且那个隐藏的input框的value值会变化,并且他是以SHH形式标识上海:
<input id="fromStation" type="hidden" value="SHH" name="leftTicketDTO.from_station">
<input type="text" id="fromStationText" class="inp-txt inp_selected" value="" name="leftTicketDTO.from_station_name">
所以在输入出发地和到达地的时候,直接获取起作用的那个隐藏的input框,然后给他赋值就可以了。上面的代码后半部分是在给输入框赋值结束后,对时间选择器进行赋值,但是在evaluate
中好像只能用原生的选择器document.querySelectorAll
,$$()
不起作用,赋值结束后点击查询按钮,出来列车的列表。
await page.tap('#query_ticket') //点击查询按钮
console.log('开始查询');
await page.waitForSelector('tr[datatran]');
let tra = await page.$('[datatran="G216"]');//通过datatran="G216"查找G216车次
await page.evaluate(() => {
var trainId = document.querySelector('[datatran="G216"]').id
console.log(this.trainId)
let tr = document.querySelector('#'+trainId.replace('price','ticket'))
let yuding_btns = tr.querySelector('td:last-child a')//看有没有预定的btn
yuding_btns.click()
})
page.on('load',async () => {
await page.tap('#normalPassenger_0')//点选第一个默认乘客
wait page.tap('#submitOrder_id')//提交按钮
await page.tap('#qr_submit_id') //确认按钮
})
8 完整代码
const puppeteer = require('puppeteer');
const month = '八月';
const day = '30';
(async () => {
const browser = await puppeteer.launch({headless:false,slowMo:150});
const page = await browser.newPage();
await page.setViewport({width:1920, height:1080});
await page.setJavaScriptEnabled(true);
// page.on('console', msg => console.log('PAGE LOG:', msg.text()));
await page.goto('https://kyfw.12306.cn/otn/login/init')
await page.type('#username', 'yourtele')
await page.type('#password', 'yourkey')
await page.waitForNavigation({
waitUntil: 'domcontentloaded'
})
console.log(page.url())
console.log('填写验证码后登录')
await page.waitForNavigation({
waitUntil: 'load'
})
await page.waitForSelector('#selectYuding,#my12306page')
await page.goto('https://kyfw.12306.cn/otn/leftTicket/init')
await page.evaluate(() => {
document.querySelector('#fromStation').value = "SHH";
document.querySelector('#toStation').value = "TJP";
})
// const fromStationText = await page.$("#fromStationText");
// await fromStationText.click();
// await page.keyboard.type("BJP");
// const toStationText = await page.$("#toStationText");
// await toStationText.click();
// await page.keyboard.type("SHH");
await page.tap('#date_icon_1');
//填写表单
console.log('开始填写日期');
await page.evaluate((month, day) => {
let cals = document.querySelectorAll('.cal');
let target = Array.from(cals).filter((cal) => cal.querySelector('.month input').value === month)[0];
let days = target.querySelectorAll('.cal-cm .cell')
let theDay = Array.from(days).filter(dayel => dayel.innerText === day + '\n')[0];
theDay.click()
}, month, day)
//点击查询
await page.tap('#query_ticket')
console.log('开始查询');
await page.waitForSelector('tr[datatran]');
let tra = await page.$('[datatran="G216"]');
await page.evaluate(() => {
var trainId = document.querySelector('[datatran="G216"]').id
console.log(this.trainId)
let tr = document.querySelector('#'+trainId.replace('price','ticket'))
let yuding_btns = tr.querySelector('td:last-child a')//看有没有预定的btn
yuding_btns.click()
})
page.on('load',async () => {
await page.tap('#normalPassenger_0')
await page.tap('#submitOrder_id')
await page.tap('#qr_submit_id')
})
await browser.close();
})();
版权声明
本站部分原创文章,部分文章整理自网络。如有转载的文章侵犯了您的版权,请联系站长删除处理。如果您有优质文章,欢迎发稿给我们!联系站长:
愿本站的内容能为您的学习、工作带来绵薄之力。
评论