用Electron写个带界面的nodejs爬虫

论坛 期权论坛 脚本     
匿名网站用户   2020-12-19 17:12   24   0

什么是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下来
文件目录

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

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

yarn https://yarn.bootcss.com/

cd 到 目录下

cnpm install yarn
yarn

等待依赖安装完成。

npm run start

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

这里写图片描述


界面编写

准备完毕,开始进入正题。
用vscode打开文件夹,顺带一提,vscode也是基于electron。vscode不愧是巨硬出品,越来越好用了。
整理一下
这里写图片描述

这里就不累赘了。
后台有多个小号要登录,就写个登录页面。
编辑一下index.html

<html>
<head>
  <meta charset="utf-8">
  <link href="http://apps.bdimg.com/libs/bootstrap/3.3.4/css/bootstrap.min.css" 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

就可以看到我们刚刚写的网页了
这里写图片描述

下载验证码

登录是需要验证码的,我们把验证码下载下来。
流程是 请求验证码网站,下载验证码保存到本地显示,验证码的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

运行一下
这里写图片描述

这里写图片描述

很好,我们要的验证码和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
这里写图片描述

模拟登录

我们需要登录后台,获取登录后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);
});

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

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP