Chromeless Demo

2017-11-28  本文已影响0人  ai8890

Chromeless 简介

Chrome 浏览器有一种模式叫做 Chrome Headless,在这种模式下,允许你正常运行 Chrome 浏览器,但是没有界面;想要调试这种模式下打开的网站,可以通过它提供的接口来实现,而 Chromeless 就是把这层接口做了封装,让你使用接口更方便。通过它,可以控制浏览器行为,如打开网站、点击按钮、填充表单、获取 DOM 元素...

可以用来做什么

1 . 可以获取网页截图
2 . 根据页面 document 文档生成 PDF 文件
3 . 编写测试代码,自动化测试网页
4 . 基于真实的浏览器环境,可以编写爬虫程序

安装

首先要安装支持 Chrome Headless 模式的浏览器。目前,Mac 上 Chrome 59 beta
版本与 Linux 上的 Chrome 57+ 已经开始支持 headless 特性。Windows 上 Chrome 暂时不支持,可以使用 Chrome Canary 60 进行开发。
下面是 Ubuntu17.10 的无界面浏览器启动命令示例:

google-chrome \
--remote-debugging-port=9222 \
--disable-gpu \
--no-sandbox  \
--headless

Chromeless 用 NodeJS 编写,要求 NodeJS 版本8.2+,安装:
npm install chromeless

如何用于网页测试

const { Chromeless } = require('chromeless')
const { expect }  = require('chai')

async function run(){
    const chromeless = new Chromeless()
    const firstPage= await chromeless
        .goto('http://www.w3school.com.cn')
        .wait('#navsecond')
        .evaluate(() => {
              // this will be executed in Chrome
              const links = [].map.call(
                document.querySelectorAll('#navsecond ul:nth-child(2) li'),
                a => (a.innerText.trim())
              )
              return links
            })
expect(firstPage).to.have.members(["JS","HTML5","XHTML","CSS","CSS3","TCP/IP"])
await chromeless.end()
}
# 运行并捕捉错误
run().catch(console.error.bind(console))

这里用到了 Chai 断言库,代码实现的功能是验证 W3school 网站首页,左侧第一个 ul 列表的内容是否包含以下内容: JS、HTML5、XHTML、CSS、CSS3、TCP/IP"。
命令详解:
goto:打开加载网站 http://www.w3school.com.cn
wait:等待指定的元素 #navsecond(这是 CSS selector) 渲染成功之后才往下执行;
evaluate:会将里面的 JS 代码送到 浏览器中执行,并获取返回结果;
运行结果:

图一:网页测试Demo结果

如何爬取 Google Search Result

下面代码实现的功能是使用 Google Search 搜索关键字,并返回结果的 Title 和链接地址。
查看执行结果

const { Chromeless } = require('chromeless');

async function run(){
    const chromeless = new Chromeless()
    const firstPage= await chromeless
        .goto('https://www.google.com')
        .wait('input[name="q"]')
        .type('云纵', 'input[name="q"]')
        .press(13) // press enter
        .wait('#foot')
        
    let hasNextPage = true
    let page = 1
    let result = null
    while (hasNextPage){
        if(page===1){
            result = await chromeless
                .evaluate(() => {
                  // this will be executed in Chrome
                  const links = [].map.call(
                    document.querySelectorAll('.g h3 a'),
                    a => ({title: a.innerText, href: a.href})
                  )
                  return links
                })
        }else{
            result = await chromeless
                .scrollTo(200,400)
                .scrollToElement('#foot td:nth-last-child(1)')
                .click('#foot td:nth-last-child(1)')
                .wait(2000)
                .wait('#foot')
                .evaluate(() => {
                              // this will be executed in Chrome
                              const links = [].map.call(
                                document.querySelectorAll('.g h3 a'),
                                a => ({title: a.innerText, href: a.href})
                              )
                              return links
                            })
        }
        console.log(result)
        hasNextPage = await chromeless.evaluate(() => {
              let nextPage =  document.querySelector('#foot td:nth-last-child(1)').innerText
              //return (nextPage==='Next')
              return nextPage.length
            })
        console.log(`第${page}页`)
        console.log(hasNextPage ? '存在下一页' : '不存在下一页')
        page++
    }
    await chromeless.end()
}

run().catch(console.error.bind(console))

命令解释:
.type('云纵', 'input[name="q"]'): 在 CSS 选择器 input[name="q"] 选中的元素(实际上就是 Google Search 搜索框)内输入’云纵‘两个字;
.press(13) :按下键盘的 Enter 键,就是在搜索框输入文字后执行查询;
.scrollTo(200,400) :滚动到距离页面左侧200px,右侧400px的位置;
.scrollToElement('#foot td:nth-last-child(1)'):滚动到 CSS 选择器 #foot td:nth-last-child(1) 选中元素(实际是 Google Search Result 的下一页链接),使元素可见;
.click('#foot td:nth-last-child(1)'):点击元素;
.wait(2000):参数是数字时,表示等待时间,参数是 CSS 选择器时表示等待元素渲染完成;

Async 与 Await

开发时要注意这两个关键字 async 和 await,使用 Chromeless,会用到他们,这是 ES7 实现的异步方案,需要了解以下内容:
1 . function 前面的 async 标识符表示函数内有异步操作;
2 . await 强调后面的异步操作执行完成后才能继续;
3 . await 只能用在async标识的函数内;
4 . await 后写非异步操作也可以,会直接执行

参考资料

1 . 体验异步的终极解决方案-ES7的Async/Await
2 . 初探 Headless Chrome

上一篇下一篇

猜你喜欢

热点阅读