用Electron写个带界面的nodejs爬虫的实现方法
什么是electron
使用 javascript, html 和 css 构建跨平台的桌面应用
[官网]()
实质就是一个精简的webkit浏览器显示html页面,通过electron做中间层可以和系统交流。给web项目套上一个node环境的壳。
前言
公司买的推广居然没有后台的api,没有api又不想死板手动操作。那就做个爬虫吧。但是又是给小白用的,自然最好带个界面,本来用c#拖出来就好了,看到vs那么大,下载都要半天。干脆就用electron做一个,顺便学习一下electron。
准备工作
安装nodejs
npm安装electron(最好换成cnpm,不然可能失败)
hello world
官方提供了快速开始的手脚架,怎么方便怎么来。
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="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
就可以看到我们刚刚写的网页了
下载验证码
登录是需要验证码的,我们把验证码下载下来。
流程是 请求验证码网站,下载验证码保存到本地显示,验证码的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); });
运行一下,点击刷新验证码按钮就可以看到熟悉的系统对话框
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 笔记本名词解析之3G、TD、WCDMA