多应用+插件架构,代码干净,支持一键云编译,码云点赞13K star,4.8-4.12 预售价格198元 广告
通过Puppeteer Api来控制Chrome进行数据抓取或自动化测试通常模拟鼠标或键盘的操作。 接下来通过一些实例来介绍这些基本操作。后文的代码演示环境如下: 1. headless均设置为false即有界面状态下测试 2. puppeteer版本0.1.7 3. chrome版本5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3514.2 Safari/537.36 ## 鼠标移动 进入baidu首页,模拟鼠标移动到更多产品按钮下。 主要流程: 1. 获取更多产品按钮对象,page.$(“#u1 > a.bri”) 2. 通过element.boundingBox()拿到坐标参数 3. 移动鼠标page.mouse.move(x,y) ``` (async () => { let browser = await puppeteer.launch({headless: false}); let page = await browser.newPage(); let response = await page.goto("https://www.baidu.com/"); await page.waitFor(1000); let element = await page.$("#u1 > a.bri"); let box = await element.boundingBox(); const x = box.x + (box.width/2); const y = box.y + (box.height/2); await page.mouse.move(x,y); await page.waitFor(10000); await page.close(); await browser.close(); } )(); ``` ## 鼠标拖拽 进入baidu地图首页进行拖拽模拟。由于puppeteer并未直接提供拖动api,因此拖动通过按下鼠标、移动鼠标、松开鼠标这三个操作来模拟。运行如下的拖拽操作会看到地图发生拖动。 ``` (async () => { let browser = await puppeteer.launch({headless: false}); let page = await browser.newPage(); let response = await page.goto("https://map.baidu.com/"); await page.waitFor(1000); await page.mouse.move(500,400); await page.mouse.down(); await page.mouse.move(100,200,{steps:1000}); await page.mouse.up(); await page.waitFor(10000); await page.close(); await browser.close(); } )(); ``` ## 鼠标单击 这次我们进入百度首页,单机新闻连接,并获取跳转后页面的html代码。示例代码如下。 ``` (async () => { const browser = await puppeteer.launch({headless: false}); const page = await browser.newPage(); const response = await page.goto("https://www.baidu.com/"); const searchButton = await page.$("#u1 > a:nth-child(1)"); const box = await searchButton.boundingBox(); const x = box.x + (box.width/2); const y = box.y + (box.height/2); const r = await Promise.all([ page.mouse.click(x,y), page.waitForNavigation() ]); const content = await page.content(); console.log(content); await page.waitFor(20000); } )(); ``` 单击链接会触发页面跳转,当单机后直接尝试通过page.content()获取页面内容会出现异常(观察该效果可将例子中page.waitForNavigation()注释) > UnhandledPromiseRejectionWarning: Error: Execution context was destroyed, most likely because of a navigation. 因此需要调用page.waitForNavigation()等待页面跳转完毕,然后在调用page.content()才能正常获取页面内容。 ## 键盘按键 这个例子中,首先进入我的博客首页https://blog.csdn.net/Revivedsun,然后在输入框中输入搜索文字,随后按下回车。按下回车后会接着打开一个新的标签页,我们将获取这个标签页的html文本。首先完整例如下。 ``` function getNewPageWhenLoaded(browser) { return new Promise((x) => browser.once('targetcreated', async (target) => { const newPage = await target.page(); const newPagePromise = new Promise(() => newPage.once('domcontentloaded', () => x(newPage))); const isPageLoaded = await newPage.evaluate(() => document.readyState); return isPageLoaded.match('complete|interactive') ? x(newPage) : newPagePromise; })); } (async () => { const browser = await puppeteer.launch({headless: false}); const page = await browser.newPage(); const response = await page.goto("https://blog.csdn.net/Revivedsun"); const elementHandler = await page.$("#csdn-toolbar > div > div > ul > li:nth-child(2) > div > a"); await page.focus("input#toolber-keyword"); await page.keyboard.type("Puppeteer",{delay:100}); const newPagePromise = getNewPageWhenLoaded(browser); await page.keyboard.press("Enter",{delay:50}); const newPage = await newPagePromise; const content = await newPage.content(); console.log(content); } )(); ``` 打开新标签页后需要获取新标签页的对象,这时通过监听事件targetcreated来实现。当事件targetcreated发生后,在回调中获取page页标签对象,随后监听domcontentloaded事件,等待页面加载完毕,一旦加载完毕,调用Promise构造函数中的resolve方法,将页标签对象传递给调用方。若未加载完毕,则将返回Promise对象。状态检测通过document.readyState来获取。 ``` function getNewPageWhenLoaded(browser) { return new Promise((x) => browser.once('targetcreated', async (target) => { const newPage = await target.page(); const newPagePromise = new Promise(() => newPage.once('domcontentloaded', () => x(newPage))); const isPageLoaded = await newPage.evaluate(() => document.readyState); return isPageLoaded.match('complete|interactive') ? x(newPage) : newPagePromise; })); } ``` 这种方法可以获得新打开标签页对象。此外页可以尝试修改target属性为_selft,在当前页打开新页面。这是使用“键盘按键“小节中介绍的方法获取新跳转页面html内容即可。 属性修改示例如下。 ``` const elementHandler = await page.$(cssSelector); await page.evaluateHandle((e) => { e.target = '_self' } ,elementHandler); ``` # 参考 1. target属性修改, https://github.com/GoogleChrome/puppeteer/issues/386#issuecomment-343059315 2. 键盘按键表 https://github.com/GoogleChrome/puppeteer/blob/v1.7.0/lib/USKeyboardLayout.js 3. 事件监听获取新打开标签对象, https://github.com/GoogleChrome/puppeteer/issues/386 --------------------- 作者:FserSuN 原文:https://blog.csdn.net/revivedsun/article/details/82121123