前言

使用 js 实现有些功能会有些麻烦甚至于无法实现,比如实现一个 pdf 合并功能,前端 js 实现会比较复杂

这时候我们就需要借助第三方的帮助了

看完这篇文章能学到什么

  1. 学会使用 nodejs 调用 python 脚本
  2. 学会如何将长时间任务的结果返回给前端
  3. nodejs 调用其他语言脚本的本质
  4. 使用 python 新建虚拟环境

为何用 python

  1. python 语言简单易学,语法简单,学习成本低
  2. python 语言有大量的第三方库,可以实现很多功能
  3. python 运行条件简单,很容易被集成

整体实现步骤

  1. 初始化一个 nodejs 项目
  2. 初始化一个 python 环境,安装依赖 PyMuPDF
  3. 编写 python 脚本,实现 pdf 合并功能
  4. 使用 child_process 模块创建子进程,执行对应的 python 脚本

代码实现(全步骤详细实现)

如果只关心最终源码的话可以直接跳过这里,到最终源码部分

1. 初始化一个 nodejs 项目

新建一个文件夹比如 pdfMerge,然后在该文件夹打开终端,输入以下命令初始化一个 nodejs 项目

1
npm init -y

这会在你的项目下创建一个 package.json 文件,里面包含了项目的基本信息。

接着在项目根目录下新建一个 index.js 文件,一个 python 文件夹,在 python 文件夹下创建一个 scripts 文件夹,然后在 scripts 文件夹下新建一个 merge_pdfs.py 文件

然后修改一下 package.json 文件,添加一个 start 命令,用于启动项目,再添加一个 type 属性,值为 module

修改之后你的 package.json 文件应该是这样子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"name": "pdfmerge",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": ""
}

2. 初始化一个 python 环境,安装依赖 PyMuPDF

执行以下命令,在刚刚创建的 python 文件夹中创建一个虚拟环境

如果你是 macos 系统,使用以下命令

1
2
3
4
cd python # 切换到python文件夹
python3 -m venv venv # 创建虚拟环境
source venv/bin/activate # 激活虚拟环境
pip install PyMuPDF # 安装 PyMuPDF

如果你是 window 系统,使用以下命令

1
2
3
4
cd python # 切换到python文件夹
python -m venv venv # 创建虚拟环境
venv\Scripts\activate # 激活虚拟环境
pip install PyMuPDF # 安装 PyMuPDF

这样我们的项目初始化就完成了,执行完上面的步骤,你的项目目录结构应该是这样的

项目结构预览

3. 编写 python 脚本,实现 pdf 合并功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import fitz  # PyMuPDF
import sys


def merge_pdfs(input_files, output_file):
"""
合并多个PDF文件到一个输出文件中。

参数:
input_files: 一个包含PDF文件路径的列表。
output_file: 输出PDF文件的路径。
"""
# 打开第一个PDF文件
merged_pdf = fitz.open()
for pdf_path in input_files:
pdf = fitz.open(pdf_path)
# 将当前PDF文件插入到合并的PDF中
merged_pdf.insert_pdf(pdf)
# 关闭当前PDF文件
pdf.close()
# 保存合并后的PDF文件
merged_pdf.save(output_file)
# 关闭合并后的PDF文件
merged_pdf.close()


if __name__ == "__main__":
input_files = sys.argv[1].split(",") # 需要合并的PDF文件列表
output_file = sys.argv[2] # 输出文件的名称
merge_pdfs(input_files, output_file)

导入 pdf 文件

随便找两个 pdf 文件放到根目录下

我这里也提供我使用的 pdf 文件

下载 pdf 文件

编写 index.js 文件

使用 nodejs 内置的 child_process 模块创建子进程,执行对应的 python 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { spawn } from "node:child_process"; // 导入子进程模块
import { fileURLToPath } from "node:url"; // 导入路径模块

// 获取 python 解释器的路径
const PYTHON_PATH = fileURLToPath(
new URL("./python/venv/bin/python", import.meta.url)
);

// 获取 python 脚本的路径
const PYTHONN_SCRIPT_PATH = fileURLToPath(
new URL("./python/scripts/merge_pdfs.py", import.meta.url)
);

// 定义需要合并的 PDF 文件列表
const pdfList = ["./实验指导书-1.pdf", "./实验指导书-2.pdf"];

// 定义输出文件的名称
const outputPdf = "./output.pdf";

// 启动子进程,执行 python 脚本
spawn(PYTHON_PATH, [PYTHONN_SCRIPT_PATH, pdfList, outputPdf]);

执行后的目录结构

最终目录结构

执行完成后再打开合并之后的 pdf 文件进行验证,也是没有问题的

最终目录结构