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,就是希望借助这种简洁模型的梳理,相对愉悦的实现自动化交互(至于标题,终归是意义过剩的产物,请忽略他的招摇。
打赏作者
您的支持将激励我继续创作!
666
能不能过验证码~
过防重复提交token~
之前spam太多,才用的这招
谢谢分享
这玩意好~ 试了下,页面里的js,可以在代码里用~
nightmare
.goto(url1)
.cookies.get()
.then(function(cookies) {
……
})
.goto(url2)
求解:
goto(url2) 为什么 执行不了
如何才能继续执行goto(url2)
不好意思,是.cookie.set()
nightmare
.url(url)
.cookies.set(cookie)
.then(function() {
console.log(‘setCookie’);
callback();
})
no console setCookie
.then()和.catch()是整个执行链的最后步骤,goto不能放在他后面
大神有没有window系统的
额搞定了,就是弹出来窗口之后,不知道怎么合理利用啊 大神有没有进一步的运用的教程啊
额,这东西挺简单的,剩下就是组合运用各种API了
请问一下我按照你自动登录并轮询的例子代码,为什么evaluate里面的循环点击的代码好像没有运行
index.html
title
window.onload=function () {
var username=document.querySelector(‘#username’)
var password=document.querySelector(‘#password’)
var submit=document.querySelector(‘#submit’)
submit.onclick=function () {
if(username.value===’username’&& password.value===’123456′){
window.location.href=’/main.html’
}
}
}
main.html
title
#inspector{
display: block;
}
防止挂机按钮
window.onload=function () {
var inspector=document.querySelector(‘#inspector’);
inspector.onclick=function () {
this.style.display=’none’;
setTimeout(function () {
inspector.style.display=’block’;
},2000)
}
}
test.js
let Nightmare = require(‘nightmare’)
let nightmare = new Nightmare({
show: true,
openDevTools: {
mode: ‘detach’
},
})
nightmare
.goto(‘http://localhost:4001/’)
.viewport(1024, 768)
.wait(1000)
.type(‘#username’, ‘username’)
.type(‘#password’, ‘123456’)
.click(‘#submit’)
.wait(1000)
.wait(‘#mainContent’)
.evaluate(() => {
/* eslint-disable */
function handle() {
// 一个叫inspector的button
var inspector = document.querySelector(‘#inspector’);
if (inspector && inspector.style.display === ‘block’) {
inspector.click();
}
}
setInterval(handle, 1000);
/* eslint-enable */
})
.evaluate(() => document.title)
.then(title => console.log(
${title} => 加载完成
)).catch(err => console.error(err))
这个怎么实现对接数据库
用nodeJS的方法实现不了 会报错
具体指什么方法?