### 關于
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面試
- 前端筆試題
- 筆試題