爬蟲的終極形態:nightmare
nightmare 是一個基於 electron 的自動化庫(意思是說它自帶瀏覽器),用於實現爬蟲或自動化測試。相較於傳統的爬蟲框架(scrapy/pyspider),或者dom操作庫(cheerio/jsdom),或者基於瀏覽器的自動化框架(selenium/phantomjs),他的優勢在於提供了一個簡潔有效 的編程模型。
來看官網給出的一個對比場景:
同樣是實現一個向yahoo自動提交關鍵詞並搜索的功能
1. PhantomJS實現
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
phantom.create(function (ph) {
ph.createPage(function (page) {
page.open('http://yahoo.com', function (status) {
page.evaluate(function () {
var el =
document.querySelector('input[title="Search"]');
el.value = 'github nightmare';
}, function (result) {
page.evaluate(function () {
var el = document.querySelector('.searchsubmit');
var event = document.createEvent('MouseEvent');
event.initEvent('click', true, false);
el.dispatchEvent(event);
}, function (result) {
ph.exit();
});
});
});
});
});
|
2. nightmare實現
1
2
3
4
|
yield Nightmare()
.goto('http://yahoo.com')
.type('input[title="Search"]', 'github nightmare')
.click('.searchsubmit');
|
怎么玩
安裝
1
|
yarn add nightmare
|
涉及到下載並編譯一個electron,你國網速下需耐心等待
配置 options
1
2
3
4
5
6
7
|
openDevTools: {
mode: 'bottom', // 開發者工具位置:right, bottom, undocked, detach
},
show: true, // 要不要顯示瀏覽器
dock: true, // 要不要在Dock上顯示圖標
waitTimeout: 60000, // .wait() 方法超時時長,單位:ms
executionTimeout: 86400000, // .evaluate() 方法超時時長,單位:ms
|
實例化
1
2
|
import Nightmare from 'nightmare'
const nightmare = new Nightmare(options)
|
交互用的API
簡單介紹幾個:
.goto(url[, headers])
跳轉到url.viewport(width, height)
瀏覽器窗口大小.wait(selector)
等待某個dom元素出現.click(selector)
點擊某個dom元素.type(selector[, text])
在某個dom元素中輸入.inject(type, file)
在頁面上掛載 js/css 文件內容.evaluate(fn[, arg1, arg2,...])
在客戶端注入JS腳本並執行,從而實現electron模型下的C/S互動及數據交換- ……
自動登錄並輪詢的例子
有那么一個網站(比如叫chagang.site),在我登錄進去后,會不定時的查崗,需要點擊一個按鈕以證明沒有離線,怎么用nightmare實現自動掛機呢?
大概分這么幾步走:
- 先跳轉到該網站
- 模擬輸入帳號信息后點擊submit
- 登錄后等待主界面加載出現
- 在客戶端起一個定時器,2秒一次輪詢那個查崗按鈕,發現就模擬點擊
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
nightmare
.goto('http://chagang.site/')
.viewport(1024, 768)
.cookies.clearAll()
.type('#username', '用戶名')
.type('#password', '密碼')
.click('input[type=submit]')
.wait('#mainContent')
.evaluate(() => {
/* eslint-disable */
function handle() {
// 一個叫inspector的button
var inspector = document.querySelector('#inspector');
if (inspector && inspector.style.visibility === 'visible') {
inspector.click();
}
}
setInterval(handle, 2000);
/* eslint-enable */
})
.evaluate(() => document.title)
.then(title => console.log(`${title} => 加載完成`))
.catch(err => console.error(err))
|
好像也沒有多難
小結
本文只涉及到API中的一小部分,寶貝都在文檔里。用 nightmare,就是希望借助這種簡潔模型的梳理,相對愉悅的實現自動化交互(至於標題,終歸是意義過剩的產物,請忽略他的招搖。