Puppeteer自动化测试鼠标键盘基本操作及注意事项

通过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

你可能感兴趣的:(爬虫数据抓取,puppeteer,爬虫与反爬虫)