用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 Express框架中处理404页面一个方式
May 28 NodeJs
ubuntu下安装nodejs以及升级的办法
May 08 NodeJs
Nodejs如何搭建Web服务器
Mar 28 NodeJs
Windows 系统下设置Nodejs NPM全局路径
Apr 26 NodeJs
nodeJs链接Mysql做增删改查的简单操作
Feb 04 NodeJs
详解Nodejs之静态资源处理
Jun 05 NodeJs
nodejs中sleep功能实现暂停几秒的方法
Jul 12 NodeJs
NodeJS 中Stream 的基本使用
Jul 30 NodeJs
nodejs提示:cross-device link not permitted, rename错误的解决方法
Jun 10 NodeJs
nodejs文件夹深层复制功能
Sep 03 NodeJs
Nodejs + sequelize 实现增删改查操作
Nov 07 NodeJs
浅谈Node的内存泄露问题
May 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 删除无限级目录与文件代码共享
2008/11/22 PHP
如何使用Strace调试工具
2013/06/03 PHP
使用php统计字符串中中英文字符的个数
2013/06/23 PHP
PHP7扩展开发教程之Hello World实现方法示例
2017/08/03 PHP
Laravel5.5 手动分页和自定义分页样式的简单实现
2019/10/15 PHP
dojo 之基础篇(三)之向服务器发送数据
2007/03/24 Javascript
JS的递增/递减运算符和带操作的赋值运算符的等价式
2007/12/08 Javascript
JavaScript 学习笔记(六)
2009/12/31 Javascript
JS简单实现文件上传实例代码(无需插件)
2013/11/15 Javascript
鼠标经过出现气泡框的简单实例
2017/03/17 Javascript
vue-cli如何添加less 以及sass
2017/07/06 Javascript
基于vue-cli创建的项目的目录结构及说明介绍
2017/11/23 Javascript
浅谈React前后端同构防止重复渲染
2018/01/05 Javascript
详解React Native 屏幕适配(炒鸡简单的方法)
2018/06/11 Javascript
在vue中解决提示警告 for循环报错的方法
2018/09/28 Javascript
js闭包的9个使用场景
2020/12/29 Javascript
vue中实现点击空白区域关闭弹窗的两种方法
2020/12/30 Vue.js
用实例解释Python中的继承和多态的概念
2015/04/27 Python
Python2与python3中 for 循环语句基础与实例分析
2017/11/20 Python
python opencv设置摄像头分辨率以及各个参数的方法
2018/04/02 Python
python pygame实现滚动横版射击游戏城市之战
2019/11/25 Python
pytorch 获取tensor维度信息示例
2020/01/03 Python
python encrypt 实现AES加密的实例详解
2020/02/20 Python
在python中list作函数形参,防止被实参修改的实现方法
2020/06/05 Python
Python基于Socket实现简易多人聊天室的示例代码
2020/11/29 Python
使用canvas压缩图片大小的方法示例
2019/08/02 HTML / CSS
如何启动时不需输入用户名与密码
2014/05/09 面试题
自动化专业个人求职信范文
2013/11/29 职场文书
婚礼主持词
2014/03/13 职场文书
企业优秀团员事迹材料
2014/08/20 职场文书
茶楼服务员岗位职责
2015/02/09 职场文书
英语辞职信怎么写
2015/02/28 职场文书
2016年教师师德师风承诺书
2016/03/25 职场文书
解决jupyter notebook图片显示模糊和保存清晰图片的操作
2021/04/24 Python
HTML5页面音频自动播放的实现方式
2021/06/21 HTML / CSS
Python中np.random.randint()参数详解及用法实例
2022/09/23 Python