用Electron写个带界面的nodejs爬虫的实现方法


Posted in NodeJs onJanuary 29, 2019

什么是Electron

使用 JavaScript, HTML 和 CSS 构建跨平台的桌面应用

[官网](https://electronjs.org/)

实质就是一个精简的Webkit浏览器显示html页面,通过electron做中间层可以和系统交流。给web项目套上一个node环境的壳。

前言

公司买的推广居然没有后台的api,没有api又不想死板手动操作。那就做个爬虫吧。但是又是给小白用的,自然最好带个界面,本来用C#拖出来就好了,看到vs那么大,下载都要半天。干脆就用Electron做一个,顺便学习一下Electron。

准备工作

安装nodejs

npm安装electron(最好换成cnpm,不然可能失败)

hello world

官方提供了快速开始的手脚架,怎么方便怎么来。

https://github.com/atom/electron-quick-start

clone下来

用Electron写个带界面的nodejs爬虫的实现方法

git那些不是我们需要的,就删掉。

安装相关的依赖,推荐用yarn。

yarn https://yarn.bootcss.com/

cd 到 目录下

cnpm install yarn
yarn

等待依赖安装完成。

npm run start

顺利的话就可以看到程序启动。

用Electron写个带界面的nodejs爬虫的实现方法

界面编写

准备完毕,开始进入正题。

用vscode打开文件夹,顺带一提,vscode也是基于electron。vscode不愧是巨硬出品,越来越好用了。

整理一下

用Electron写个带界面的nodejs爬虫的实现方法

这里就不累赘了。

后台有多个小号要登录,就写个登录页面。

编辑一下index.html

<html>
<head>
 <meta charset="utf-8">
 <link href="http://apps.bdimg.com/libs/bootstrap/3.3.4/css/bootstrap.min.css" rel="external nofollow" rel="stylesheet">
</head>
<body>
 <div class="panel panel-default" style="margin: 10px">
  <div class="panel-body">
   <div class="form-horizontal" role="form">
    <div class="form-group">
     <label for="input_name" class="col-sm-2 control-label">登录帐号</label>
     <div class="col-sm-10">
      <input type="text" class="form-control" id="input_name" placeholder="请输入用户名">
     </div>
    </div>
    <div class="form-group">
     <label for="input_pass" class="col-sm-2 control-label">登录密码</label>
     <div class="col-sm-10">
      <input type="password" class="form-control" id="input_pass" placeholder="请输入登录密码">
     </div>
    </div>
    <div class="form-group">
     <label for="input_check" class="col-sm-2 control-label">验证码:</label>
     <div class="col-sm-6">
      <input type="text" class="form-control" id="input_check" placeholder="请输入验证码">
     </div>
     <div class="col-sm-2">
      <img id="img_code" src="code.png" />
     </div>
    </div>
    <div class="form-group">
     <div class="col-sm-offset-2 col-sm-2">
      <button id="btn_submit" class="btn btn-default">登录</button>
     </div>
     <div class="col-sm-2">
      <button id="btn_refresh" class="btn btn-default">刷新验证码</button>
     </div>
    </div>
   </div>
  </div>
 </div>
 <script>
  require('./index.js');
 </script>
</body>
</html>

都是些 很简单的html代码,为了好看的就用了bootstrap

electron可以调用bootstap、jquery ,方便开发。调用jq有个小小的坑,注意一下。

不过我这里不需要什么效果,就简单点。

在vscode 快捷键 Ctrl + ` 调出 CMD 运行一下

npm run start

就可以看到我们刚刚写的网页了

用Electron写个带界面的nodejs爬虫的实现方法

下载验证码

登录是需要验证码的,我们把验证码下载下来。

流程是 请求验证码网站,下载验证码保存到本地显示,验证码的cookie保存下来,后面登录时候需要用到cookie

安装需要的依赖 superagent , fs-extra

编辑 main.js

const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow

const path = require('path')
const url = require('url')
// 爬虫
const superagent = require('superagent');
// 操作文件
const fs = require('fs-extra');

let mainWindow
// 验证码的cookie
var codeCookie
// 验证码网址
const codeUrl = '验证码地址';
// 头信息
const browserMsg = {
 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36',
 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
};

function createWindow() {
 mainWindow = new BrowserWindow({
  width: 800,
  height: 600
 })
 superagent
  .get(codeUrl)
  .set(browserMsg)
  .end((err, res) => {
   codeCookie = res.header['set-cookie']
   console.log('codeCookie: ' + codeCookie)
   // 验证码图片保存到本地
   fs.outputFile(path.join(__dirname) + '/code.png', res.body, function (err) {})
  })
 mainWindow.loadURL(url.format({
  pathname: path.join(__dirname, 'index.html'),
  protocol: 'file:',
  slashes: true
 }))
 // 打开调试控制台
 mainWindow.webContents.openDevTools()

 mainWindow.on('closed', function () {
  mainWindow = null
 })

}
app.on('ready', createWindow)

app.on('window-all-closed', function () {
 if (process.platform !== 'darwin') {
  app.quit()
 }
})

app.on('activate', function () {
 if (mainWindow === null) {
  createWindow()
 }
})

说一下安装的依赖

fs-extra fs-extra模块是系统fs模块的扩展,提供了更多便利的 API,并继承了fs模块的 API。

主角就是 superagent https://www.npmjs.com/package/superagent

运行一下

用Electron写个带界面的nodejs爬虫的实现方法

用Electron写个带界面的nodejs爬虫的实现方法

很好,我们要的验证码和cookie 都有了。

分析登录流程

用 Fiddler 抓包工具和浏览器的调试控制台分析一下后台的登录。

这里不是重点就略过了。

Electron 通信

渲染进程(就是网页) 登录 需要 主进程保存的codeCookie ,这就要两者进行通信。

Electron之间的通信是用ipc

主进程的是 ipcMain 也可以用 mainWindow.webContents来发送

渲染进程的是 ipcRenderer

这里演示一下 主进程发送cookie 给 渲染进程

main.js 文件

const ipcMain = electron.ipcMain;
ipcMain.on('notice', (e, msg) => {
 switch (msg) {
  case 'getcodeCookie':
   mainWindow.webContents.send('codeCookie',codeCookie)
   break
  default:
   break
 }
})

打开调试控制台 可以看到输出

index.js

const electron = require('electron');
const ipcRenderer = electron.ipcRenderer;
// 获取控件
let btn_submit = document.getElementById("btn_submit");
btn_submit.addEventListener('click', (e) => {
  ipcRenderer.send('notice', 'getcodeCookie');
});
// 监听 codeCookie
ipcRenderer.on('codeCookie', (e, msg) => {
  codeCookie = msg;
  console.log('接受主进程发送的codeCookie: '+codeCookie);
});

运行一下, 点击登录按钮

就可以在调试控制台看到 codeCookie

用Electron写个带界面的nodejs爬虫的实现方法

模拟登录

我们需要登录后台,获取登录后cookie这样才方便我们操作。

编辑index.js

const electron = require('electron');
const ipcRenderer = electron.ipcRenderer;
const path = require('path');
const superagent = require('superagent');

// 链接
const urls = {
  loginUrl: "登录的地址",
  codeUrl: "验证码地址",
  targetUrl: "后台的地址"
};

// 头信息
const browserMsg = {
  "User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36",
  'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
};
// 验证码cookie
var codeCookie;
// 登录后的cookie
var tokenCookie;

// 获取控件
const btn_submit = document.getElementById("btn_submit");
const btn_refresh = document.getElementById("btn_refresh");
const input_name = document.getElementById("input_name");
const input_pass = document.getElementById("input_pass");
const input_code = document.getElementById("input_code");

// 登录按钮 点击事件
btn_submit.addEventListener('click', (e) => {
  ipcRenderer.send('notice', 'getcodeCookie');
  // 获取输入文本
  var name = input_name.value;
  var pass = input_pass.value;
  var code = input_check.value;
  // 校验输入
  if (name == "" || pass == "" || code == "") {
    alert("请输入");
  } else {
    // 校验通过 开始进行登录操作
    superagent
      .post(urls.loginUrl)
      .set('Cookie', codeCookie)
      .set(browserMsg)
      // 避免登录后的302重定向
      .redirects(0)
      .send({
        'LoginForm[username]': name
      }).send({
        'LoginForm[password]': pass
      }).send({
        logincode: code
      }).send({
        jz: '0'
      }).end((err, res) => {
        // 登录成功 获取tokenCookie
        // 获取tokenCookie
        tokenCookie = res.header['set-cookie'];
        superagent
          .get(urls.targetUrl)
          .set('Cookie',tokenCookie)
          .set(browserMsg)
          .end((err,res)=>{
            // 成功进入后台
            console.log(res.text);
          })
      });
  }

});

btn_refresh.addEventListener('click', (e) => {

});

ipcRenderer.on('codeCookie', (e, msg) => {
  codeCookie = msg;
  console.log('接受主进程发送的codeCookie: ' + codeCookie);
});

这里只是演示一下代码怎么写,具体不一定那么顺利的拿到tokenCookie。具体情况具体分析。

关键是请求要带上cookie

数据抓取

成功进入到后台了,就要抓取需要的数据了。这里就需要 cheerio 工具了

cheerio https://cheerio.js.org/

可以理解是node上jq , 操作基本跟jq是一样的。

操作还是很简单的。

要注意的是nodejs是异步的,就连for也是异步的。

有时候要等待请求完成的话,就要用上 async 了。

导出xlsx表格

爬虫基本完成了,怎么导出数据就随意了。

如果是要生成xls表格,一般是用excel-export 简单够用

我这里推荐 另一个 better-xlsx 。

这里演示一下 , 怎么调用系统的保存对话框,保存文件。

编辑 index.js

const remote = electron.remote;

btn_refresh.addEventListener('click', (e) => {

  const filepath =remote.dialog.showSaveDialog(remote.getCurrentWindow(), {
    // 过滤文件类型
    filters: [{
      name: "xls Files",
      extensions: ['xlsx']
    },
    {
      name: 'All Files',
      extensions: ['*']
    }
  ]
  });
  console.log(filepath);
});

运行一下,点击刷新验证码按钮就可以看到熟悉的系统对话框

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

NodeJs 相关文章推荐
NodeJS中Buffer模块详解
Jan 07 NodeJs
NodeJs基本语法和类型
Feb 13 NodeJs
nodejs+express实现文件上传下载管理网站
Mar 15 NodeJs
nodejs爬虫遇到的乱码问题汇总
Apr 07 NodeJs
NodeJs安装npm包一直失败的解决方法
Apr 28 NodeJs
nodejs socket实现的服务端和客户端功能示例
Jun 02 NodeJs
nodejs中函数的调用实例详解
Oct 31 NodeJs
手把手教你如何使用nodejs编写cli命令行
Nov 05 NodeJs
NodeJS实现同步的方法
Mar 02 NodeJs
nodejs log4js 使用详解
May 31 NodeJs
nodejs对mongodb数据库的增加修删该查实例代码
Jan 05 NodeJs
nodejs nedb 封装库与使用方法示例
Feb 06 NodeJs
NVM安装nodejs的方法实用步骤
Jan 16 #NodeJs
nodeJS进程管理器pm2的使用
Jan 09 #NodeJs
NodeJS模块与ES6模块系统语法及注意点详解
Jan 04 #NodeJs
nodejs 使用http进行post或get请求的实例(携带cookie)
Jan 03 #NodeJs
详解nodejs 配置文件处理方案
Jan 02 #NodeJs
nodejs基础之多进程实例详解
Dec 27 #NodeJs
nodejs基础之常用工具模块util用法分析
Dec 26 #NodeJs
You might like
深入PHP中的HashTable结构详解
2013/06/13 PHP
TP框架实现上传一张图片和批量上传图片的方法分析
2020/04/23 PHP
关于javascript中this关键字(翻译+自我理解)
2010/10/20 Javascript
Jquery显示、隐藏元素以及添加删除样式
2013/08/09 Javascript
Extjs3.0 checkboxGroup 动态添加item实现思路
2013/08/14 Javascript
jQuery标签替换函数replaceWith()的使用例子
2014/08/28 Javascript
详谈JavaScript内存泄漏
2014/11/14 Javascript
Vue.js常用指令汇总(v-if、v-for等)
2016/11/03 Javascript
ajax级联菜单实现方法实例分析
2016/11/28 Javascript
AngularJS路由删除#符号解决的办法
2017/09/28 Javascript
vue mint-ui学习笔记之picker的使用
2017/10/11 Javascript
vue组件生命周期详解
2017/11/07 Javascript
layui的layedit富文本赋值方法
2019/09/18 Javascript
详解vuejs中执行npm run dev出现页面cannot GET/问题
2020/04/26 Javascript
浅谈JS for循环中使用break和continue的区别
2020/07/21 Javascript
[04:04]显微镜下的DOTA2第六期——电影级别的华丽团战
2014/06/20 DOTA
详解Python中的正则表达式的用法
2015/04/09 Python
Tornado协程在python2.7如何返回值(实现方法)
2017/06/22 Python
Python基于TCP实现会聊天的小机器人功能示例
2018/04/09 Python
python实现比较文件内容异同
2018/06/22 Python
OpenCV 边缘检测
2019/07/10 Python
利用rest framework搭建Django API过程解析
2019/08/31 Python
python进程间通信Queue工作过程详解
2019/11/01 Python
爬虫代理的cookie如何生成运行
2020/09/22 Python
Python WebSocket长连接心跳与短连接的示例
2020/11/24 Python
python 实现Harris角点检测算法
2020/12/11 Python
让IE9以下版本的浏览器兼容HTML5的方法
2014/03/12 HTML / CSS
历史学专业求职信
2014/06/19 职场文书
无财产无子女离婚协议书范文
2014/09/14 职场文书
五年级下册复习计划
2015/01/19 职场文书
办公室主任个人总结
2015/02/28 职场文书
2015年个人审计工作总结
2015/04/07 职场文书
单位计划生育责任书
2015/05/09 职场文书
护士业务学习心得体会
2016/01/25 职场文书
浅谈node.js中间件有哪些类型
2021/04/29 Javascript
python中filter,map,reduce的作用
2022/06/10 Python