### 关于
nightmare是基于`electron`的一个自动化测试的套件,内置了浏览器,当然也可用于爬虫.我也分别对这两个功能进行了简单的测试.后续会深入研究.
[github地址](https://github.com/segmentio/nightmare)
### 简单操作,编写一个自动操作的demo
#### 安装
```js
npm i nightmare -S
```
#### ES6支持
1. 安装babel
```js
//安装三个babel套件
//分别是es6基础编译包,扩展支持包,运行环境包
npm i babel-register babel-polyfill babel-preset-env -D
```
2. 创建`.baberc`文件
```
{
"presets": ["env"]
}
```
3. 创建入口文件`index.js`
```js
//依赖babel
require("babel-register");
require("babel-polyfill");
require('测试demo的入口js文件')
```
#### 实现自动化浏览
以`http://demo.timepack.cn/web`为例:
1. 登录
```js
const login = async() => {
console.log('开始登录...', '>>>>>>>>')
await nm.goto('http://demo.timepack.cn/web');
await nm.click('.tab :nth-child(7)');
await nm.wait('#inputForm');
//输入用户名和密码
await nm.type('#account', 'xxxxx');
await nm.type('#password', 'xxxx');
//获取验证码
const code = await nm.evaluate(() => {
return document.querySelector('#v-code').innerText;
})
console.log(`code:${code}`)
await nm.type('#code', code);
//点击登录
await nm.click('.pw-loginBtn');
console.log('登录成功...', '>>>>>>>>');
}
```
2. 新建一个表单
```js
/**
* 新建活动
* @return {[type]} [description]
*/
const newActivity = async() => {
console.log('开始创建新的活动...', '>>>>>>>>');
await nm.wait(3000);
await nm.click('#activity_id');
await nm.wait('#activityList');
await nm.click('.title>.button');
await nm.wait('#inputForm');
await nm.type('#title', `${title}标题${new Date().getTime()}`);
await nm.type('#content', `${title}内容${new Date().getTime()}`);
await nm.type('#start', `2017-01-01`);
await nm.type('#end', `2017-12-31`);
await nm.type('#upperLimit', 188);
await nm.click('.personal-edit>a:first-child');
await nm.wait('#activityList');
console.log('创建活动完成...', '>>>>>>>>');
}
```
3. 退出
```js
const close = async() => {
console.log('测试完成...', '>>>>>>');
await nm.end();
}
```
4. 登录的超时和多次尝试操作
首先写个通用的方法:
```js
//多次执行函数方法
const runTimes = async(fn, times, timeout) => {
for (let i = 0; i < times; i++) {
try {
return await outTime(fn, timeout);
} catch (e) {
logger.warn(e.message);
}
}
}
//登录限时
const outTime = (fn, timeout) => {
return Promise.race([
fn(),
new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('操作超时了!!!'));
}, timeout);
})
])
}
export default {runTimes}
```
5. 运行方法
```js
const run = async() => {
await helper.runTimes(login, 3, 10000);
await newActivity();
await close();
}
run();
```
```js
//命令行运行则开始操作
node index.js
```
以上,Over!
* * * * *
### 爬虫使用
现在我们使用`nightmare`对百度图片进行爬虫操作.
首先,我们还需要`log4js`进行日志的记录(关于`log4js`强大的功能需要单独研究,这里我们简单的使用下吧!).
#### 包导入
```js
const Nightmare = require('nightmare')
const log4js = require('log4js');
const logger = log4js.getLogger();
logger.level = 'debug';
```
#### 配置文件
我们新建一个`config.js`,对我们需要的参数进行一些简单的预设.首先我们的目标是`website`,搜索关键词是`keywords`,这里指的是百度图片输入框内的内容,然后图片下载的主路径是`diskPath`.
关于`scroll`,预期我们发现百度图片采用了图片滚动懒加载,故我们需要模拟滚动条的动作,从而方便一次性获取更多的图片.
```js
export default {
website: 'http://image.baidu.com/',
diskPath: 'G:/images/',
keywords: '女明星',
scroll: {
start: 0,//滚动起始位置
step: 1024,//每次滚动的高度
times: 100,//滚动次数
interval: 100//滚动时间间隔
}
}
```
#### 图片下载
图片下载我们采用异步批量下载的方式,同时使用到了`bagpipe`插件,用来控制并发的数量.
```js
//下载图片
const download = (target, list) => {
if (!fs.existsSync(target)) {
logger.info('创建新的目录!');
fs.mkdirSync(target);
}
list.forEach((item, index) => {
var destImage = path.resolve(target, uuidV4() + '.jpg');//uuid用来重命名图片
bagpipe.push(saveImageFlie, item, destImage, function(err, data) {});
});
}
const saveImageFlie = (src, dest, callback) => {
request.head(src, function(err, res, body) {
if (src) {
request(src).pipe(fs.createWriteStream(dest)).on('close', function() {
logger.info(`第${index++}张图片下载完成`);
callback(null, dest);
});
}
});
};
```
#### 分析dom结构,获取图片列表
```js
const getImageList = async() => {
return await nm.evaluate(() => {
let elements = document.querySelectorAll('.main_img');
let result = [];
for (var i = 0; i < elements.length; ++i) {
var item = elements[i];
result.push(item.getAttribute('data-imgurl'));
}
return result;
});
}
```
#### 屏幕延时自动滚动
```js
//主要是图片有个加载时间,所以最好限定个延时
const autoSroll = async() => {
logger.debug(`开始滚动屏幕`);
for (let i = 0; i < config.scroll.times; i++) {
let newPos = config.scroll.start + config.scroll.step * i;
await outTime(newPos, config.scroll.interval);
}
}
const outTime = (pos, timeout = 500) => {
return Promise.all([
nm.scrollTo(pos, 0),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, timeout);
})
])
}
```
* 完整代码参考[github](https://github.com/MillZhang/Node/blob/master/crawler/pic.js)
#### 说明
这里获取的都是缩略图,需要获取更高清的图片,我们还需要通过图片点击进去,后续再研究.
<p class="over">Over!</p>
- 前端
- C1-Javascript
- H5图片分块和断点续传
- JavascriptPatterns[Stoyanstefanov]
- macotask和microtask
- 前端代码生成器
- 跨域
- 页面回到顶部滚动按钮实现
- C2-CSS
- 浏览器的一些单位
- 盒模型
- 移动端判断横竖屏
- C3-框架
- ReactNative
- 开发环境搭建(安卓篇)
- Vue
- vue+pdfjs使用
- vue+typescript使用实践
- vue+webpack3.x集成typescript
- Vue源码3
- vue源码分析1
- vue源码分析2
- vue笔记
- C4-工具
- git
- Gitlab-CICD
- mock规则
- vscode-settings
- webpack自定义命令,切换代理地址
- 正则表达式
- 深入浅出webpack
- C5-Node
- express
- express源码阅读
- nightmare使用指南
- 爬虫1.0
- C6-微信
- 微信
- C7-Canvas
- 基础API
- 前端随笔笔记
- 后端
- C1-Java
- shiro
- C2-Linux
- ffmpeg
- ITerm
- Linux
- MongoDB安装
- MySql安装
- Ngnix反向代理
- 常见错误
- 备忘
- mac
- 备忘-Work
- 备忘Link
- 服务器资源
- 教程
- Hexo个人博客搭建笔录
- 文档
- CSS编码规范
- 前端编码规范
- 随笔
- 整理
- 正则
- 链接收藏
- 面试
- CodeWars题库
- CodeWars题库(二)
- Java社招面试题
- Java面试
- Web面试
- 前端笔试题
- 笔试题