Chromeless Demo

Chromeless 簡介

Chrome 瀏覽器有一種模式叫做 Chrome Headless,在這種模式下躲舌,允許你正常運行 Chrome 瀏覽器,但是沒有界面;想要調(diào)試這種模式下打開的網(wǎng)站绍绘,可以通過它提供的接口來實現(xiàn),而 Chromeless 就是把這層接口做了封裝迟赃,讓你使用接口更方便陪拘。通過它,可以控制瀏覽器行為纤壁,如打開網(wǎng)站左刽、點擊按鈕、填充表單酌媒、獲取 DOM 元素...

可以用來做什么

1 . 可以獲取網(wǎng)頁截圖
2 . 根據(jù)頁面 document 文檔生成 PDF 文件
3 . 編寫測試代碼欠痴,自動化測試網(wǎng)頁
4 . 基于真實的瀏覽器環(huán)境,可以編寫爬蟲程序

安裝

首先要安裝支持 Chrome Headless 模式的瀏覽器秒咨。目前喇辽,Mac 上 Chrome 59 beta
版本與 Linux 上的 Chrome 57+ 已經(jīng)開始支持 headless 特性。Windows 上 Chrome 暫時不支持拭荤,可以使用 Chrome Canary 60 進(jìn)行開發(fā)茵臭。
下面是 Ubuntu17.10 的無界面瀏覽器啟動命令示例:

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

Chromeless 用 NodeJS 編寫,要求 NodeJS 版本8.2+舅世,安裝:
npm install chromeless

如何用于網(wǎng)頁測試

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 斷言庫旦委,代碼實現(xiàn)的功能是驗證 W3school 網(wǎng)站首頁,左側(cè)第一個 ul 列表的內(nèi)容是否包含以下內(nèi)容: JS雏亚、HTML5缨硝、XHTML、CSS罢低、CSS3查辩、TCP/IP"。
命令詳解:
goto:打開加載網(wǎng)站 http://www.w3school.com.cn网持;
wait:等待指定的元素 #navsecond(這是 CSS selector) 渲染成功之后才往下執(zhí)行宜岛;
evaluate:會將里面的 JS 代碼送到 瀏覽器中執(zhí)行,并獲取返回結(jié)果功舀;
運行結(jié)果:

圖一:網(wǎng)頁測試Demo結(jié)果

如何爬取 Google Search Result

下面代碼實現(xiàn)的功能是使用 Google Search 搜索關(guān)鍵字,并返回結(jié)果的 Title 和鏈接地址辟汰。
查看執(zhí)行結(jié)果

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 搜索框)內(nèi)輸入’云縱‘兩個字;
.press(13) :按下鍵盤的 Enter 鍵戴而,就是在搜索框輸入文字后執(zhí)行查詢凑术;
.scrollTo(200,400) :滾動到距離頁面左側(cè)200px,右側(cè)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):參數(shù)是數(shù)字時姻檀,表示等待時間命满,參數(shù)是 CSS 選擇器時表示等待元素渲染完成;

Async 與 Await

開發(fā)時要注意這兩個關(guān)鍵字 async 和 await绣版,使用 Chromeless胶台,會用到他們,這是 ES7 實現(xiàn)的異步方案诈唬,需要了解以下內(nèi)容:
1 . function 前面的 async 標(biāo)識符表示函數(shù)內(nèi)有異步操作;
2 . await 強(qiáng)調(diào)后面的異步操作執(zhí)行完成后才能繼續(xù)铸磅;
3 . await 只能用在async標(biāo)識的函數(shù)內(nèi)杭朱;
4 . await 后寫非異步操作也可以阅仔,會直接執(zhí)行

參考資料

1 . 體驗異步的終極解決方案-ES7的Async/Await
2 . 初探 Headless Chrome

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末八酒,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子刃唐,更是在濱河造成了極大的恐慌,老刑警劉巖衔瓮,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抖甘,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)碍现,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門米奸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人慢睡,你說我怎么就攤上這事∑” “怎么了棕硫?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哈扮。 經(jīng)常有香客問我,道長滑肉,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任问畅,我火速辦了婚禮六荒,結(jié)果婚禮上护姆,老公的妹妹穿的比我還像新娘恬吕。我一直安慰自己,他們只是感情好铐料,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著柒凉,像睡著了一般篓跛。 火紅的嫁衣襯著肌膚如雪膝捞。 梳的紋絲不亂的頭發(fā)上愧沟,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天鲤遥,我揣著相機(jī)與錄音林艘,去河邊找鬼。 笑死狐援,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的啥酱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼镶殷,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了宇植?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤指郁,失蹤者是張志新(化名)和其女友劉穎拷呆,沒想到半個月后闲坎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體茬斧,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年绣溜,在試婚紗的時候發(fā)現(xiàn)自己被綠了娄蔼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡岁诉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出涕癣,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布炼列,位于F島的核電站音比,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏硅确。R本人自食惡果不足惜明肮,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一菱农、第九天 我趴在偏房一處隱蔽的房頂上張望柿估。 院中可真熱鬧,春花似錦秫舌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽墨缘。三九已至,卻和暖如春宽涌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卸亮。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工玩裙, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留兼贸,地道東北人献酗。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像罕偎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354