Electron实战 -- 构建Windows桌面版Scrapydweb

背景

Scrapydweb是管理Scrapyd实例(一个爬虫工具)的Web应用,其运行依赖Scrapyd服务的运行,现计划利用Electron将其打包成一个桌面版应用。

思路如下:

  1. 利用pyinstaller将Scrapyd、Scrapydweb分别打包成可执行文件(one-folder bundle)
  2. 构建Electron app, 在其中先后启动Scrapyd和Scrapydweb
  3. 利用electron-forge对Electron app进行打包,构建最终的发布包

详细步骤

打包Scrapyd、Scrapydweb

本文所有操作均在Windows Powershell中进行
确保你的Windows中已安装python>=3.7

检查python版本

安装pyinstaller

pip install pyinstaller

安装Scrapyd

pip install scrapyd

打包Scrapyd

进入Scrapyd的安装目录(可以通过pip show scrapyd查看),观察到scrapyd的启动文件是scripts/scrapyd_run.py,于是执行下述打包指令。

kotlin 复制代码
# 生成spec文件
pyi-makespec `
--add-data "VERSION:scrapyd" `
--add-data "txapp.py:scrapyd" `
--add-data "default_scrapyd.conf:scrapyd" `
--hidden-import "scrapyd.app" `
--hidden-import "scrapyd.spiderqueue" `
--hidden-import "scrapyd.eggstorage" `
--hidden-import "scrapyd.jobstorage" `
--hidden-import "scrapyd.launcher" `
--hidden-import "scrapyd.website" `
--hidden-import "scrapyd.webservice" `
--hide-console "hide-early" `
scripts/scrapyd_run.py

# 按照spec文件打包
pyinstaller scrapyd_run.spec

程序启动(例如双击.exe文件)会弹出一个控制台窗口,如果想隐藏这个窗口,就可以像上面这样指定hide-console=hide-early

打包完成后,在当前目录下会看到dist目录,目录结构如下。其中,scrapyd_run.exe就是最终的可执行文件。由于我们是以one-folder模式打的包,_internal目录也是不可丢弃的。

安装Scrapydweb

pip install scrapydweb

打包Scrapydweb

由于Scrapydweb启动依赖一个配置文件,且Scrapydweb在第一次启动检查到该文件不存在时,会自动生成该配置文件。因此我们先启动一次Scrapyweb,在命令行直接运行 scrapydweb即可。 这时,可以在当前目录下看到新生成了scrapydweb_settings_v10.py。由于该示例中我们只会启动一个本地的scrapyd实例,因此需要修改一下该配置文件。将其中('username', 'password', 'localhost', '6801', 'group'),一行注释掉。

py 复制代码
SCRAPYD_SERVERS = [
    '127.0.0.1:6800',
    # 'username:password@localhost:6801#group',
    #('username', 'password', 'localhost', '6801', 'group'),
]

接下来类似打包Scrapyd的流程,先进入Scrapydweb的安装目录,观察到其启动文件是run.py,于是执行下述指令。

js 复制代码
# 生成spec文件
pyi-makespec `
--add-data "data:scrapydweb/data" `
--add-data "static:scrapydweb/scrapydweb/static" `
--add-data "templates:scrapydweb/templates" `
--hide-console "hide-early" `
run.py

# 按照spec文件打包
pyinstaller run.spec

再将上面得到的scrapydweb_settings_v10.py拷贝到dist/run目录下,目录结构如下。其中,run.exe是最终的可执行文件。

构建electron app

检查是否安装node、git

创建electron app

npm init electron-app@latest my-app

此时,可以看到在my-app目录下生成了若干目录和文件。编辑src/index.js,在其中启动scrapyd和scrapydweb子进程。最终完整的index.js如下:

javascript 复制代码
const { app, BrowserWindow } = require('electron');
const path = require('node:path');

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) {
  app.quit();
}

const backendScrapyd = require('child_process').spawn('scrapyd_run.exe',
{cwd: path.join(app.getPath('exe'), '../scrapyd_run')});

const backendScrapydweb = require('child_process').spawn('run.exe',
{cwd: path.join(app.getPath('exe'), '../run')});

const createWindow = () => {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  });

  // and load the index.html of the app.
  // mainWindow.loadFile(path.join(__dirname, 'index.html'));
  mainWindow.loadURL('http://localhost:5000');

  // Open the DevTools.
  // mainWindow.webContents.openDevTools();
};

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
  createWindow();

  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  
  if (process.platform !== 'darwin') {
    backendScrapydweb.kill();
    backendScrapyd.kill();
    app.quit();
  }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.

打包electron app

npm run make

这里make失败了,原因是ENOTEMPTY,类似错误参见github.com/electron/fo...

可以看到在当前目录下生成一个out目录,里面是构建好的文件。将上面打包好的scrapyd和scrapydweb复制到out目录,结构如下。my-app.exe就是最终的可执行文件,再将整个目录压缩即可得到一个完整的桌面版Scrapydweb安装包。

改进方向

  • 合并scrapyd和scrapydweb打包,减少体积
  • index.js中启动子进程之间作同步(考虑到scrapydweb依赖scrapyd)
  • electron-forge直接将外部文件打包进去(是否可以?),而不是通过手动压缩的方式
相关推荐
张童瑶1 天前
Vue Electron 使用来给若依系统打包成exe程序,出现登录成功但是不跳转页面(已解决)
javascript·vue.js·electron
依了个旧1 天前
Electron内嵌网页实现打印预览功能
electron
朝阳392 天前
Electron-vite【实战】MD 编辑器 -- 编辑区(含工具条、自定义右键快捷菜单、快捷键编辑、拖拽打开文件等)
javascript·electron·编辑器
朝阳392 天前
Electron-vite【实战】MD 编辑器 -- 大纲区(含自动生成大纲,大纲缩进,折叠大纲,滚动同步高亮大纲,点击大纲滚动等)
javascript·electron·编辑器
持久的棒棒君3 天前
npm安装electron下载太慢,导致报错
前端·electron·npm
LEAFF3 天前
Electron License 激活系统集成开发步骤
vue.js·typescript·electron
Lstmxx3 天前
Electron:使用数据流的形式加载本地视频
前端·electron·node.js
rookiefishs4 天前
如何控制electron的应用在指定的分屏上打开🧐
前端·javascript·electron
高山我梦口香糖4 天前
[electron]预脚本不显示内联script
前端·javascript·electron
卸任7 天前
Electron自制翻译工具:增加中英互译
前端·react.js·electron