经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » JavaScript » 查看文章
用Electron写个带界面的nodejs爬虫的实现方法
来源:jb51  时间:2019/1/31 9:04:39  对本文有异议

什么是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。

  1. yarn https://yarn.bootcss.com/

cd 到 目录下

  1. cnpm install yarn
  2. yarn

等待依赖安装完成。

  1. npm run start

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

界面编写

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

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

整理一下

这里就不累赘了。

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

编辑一下index.html

  1. <html>
  2. <head>
  3. <meta charset="utf-8">
  4. <link href="http://apps.bdimg.com/libs/bootstrap/3.3.4/css/bootstrap.min.css" rel="external nofollow" rel="stylesheet">
  5. </head>
  6. <body>
  7. <div class="panel panel-default" style="margin: 10px">
  8. <div class="panel-body">
  9. <div class="form-horizontal" role="form">
  10. <div class="form-group">
  11. <label for="input_name" class="col-sm-2 control-label">登录帐号</label>
  12. <div class="col-sm-10">
  13. <input type="text" class="form-control" id="input_name" placeholder="请输入用户名">
  14. </div>
  15. </div>
  16. <div class="form-group">
  17. <label for="input_pass" class="col-sm-2 control-label">登录密码</label>
  18. <div class="col-sm-10">
  19. <input type="password" class="form-control" id="input_pass" placeholder="请输入登录密码">
  20. </div>
  21. </div>
  22. <div class="form-group">
  23. <label for="input_check" class="col-sm-2 control-label">验证码:</label>
  24. <div class="col-sm-6">
  25. <input type="text" class="form-control" id="input_check" placeholder="请输入验证码">
  26. </div>
  27. <div class="col-sm-2">
  28. <img id="img_code" src="code.png" />
  29. </div>
  30. </div>
  31. <div class="form-group">
  32. <div class="col-sm-offset-2 col-sm-2">
  33. <button id="btn_submit" class="btn btn-default">登录</button>
  34. </div>
  35. <div class="col-sm-2">
  36. <button id="btn_refresh" class="btn btn-default">刷新验证码</button>
  37. </div>
  38. </div>
  39. </div>
  40. </div>
  41. </div>
  42. <script>
  43. require('./index.js');
  44. </script>
  45. </body>
  46. </html>

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

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

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

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

  1. npm run start

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

下载验证码

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

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

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

编辑 main.js

  1. const electron = require('electron')
  2. const app = electron.app
  3. const BrowserWindow = electron.BrowserWindow
  4.  
  5. const path = require('path')
  6. const url = require('url')
  7. // 爬虫
  8. const superagent = require('superagent');
  9. // 操作文件
  10. const fs = require('fs-extra');
  11.  
  12. let mainWindow
  13. // 验证码的cookie
  14. var codeCookie
  15. // 验证码网址
  16. const codeUrl = '验证码地址';
  17. // 头信息
  18. const browserMsg = {
  19. 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36',
  20. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  21. };
  22.  
  23. function createWindow() {
  24. mainWindow = new BrowserWindow({
  25. width: 800,
  26. height: 600
  27. })
  28. superagent
  29. .get(codeUrl)
  30. .set(browserMsg)
  31. .end((err, res) => {
  32. codeCookie = res.header['set-cookie']
  33. console.log('codeCookie: ' + codeCookie)
  34. // 验证码图片保存到本地
  35. fs.outputFile(path.join(__dirname) + '/code.png', res.body, function (err) {})
  36. })
  37. mainWindow.loadURL(url.format({
  38. pathname: path.join(__dirname, 'index.html'),
  39. protocol: 'file:',
  40. slashes: true
  41. }))
  42. // 打开调试控制台
  43. mainWindow.webContents.openDevTools()
  44.  
  45. mainWindow.on('closed', function () {
  46. mainWindow = null
  47. })
  48.  
  49. }
  50. app.on('ready', createWindow)
  51.  
  52. app.on('window-all-closed', function () {
  53. if (process.platform !== 'darwin') {
  54. app.quit()
  55. }
  56. })
  57.  
  58. app.on('activate', function () {
  59. if (mainWindow === null) {
  60. createWindow()
  61. }
  62. })

说一下安装的依赖

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 文件

  1. const ipcMain = electron.ipcMain;
  2. ipcMain.on('notice', (e, msg) => {
  3. switch (msg) {
  4. case 'getcodeCookie':
  5. mainWindow.webContents.send('codeCookie',codeCookie)
  6. break
  7. default:
  8. break
  9. }
  10. })

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

index.js

  1. const electron = require('electron');
  2. const ipcRenderer = electron.ipcRenderer;
  3. // 获取控件
  4. let btn_submit = document.getElementById("btn_submit");
  5. btn_submit.addEventListener('click', (e) => {
  6. ipcRenderer.send('notice', 'getcodeCookie');
  7. });
  8. // 监听 codeCookie
  9. ipcRenderer.on('codeCookie', (e, msg) => {
  10. codeCookie = msg;
  11. console.log('接受主进程发送的codeCookie: '+codeCookie);
  12. });

运行一下, 点击登录按钮

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

模拟登录

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

编辑index.js

  1. const electron = require('electron');
  2. const ipcRenderer = electron.ipcRenderer;
  3. const path = require('path');
  4. const superagent = require('superagent');
  5.  
  6. // 链接
  7. const urls = {
  8. loginUrl: "登录的地址",
  9. codeUrl: "验证码地址",
  10. targetUrl: "后台的地址"
  11. };
  12.  
  13. // 头信息
  14. const browserMsg = {
  15. "User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36",
  16. 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
  17. };
  18. // 验证码cookie
  19. var codeCookie;
  20. // 登录后的cookie
  21. var tokenCookie;
  22.  
  23. // 获取控件
  24. const btn_submit = document.getElementById("btn_submit");
  25. const btn_refresh = document.getElementById("btn_refresh");
  26. const input_name = document.getElementById("input_name");
  27. const input_pass = document.getElementById("input_pass");
  28. const input_code = document.getElementById("input_code");
  29.  
  30. // 登录按钮 点击事件
  31. btn_submit.addEventListener('click', (e) => {
  32. ipcRenderer.send('notice', 'getcodeCookie');
  33. // 获取输入文本
  34. var name = input_name.value;
  35. var pass = input_pass.value;
  36. var code = input_check.value;
  37. // 校验输入
  38. if (name == "" || pass == "" || code == "") {
  39. alert("请输入");
  40. } else {
  41. // 校验通过 开始进行登录操作
  42. superagent
  43. .post(urls.loginUrl)
  44. .set('Cookie', codeCookie)
  45. .set(browserMsg)
  46. // 避免登录后的302重定向
  47. .redirects(0)
  48. .send({
  49. 'LoginForm[username]': name
  50. }).send({
  51. 'LoginForm[password]': pass
  52. }).send({
  53. logincode: code
  54. }).send({
  55. jz: '0'
  56. }).end((err, res) => {
  57. // 登录成功 获取tokenCookie
  58. // 获取tokenCookie
  59. tokenCookie = res.header['set-cookie'];
  60. superagent
  61. .get(urls.targetUrl)
  62. .set('Cookie',tokenCookie)
  63. .set(browserMsg)
  64. .end((err,res)=>{
  65. // 成功进入后台
  66. console.log(res.text);
  67. })
  68. });
  69. }
  70.  
  71. });
  72.  
  73. btn_refresh.addEventListener('click', (e) => {
  74.  
  75. });
  76.  
  77. ipcRenderer.on('codeCookie', (e, msg) => {
  78. codeCookie = msg;
  79. console.log('接受主进程发送的codeCookie: ' + codeCookie);
  80. });

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

关键是请求要带上cookie

数据抓取

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

  1. cheerio https://cheerio.js.org/

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

操作还是很简单的。

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

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

导出xlsx表格

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

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

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

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

编辑 index.js

  1. const remote = electron.remote;
  2.  
  3. btn_refresh.addEventListener('click', (e) => {
  4.  
  5. const filepath =remote.dialog.showSaveDialog(remote.getCurrentWindow(), {
  6. // 过滤文件类型
  7. filters: [{
  8. name: "xls Files",
  9. extensions: ['xlsx']
  10. },
  11. {
  12. name: 'All Files',
  13. extensions: ['*']
  14. }
  15. ]
  16. });
  17. console.log(filepath);
  18. });

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

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号