第一阶段:基础环境准备
在开始之前,确保你的 Linux 服务器(Ubuntu/Debian 推荐)环境是干净且完备的。
- 安装必要系统组件:
# 更新系统
apt update && apt upgrade -y
# 安装 Python 环境及工具
apt install -y python3 python3-pip google-chrome-stable nginx curl psmisc
- 安装 Python 依赖库:
# DrissionPage: 网页自动化
# Flask/Flask-CORS: 订阅接口
# pytz: 上海时区处理
pip3 install DrissionPage Flask flask_cors pytz --break-system-packages
1.5权限与防火墙配置
在脚本运行前,必须打通 80 端口访问通道:
- 创建目录并赋权(使用
nano编辑时可直接执行以下命令):
mkdir -p /var/www/html
chown -R www-data:www-data /var/www/html
chmod -R 755 /var/www/html
- 放行端口(确保云服务器防火墙和系统防火墙双重放行):
ufw allow 80/tcp # 网页访问
ufw allow 5000/tcp # 订阅接口
ufw allow 587/tcp # 邮件发送
第二阶段:核心代码部署
我们需要在 /root 目录下创建两个 Python 文件。
1. 订阅后端 (sub_server.py)
nano /root/sub_server.py
用于接收用户在网页上填写的邮箱。
- 代码要点:监听
5000端口,将邮箱写入subscribers.txt。 - 启动命令:
nohup python3 /root/sub_server.py > /root/sub_server.log 2>&1 &
2. 库存监测器 (spartan_monitor.py)
nano /root/spartan_monitor.py
这是最核心的脚本。
- 代码要点:
MONITOR_CONFIG: 填入你要监控的 PID(ProductID)。MAIL_SETTINGS: 填入你的 QQ 邮箱和 16位授权码。SERVER_IP: 必须填入你的公网 IP,否则网页点击订阅会没反应。SAVE_PATH: 默认/var/www/html/index.html。
第三阶段:文件与目录结构检查
请确认你的服务器文件布局如下:
| 文件路径 | 作用说明 | 备注 |
/root/spartan_monitor.py | 监测脚本 | 手动运行一次测试逻辑 |
/root/sub_server.py | 订阅 API | 必须保持后台持续运行 |
/root/subscribers.txt | 邮箱数据库 | 权限建议 644,每行一个邮箱 |
/root/stock_status.json | 状态机缓存 | 脚本自动生成,对比上次库存 |
/var/www/html/index.html | 前端展示页 | 确保 Nginx 拥有读取权限 |
第四阶段:自动化与持久化 (关键点)
- 让订阅接口永不掉线
使用 nohup 启动后,即使你关闭 SSH 窗口,它也会运行。
nohup python3 /root/sub_server.py > /root/sub_server.log 2>&1 &
- 让监测脚本定时运行
我们使用 Crontab 来实现每 5 分钟自动巡检一次。
crontab -e
在文件最下方加入:
# 每5分钟运行一次监测脚本,并输出日志到 cron_log.log 方便排错
*/5 * * * * /usr/bin/python3 /root/spartan_monitor.py >> /root/cron_log.log 2>&1
第五阶段:如何进行一次完整的“补货测试”?
为了确认邮件能不能发出来,你不需要等官方补货,可以手动触发:
- 添加测试邮箱:手动在
/root/subscribers.txt填入你的测试邮箱。 - 修改缓存骗过脚本:
- 打开
/root/stock_status.json。 - 找一个现在状态是
AVAILABLE的产品,把值改成"SOLD OUT"。
- 打开
- 手动运行脚本
python3 /root/spartan_monitor.py
查看结果:脚本会发现状态从 "SOLD OUT" 变回了真实网页的 "AVAILABLE",从而判定为“刚刚补货”,立刻发信。
第六阶段:常见问题排查 (故障手册)
- 网页时钟不走:检查网页源代码里的
iso_time是否正确生成,且浏览器没报错。 - 订阅显示“后端未连接”:检查服务器
5000端口是否在防火墙(如腾讯云/阿里云的安全组)放行。 - 邮件报 SSL 错误:确认代码里使用的是
server.starttls()而不是SMTP_SSL(对于 587 端口)。 - DrissionPage 启动失败:通常是因为残留的 Chrome 进程太多,代码里的
pkill -9 chrome会尝试清理,如果还不行,请增加服务器 Swap 交换内存。
日常维护与测试
- 文件与路径一览表
| 文件路径 | 作用 | 运维操作 |
/root/sub_server.py | 订阅 API | 若点击订阅没反应,重启此脚本 |
/root/subscribers.txt | 邮箱数据库 | 可用 nano 手动增删邮箱 |
/root/stock_status.json | 库存记录 | 删掉此文件可强制脚本触发一次提醒 |
/var/www/html/index.html | 前端展示页 | 直接浏览器访问 http://你的IP 查看 |
- 如何重启订阅后端?
如果你改了代码或者发现后端死掉了,先杀掉它再重启:
pkill -f sub_server.py
nohup python3 /root/sub_server.py > /root/sub_server.log 2>&1 &
核心逻辑复习
本系统采用 “状态机对比” 模式:
- 第 1 步:从
stock_status.json获取上一次状态。 - 第 2 步:爬取 Spartan 官网获取当前状态。
- 第 3 步:对比。只有 [之前是 SOLD OUT] 且 [现在是 AVAILABLE] 时,才会发送邮件。
- 第 4 步:更新 JSON 文件和网页。
这套流程现在已经刻在你的服务器里了。下一步:建议你在浏览器打开你的 IP 地址,亲自测试一下订阅功能是否能正常将邮箱写入 /root/subscribers.txt。
注意❗
Traceback (most recent call last):
File "/root/spartan_monitor.py", line 234, in <module>
check_stock()
File "/root/spartan_monitor.py", line 96, in check_stock
page = ChromiumPage(co)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/dist-packages/DrissionPage/_pages/chromium_page.py", line 23, in __new__
browser = Chromium(addr_or_opts=addr_or_opts)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/dist-packages/DrissionPage/_base/chromium.py", line 41, in __new__
is_headless, browser_id, is_exists, ws_only = run_browser(opt)
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/dist-packages/DrissionPage/_base/chromium.py", line 501, in run_browser
is_exists = connect_browser(chromium_options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/dist-packages/DrissionPage/_functions/browser.py", line 38, in connect_browser
raise BrowserConnectError(_S._lang.BROWSER_CONNECT_ERR1_, port, port, ADDRESS=address)
DrissionPage.errors.BrowserConnectError:
Browser connect failed, check whether the port 9222 is a browser and "--remote-debugging-port=9222" startup item is added.
Address: 127.0.0.1:9222
Version: 4.1.1.2
这个错误 DrissionPage.errors.BrowserConnectError 是自动化脚本中最常见的报错之一。它意味着 DrissionPage 无法连接到 Chrome 浏览器。
由于你是在 Linux 服务器上以 root 身份运行,通常由以下三个原因造成:
1. 核心原因:Chrome 无法在 root 模式下正常启动
Chrome 默认禁止以 root 身份运行,除非添加 --no-sandbox 参数。虽然代码里写了,但如果后台有残留的 Chrome 进程(死锁状态),DrissionPage 尝试启动新实例时会失败。
解决方法:彻底清理残留进程 在终端运行:
# 强制杀死所有 Chrome 进程
pkill -9 chrome
pkill -9 chromium
2. 环境兼容性:缺少运行依赖
在 Linux (Ubuntu/Debian) 上运行 Headless Chrome 需要一些底层的图形库支持(即使你不使用显示器)。
解决方法:补充安装依赖
apt-get update
apt-get install -y libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxrandr2 libgbm1 libasound2
3. 代码微调:显式指定无沙盒模式
请使用 nano /root/spartan_monitor.py 检查你的 check_stock 函数,确保 co (ChromiumOptions) 的设置部分是这样的:
def check_stock():
# 强制清理(双重保险)
os.system("pkill -9 chrome > /dev/null 2>&1")
co = ChromiumOptions()
co.set_browser_path(CHROME_PATH)
# 必须包含以下几项
co.set_argument('--no-sandbox') # root 运行必备
co.set_argument('--headless') # 服务器无界面必备
co.set_argument('--disable-gpu') # 减少资源占用
co.set_argument('--disable-dev-shm-usage') # 防止内存不足导致的崩溃
co.set_argument('--remote-debugging-port=9222') # 显式指定端口
# 如果还是报错,尝试添加这一行,指定一个干净的用户数据目录
co.set_user_data_path('/tmp/chrome_user_data')
page = ChromiumPage(co)
# ... 后续代码
4. 权限问题:/tmp 目录
有时候 Chrome 无法在默认的 /tmp 目录下创建临时文件。 你可以尝试手动创建刚才指定的目录并赋权:
mkdir -p /tmp/chrome_user_data
chmod -R 777 /tmp/chrome_user_data
验证步骤
修改完代码并清理进程后,直接手动运行:
python3 /root/spartan_monitor.py
如果看到以下输出,说明修好了: [2025-xx-xx] 检查中...

评论