春节Python自动化实战:抢票监控、批量祝福与定时任务
2026/9/14 20:38:03 网站建设 项目流程

每逢腊月,我的手机就开始被两类消息刷屏:一类是抢票加速包的“好友助力”,另一类是复制粘贴式的群发祝福。前几年我也随大流,直到有一次盯着12306的刷新按钮盯到凌晨,大拇指都快抽筋,才意识到这种重复劳动本不应该由人来干。于是去年春节,我用Python写了三个自动化脚本,把抢票监控、批量祝福、定时提醒这三件事全部交给机器,那几天是我过得最轻松的一个年。

这篇文章就是那次实践的完整记录。不讲虚的,直接说清楚:为什么选Python、环境怎么搭、三个脚本分别怎么写、跑起来之后踩了哪些坑,以及哪些自动化能做、哪些不该做。如果你也想在春节前搞定这套“数字年味”基建,可以参考这份踩过坑的实战笔记。

1. 为什么春节自动化是刚需:三个脚本解决的痛点

1.1 春节场景的三个高频痛点拆解

春节的“忙”,跟日常工作的忙完全不是一回事。日常忙是任务多、节奏快,春节忙是纯体力消耗叠加情绪消耗。

先说抢票。12306预售期一出,全家人的行程就像一盘散沙落在不同日期、不同车次上。手动刷票时,你得反复切换查询条件,盯着余票数字从“有”变成“无”,再等它从“无”变回“有”。如果是热门线路,放票后几分钟内连候补都排不上。这里最折磨人的不是操作本身,而是不确定性——你不知道什么时候会放票,只能一遍遍刷新,把整个人的精力都耗在了一个刷新按钮上。

再说群发祝福。我每年通讯录里要点对点发祝福的人有三百多个,包括同事、客户、老同学、亲戚。用微信自带群发助手只能选200人上限,而且不能针对不同人换称呼。手动逐条发,从晚上八点发到凌晨,经常发到后半段开始复制粘贴错乱,把给张总的祝福发给了李姐,场面一度非常尴尬。

第三件是提醒类的小事,比如抢红包雨时间、年会抽奖投票、给长辈拜年的准确时间节点。这些事单看不难,但混在年夜饭、看春晚、打牌这些事里,很容易忘。人一旦进入过节状态,对“定时”这件事的敏感度会断崖式下降。

这三件事有一个共同特征:规则明确、操作重复、容错率低。这正是自动化脚本最擅长处理的场景。

1.2 为什么选Python而不是其他工具

市面上做自动化的工具有很多:按键精灵、AutoHotkey、iMacros、甚至Excel里的VBA。为什么最终选了Python?我的理由有三条。

第一,生态覆盖面广。抢票监控需要HTTP请求和JSON解析,批量祝福需要模拟键鼠操作或调用接口,定时任务需要系统调度,这三个需求在Python里都有非常成熟的库:requestsjsonpyautoguischedulelogging。不需要在不同工具之间来回跳,一个语言全搞定。

第二,排查问题成本低。自动化脚本最大的坑是“不知道哪里错了”。Python的异常堆栈可读性极高,配合requests的响应状态码和pyautogui的截图定位,问题基本能在几分钟内定位。而按键精灵这类工具一旦出错,你看到的只是“脚本停止”,调试体验接近盲人摸象。

第三,可迁移性。今年写完抢票监控,明年改改日期参数就能复用;给A客户群发祝福的逻辑,换个Excel表格就能给B项目发通知。脚本一旦沉淀下来,就是自己的数字化资产。

当然Python也有短板:打包分发不如Go方便,运行效率也不是最高。但春节自动化这种低频、轻量、逻辑简单的场景,Python的打法完全够用。

1.3 这套方案能做什么、不能做什么

先说能做的:

  • 定时监控12306余票,一旦目标车次有票立即推送通知到手机;
  • 批量生成带称呼的个性化祝福文案,按名单逐条发送;
  • 用定时任务在指定时间点自动执行脚本,全程不需要人工盯守;
  • 日志记录每次执行结果,出错自动告警。

再说不能做的:

  • 不能绕过12306的验证码和风控机制去“抢票”。铁路部门的用户协议明确禁止非官方的自动购票行为,所以我的方案定位是“监控+提醒”,把人工操作的等待成本降到最低,而不是替代人工下单;
  • 不能对微信等平台进行大规模、高频的自动化操作。这个我后面会细讲,平台风控不是吃素的,脚本写得再稳也扛不住封号;
  • 不能保证100%不出错。网络波动、登录态过期、接口结构调整,任何一个环节都可能挂,所以必须设计异常兜底。

把预期管理做对,工具才能真正提升效率,而不是给你惹麻烦。

2. Python开发环境三件套:安装、虚拟环境与IDE配置

2.1 本机Python安装的坑与版本选择

很多新手第一步就栽在Python安装上。这里把三个主流系统的关键点一次说清。

Windows:去官网下载安装包时,一定要勾选“Add Python to PATH”,否则装完在cmd里敲python会提示找不到命令。装完后打开cmd,输入python --version验证。如果出现“Microsoft Store”的应用商店跳转,说明你用的是系统自带的假入口,需要去“设置 -> 应用 -> 应用执行别名”里把两个python.exe的别名关掉。

macOS:系统自带的Python 2.7早就不维护了,千万别用。建议直接装Homebrew,然后brew install python@3.12。装完注意看终端提示的PATH路径,Homebrew会把Python装到/opt/homebrew/bin,如果which python3指向/usr/bin/python3,说明还在用系统自带版本。

Linux(Ubuntu/Debian系):执行sudo apt update && sudo apt install python3 python3-venv python3-pip。注意不要手动删系统自带的Python,很多系统工具依赖它,删了会导致桌面环境出问题。

版本选择上,我建议用3.10或3.11,不要盲目追最新版。原因很实际:自动化脚本常用的一些库,尤其是涉及GUI模拟和旧接口的,对新版本Python的适配会有滞后。我实测3.12跑pyautogui在部分Windows环境会有权限弹窗兼容问题,而3.11非常稳定。选一个成熟版本,远比你用最新版但被依赖库报错卡住要省心。

2.2 venv虚拟环境:为什么不直接全局安装

如果你想把多个Python项目装在同一个环境里,很快会碰到“依赖地狱”。A项目需要requests==2.28,B项目需要requests==2.31,两个项目共用全局环境,升级一个另一个就挂了。

venv是Python自带的虚拟环境工具,核心作用就是为每个项目创建独立的依赖目录。操作很简单:

# 创建虚拟环境(在项目目录下执行) python -m venv venv # 激活虚拟环境 # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate # 激活后命令行前面会出现(venv)前缀,表示已进入虚拟环境

之后用pip install安装的所有包都会进到这个独立环境里,不影响系统全局。我第一次做春节脚本时嫌麻烦,直接在全局环境装了一堆库,结果春节前一周升级了一个依赖库,把另一个脚本搞崩了,大半夜在那排查依赖冲突,血的教训。

项目依赖固定下来后,用requirements.txt管理:

# 导出当前虚拟环境的所有依赖 pip freeze > requirements.txt # 在新机器上一键还原 pip install -r requirements.txt

这个文件我会连同脚本一起存到Git仓库里,换电脑、换环境都能快速复原。

2.3 IDE选型与调试技巧

春节写脚本讲究快、稳、好排查,我建议用VS Code加Python插件,轻量且调试体验够用。

关键配置有三块:

第一,Python解释器指向虚拟环境。在VS Code里按Ctrl+Shift+P,输入“Python: Select Interpreter”,选择刚才创建的venv目录下的Python。选错解释器是新手最常见的坑,写了半天代码,运行时报ModuleNotFoundError,其实就是解释器没切到虚拟环境。

第二,开启“Python: Terminal: Activate Env In Current Terminal”,这样每次打开新终端,VS Code会自动激活虚拟环境。

第三,学会用断点调试。在代码行号左侧点一下出现红点,然后按F5启动调试。程序执行到红点处会暂停,你可以逐行查看变量的值。这个功能在排查“接口返回的数据结构和预期不一致”这种问题时,比print大法高效十倍。

基础环境就绪后,接下来进入正题:三个脚本逐个拆解。

3. 12306余票监控脚本:原理、接口分析与时序设计

3.1 抢票自动化的工作流程

一个完整的12306自动购票流程包括:登录、查询余票、提交订单、选择乘客、确认支付。这里面每一环都涉及风控和验证机制。

我见过不少人尝试用Selenium控制浏览器去模拟整个购票流程,但实际风中控的强度远高于预期:验证码识别是专业的图像模型在搞,登录状态异常会触发滑块验证,高频请求会直接封IP。普通脚本作者在这条路上投入产出比极低,而且有合规风险。

所以我采用的方案是“只做查询和提醒,不做下单”。查询余票这个动作对人来说是重复劳动,但对服务器来说只是一个公开的查询接口。这个方案把用户协议里最敏感的“自动化购票”部分绕开了,风险和实现成本都大幅下降。省下来的时间足够你在收到提醒后,用手机在官方App上一分钟完成手动购票。

3.2 余票查询接口实例:以requests模拟查询

12306的余票查询接口是对外开放的,不需要登录也能访问。核心请求是一个GET接口,参数包括出发站、到达站、日期。车次信息里包含各席别余票情况。

先做车站代码表。12306用的不是“北京”这种中文名,而是电报码,比如“北京”对应BJP。车站代码表可以提前抓取一次并存成JSON文件,避免每查一次就重拉全表。

import requests import json # 先请求一次车站代码表(频率不要太高,存本地复用) def fetch_station_map(): url = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js" resp = requests.get(url, headers={"User-Agent": "Mozilla/5.0"}) text = resp.text # 返回格式: var station_names ='@bjb|北京北|BJP|...' data = text.split("'")[1].split("@")[1:] station_map = {} for item in data: parts = item.split("|") # parts[1]是中文名, parts[2]是电报码 station_map[parts[1]] = parts[2] with open("stations.json", "w", encoding="utf-8") as f: json.dump(station_map, f, ensure_ascii=False, indent=2) return station_map

然后用车站代码查余票:

import requests import json from datetime import datetime, timedelta def query_left_ticket(from_station, to_station, date_str): # 读车站表 with open("stations.json", "r", encoding="utf-8") as f: station_map = json.load(f) from_code = station_map.get(from_station) to_code = station_map.get(to_station) if not from_code or not to_code: raise ValueError("车站代码不存在,请检查中文名") url = "https://kyfw.12306.cn/otn/leftTicket/query" params = { "leftTicketDTO.train_date": date_str, "leftTicketDTO.from_station": from_code, "leftTicketDTO.to_station": to_code, "purpose_codes": "ADULT" } headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Referer": "https://kyfw.12306.cn/otn/leftTicket/init" } resp = requests.get(url, params=params, headers=headers, timeout=10) resp.raise_for_status() data = resp.json() tickets = [] if data.get("data") and data["data"].get("result"): for item in data["data"]["result"]: fields = item.split("|") # 关键字段索引:3=车次, 8=出发时间, 9=到达时间, 13=二等座, 26=一等座, 29=无座 train_no = fields[3] start_time = fields[8] end_time = fields[9] second_class = fields[30] # 各版本字段索引略有差异 first_class = fields[31] no_seat = fields[29] tickets.append({ "车次": train_no, "出发": start_time, "到达": end_time, "二等座": second_class, "一等座": first_class, "无座": no_seat }) return tickets if __name__ == "__main__": # 明天 target_date = (datetime.now() + timedelta(days=1)).strftime("%Y-%m-%d") result = query_left_ticket("北京", "上海", target_date) for t in result: if t["二等座"] not in ("无", ""): print(f"{t['车次']} {t['出发']}-{t['到达']} 二等座有票: {t['二等座']}")

这里要特别提醒:接口返回的字段索引在不同版本可能有变化。我最初从网上找了一份字段表,直接跑的时候数据错位,把“有票”误判成“无票”,还好没有造成实际损失,只是虚惊一场。所以写完后第一步是打印原始返回的fields数组,对照着确认索引。

3.3 数据解析与信息推送

查到了余票,还要让人及时看到。手机盯屏幕当然可以,但既然做了自动化,就要把通知也一并自动化。我常用的推送方式有三种:

推送方式优点缺点适用场景
SMTP邮件配置简单、无条件限制可能有延迟、容易进垃圾箱兜底通知
Server酱扫码绑定微信、实时推送需要注册获取SendKey个人预警
钉钉/企业微信群机器人免费、支持多人接收需要建群、配置Webhook家庭群通知

我推荐Server酱作为主力通知通道,配置非常轻量。注册后在个人后台拿到一个SendKey,然后:

import requests def send_serverchan(title, content, send_key): url = f"https://sctapi.ftqq.com/{send_key}.send" data = {"title": title, "desp": content} resp = requests.post(url, data=data) resp.raise_for_status()

这样当脚本轮询到目标车次有余票时,微信会立刻收到推送,标题写“北京到上海 D705 二等座有票”,正文放车次详情和购票链接。收到推送后用手机打开官方App手动购票,全程不到一分钟。

3.4 避开封禁的节奏控制

自动化查询有两个“雷区”:请求频率过高、请求特征过于统一。

请求频率方面,官方接口虽然公开,但频繁访问同样会被限流。我的实测数据是:单次查询请求耗时约200到500毫秒,如果把轮询间隔设在1秒以内,持续几分钟后大概率返回异常响应或直接超时。稳妥的轮询间隔是3到5秒,每查询一次就随机sleep 3到5秒之间的一个值。

import random import time interval = random.uniform(3, 5) time.sleep(interval)

请求特征方面,User-Agent不要固定用一个,可以在几个常见浏览器的UA池里随机切换。另外建议用requests.Session()保持连接,模拟浏览器的行为模式:

session = requests.Session() session.headers.update({ "User-Agent": random.choice(UA_LIST), "Referer": "https://kyfw.12306.cn/otn/leftTicket/init" })

控制好节奏,脚本连续跑几天不出问题是很正常的。

4. 祝福消息批量发送:从pyautogui模拟操作到模板化文案

4.1 消息自动化的三种实现路线

群发祝福比抢票更微妙,因为涉及社交平台的用户协议。我做这个功能时认真对比过三条技术路线。

路线一:开放平台官方API。企业微信、钉钉、Telegram这类平台有完善的机器人API,合法合规,但问题是:你的客户、同学、亲戚未必在这类平台上。如果只是给企业客户发,这确实是首选。

路线二:非官方第三方库,比如itchatwechaty这类。它们的原理是通过网页版或HOOK方式接管微信协议。问题在于:网页版微信本身在很多账号上不可用,HOOK方式更容易触发风控。我在两年前测试过,批量发送几十条消息后,账号被限制了朋友圈和部分聊天功能,折腾了一周才解封。为了发个祝福搭上账号,非常不值。

路线三:桌面端GUI自动化,也就是pyautogui模拟鼠标键盘操作。它不介入通信协议,本质上是替你在电脑上“手动操作”。优点是不容易被平台判定为协议异常,缺点是如果界面布局发生变化,脚本需要同步调整。

综合来看,个人场景下路线三最平衡。本文后续就围绕这条路展开。

4.2 模板化祝福文案设计

群发祝福最尴尬的一点是“复制粘贴感”太强。发给所有人的文案都是一模一样,收的人一眼就能看出来。但逐条现写三百条又不现实,所以要用模板加变量的方式做个性化。

我的做法是用Excel维护一个联系人名单,字段包含:姓名、称呼、关系类别、个性化备注。然后准备几个不同风格的模板,根据关系类别自动切换。

称呼:{称呼} 模板(同事):新年快乐!{称呼},感谢这一年的并肩作战。愿新岁平安喜乐,诸事顺遂,咱们节后见! 模板(客户):尊贵的{称呼},感谢过去一年与您同行。值此新春之际,谨祝事业蒸蒸日上,身体健康万事如意! 模板(朋友):{称呼},新春大吉!愿你岁岁常欢愉,万事皆胜意。改天约饭!

读取Excel用pandas库,但春节自动化这种轻量场景,只用标准库的csv模块就够了,避免为了一个小功能引入重型依赖。

import csv contacts = [] with open("contacts.csv", encoding="utf-8-sig") as f: reader = csv.DictReader(f) for row in reader: contacts.append(row) # 模板替换 def gen_message(contact): template = contact["template"] msg = template.replace("{称呼}", contact["称呼"]) return msg

注意CSV文件要用utf-8-sig编码打开,否则Excel里写的中文在读取时会乱码。这个细节我第一年就踩过,生成的消息批量乱码,差点全发出去了。

4.3 pyautogui实操:打开窗口、定位输入框、发送

pyautogui的核心逻辑就三步:定位目标坐标、模拟点击输入、按回车发送。第一步最关键,也是最容易出问题的。

下面是一套我在Windows上稳定跑通的流程:

import pyautogui import time pyautogui.PAUSE = 1.5 # 每个操作之间停顿1.5秒,给界面留反应时间 pyautogui.FAILSAFE = True # 鼠标快速移到左上角可紧急停止 def send_message_to_contact(contact_name, message): # 1. 打开微信的搜索框(快捷键 Ctrl+F) pyautogui.hotkey("ctrl", "f") time.sleep(1) # 2. 输入联系人姓名 pyautogui.write(contact_name, interval=0.05) time.sleep(1) # 3. 按回车进入聊天窗口 pyautogui.press("enter") time.sleep(1) # 4. 在输入框粘贴消息 pyautogui.write(message, interval=0.02) time.sleep(0.5) # 5. 发送 pyautogui.press("enter") time.sleep(1)

这里有两个很重要的参数:PAUSEFAILSAFE

PAUSE是每个pyautogui操作之间的默认间隔。如果设成0,脚本执行速度会飞快,但界面渲染跟不上,很容易丢操作。1到1.5秒的间隔虽然看起来“慢”,但胜在稳定。

FAILSAFE是安全机制。一旦开启,如果脚本失控乱飞,你只要把鼠标甩到屏幕左上角,程序就会立刻抛出pyautogui.FailSafeException并停止,避免脚本在不知情的情况下乱点一通。

还有一个细节:pyautogui.write()对中文支持不太好,它在Windows上模拟的是直接按键输入,中文会丢字符。最好的方案是先把消息复制到剪贴板,再模拟Ctrl+V粘贴:

import pyperclip pyperclip.copy(message) pyautogui.hotkey("ctrl", "v") pyautogui.press("enter")

pyperclip是一个轻量的剪贴板操作库,配合pyautogui在中文输入场景下非常好用。

4.4 发消息的节奏与风控提醒

GUI自动化虽然比协议级操作安全,但依然要控制节奏。我实测下来,每次发送间隔建议不少于5到8秒,每发20条左右暂停一两分钟。频率太高,微信PC端的检测机制同样会介入。

这里有一个更稳妥的替代思路:与其用微信逐条发文字,不如把祝福生成一张张长图。用PIL库把文案渲染成图片,再通过文件传输助手批量发到手机,由你手动转发到朋友圈或群聊。这样操作量大幅下降,而且“发图”比“逐条发文字”的触发风控概率低很多。

from PIL import Image, ImageDraw, ImageFont def draw_blessing_image(name, message, output_path): img = Image.new("RGB", (800, 500), color=(255, 248, 235)) draw = ImageDraw.Draw(img) # 字体路径根据系统调整,Windows可以用微软雅黑 font_title = ImageFont.truetype("msyh.ttc", 48) font_text = ImageFont.truetype("msyh.ttc", 28) draw.text((60, 60), f"{name},新春快乐!", font=font_title, fill=(180, 40, 40)) draw.text((60, 200), message, font=font_text, fill=(60, 60, 60)) img.save(output_path)

把写好的文案逐条渲染成图片,然后手动或半自动发送。这个方案我在去年春节用下来,既保住了仪式感,又避开了高频操作风险。

5. 定时任务调度与异常兜底:让脚本自动运行起来的完整方案

5.1 定时触发:Windows任务计划与Linux cron

脚本写好只是第一步,关键是让它按计划自动跑。很多人第一反应是在代码里写while Truesleep,这在短时间运行可以,但长时间驻留有两个问题:一是电脑休眠脚本就断,二是没有自动重启机制,出错后只能人工救。

正确的做法是交给操作系统级的定时任务管理器。

Windows环境下:按Win+R输入taskschd.msc打开任务计划程序,创建基本任务。触发器选“每天”,时间设为早上8点,操作选“启动程序”。程序填python.exe的完整路径,参数填脚本的完整路径,起始于填脚本所在目录。重点注意几个设置:

  • “条件”选项卡里,取消勾选“只有在计算机使用交流电源时才启动此任务”,否则笔记本拔电后任务不会执行;
  • “设置”选项卡里,勾选“如果任务失败,按以下频率重新启动”,间隔5分钟,最多重启3次;
  • 关键一步:你的Python要激活虚拟环境,但任务计划直接执行python.exe不会自动进入虚拟环境,所以要么在脚本前加上激活命令,要么直接用虚拟环境里的python.exe路径。
# 任务计划程序的“操作”里可以直接写: C:\path\to\venv\Scripts\python.exe C:\path\to\ticket_monitor.py

Linux/macOS环境下:用crontab配置,一行搞定:

# 每天8点和20点各执行一次余票监控 0 8,20 * * * cd /path/to/project && /usr/bin/python3 ticket_monitor.py >> logs/cron.log 2>&1

注意cron执行时的环境变量和终端不一样,尤其是PATH。建议在脚本开头用绝对路径,或者在crontab里显式声明SHELLPATH

5.2 日志记录与异常捕获

定时任务跑起来后,你不可能每次都盯着终端看输出。如果没有日志,脚本出错你根本不知道。

我用的方案是Python标准库的logging,同时输出到文件和控制台:

import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", handlers=[ logging.FileHandler("script.log", encoding="utf-8"), logging.StreamHandler() ] ) logger = logging.getLogger(__name__)

在关键节点打日志,比如“开始查询”“查询结束,发现N个车次有票”“网络请求超时,重试第2次”。这样出问题后翻日志,一眼就能定位是哪一步挂了。

异常捕获要区分“可恢复错误”和“不可恢复错误”。网络超时是可恢复的,重试几次就好;登录态过期是不可恢复的,应该立刻发通知让人工介入,而不是无限重试。

import time MAX_RETRY = 3 def query_with_retry(max_retry=MAX_RETRY): for attempt in range(1, max_retry + 1): try: return query_left_ticket("北京", "上海", date_str) except requests.exceptions.RequestException as e: logger.warning(f"第{attempt}次查询失败: {e}") if attempt == max_retry: send_serverchan("余票监控异常", f"连续{max_retry}次失败,请检查网络或接口", send_key) raise time.sleep(10 * attempt)

5.3 进程守护:让脚本崩了自动重启

定时任务适合“短时运行完就退出”的脚本。如果某个脚本需要长时间驻留,比如持续监听某个事件,那就要引入进程守护。

Linux下我用supervisor,配置一个简单的守护进程:

[program:ticket_monitor] command=/path/to/venv/bin/python /path/to/ticket_monitor.py directory=/path/to/project autostart=true autorestart=true stderr_logfile=/path/to/logs/err.log stdout_logfile=/path/to/logs/out.log

autorestart=true的意思是进程异常退出后自动拉起。这比你在代码里写while True再包一层try...except要可靠得多。

Windows下可以用计划任务的“如果任务失败重新启动”做到类似效果,或者用脚本套一层死循环,但体验一般。个人建议:春节这种短周期场景,能拆成定时短任务的就不要做成常驻进程,复杂度越低越不容易出问题。

5.4 断网、登录失效的处理

春节在老家,网络环境不稳定是常态。我在县城老家实测,晚上8点到11点用网高峰期,宽带延迟能到200毫秒以上,偶尔还会断线。

针对断网,我的方案是在脚本轮询前先做一次网络连通性检测:

import socket def is_network_ok(host="www.baidu.com", timeout=3): try: socket.create_connection((host, 80), timeout=timeout) return True except OSError: return False

如果是12306的登录态过期,查询接口本身不需要登录,问题不大。但如果你后续扩展了自动下单功能,登录Cookie的刷新管理就是一门学问。我的建议是:查询场景保持匿名访问,不要为了“省一次手动输入账号”去维护登录态,复杂度会成倍上升。

6. 脚本落地后的真实体验与合规提醒

6.1 实测数据:脚本跑了多少天、节省多少时间

去年春运,我从腊月十六开始跑余票监控脚本,到除夕前一天,一共跑了14天。目标是从北京回老家的三趟车次。

对比前年的手动刷票体验,前年我每天早中晚查三次票,每次花10到15分钟,累计超过6小时,而且经常因为没及时看到余票而错过。去年脚本全天候轮询,总共推送了7次有票提醒,我成功买到了3张票(自己和父母各一张),实际人工投入时间不超过20分钟——主要是收到推送后的手动下单操作。

除夕群发祝福方面,往年我从晚上7点发到11点多,耗时超过4小时,还发错好几次。去年用脚本加长图方案,下午4点开始跑,5点半全部搞定,包含检查和修改的时间。而且因为用了模板加称呼替换,每个收件人看到的都是带自己名字的版本,反馈明显比以前“复制粘贴”的祝福好。

6.2 踩坑记录:硬编码带来的连环翻车

第一次跑祝福脚本时,我把联系人名单直接硬编码在Python文件里,看起来省事,实际上给后面挖了坑。中途客户名单新增了一个人,我得打开代码文件,找到那一长串字典,小心翼翼地插入一行,还要注意逗号不能漏。改完之后突然想到,万一代码换行把某个文件夹路径弄乱了怎么办?

于是我从一开始就决定用csv文件管理联系人数据,代码只负责读文件。这样做的好处是,数据更新完全不需要碰代码,给谁发、不发谁、改称呼,一个Excel全搞定。春节前三天你还在加人?没关系,改完CSV保存,脚本下次运行自动生效。

这个“数据与逻辑分离”的思路,后来也被我用在祝福模板上。模板和文案全部放在一个独立的纯文本文件中,脚本按标记读取。调整文案只需要改文本,不需要重新看代码逻辑。

另一个容易忽视的坑是时区和日期边界问题。腊月二十九的深夜,脚本用的是“当天”日期去查询余票,结果到了23点50分还在查当天的票,车次早就全部开走了,白白浪费请求次数。后来我加了判断:如果当前时间晚于20点,自动把查询日期滚到第二天。

6.3 合规边界与风险自检清单

自动化这件事,技术可行性只是其中一个维度,合规和伦理边界同样重要。

先说12306。铁路部门在用户协议中明确禁止使用非官方渠道进行自动购票。我的脚本只做“余票查询+信息推送”,不涉及提交订单、不绕过验证码、不影响购票系统正常使用,这在我个人判断中属于可接受的技术实践。但如果你要把它扩展成“全自动抢票”,请务必考虑法律风险。我强烈建议保持“监控+提醒”的定位,把最终决策和执行交给人来完成。

再说微信等社交平台。无论用pyautogui还是其他方式,批量操作都可能违反平台用户协议,并存在账号处罚风险。春节祝福是善意的,但善意不能成为行为的免责金牌。我的原则是:频率要低、数量要合理、内容要克制。宁可战线拉长一点,也不要在短时间轰炸。

风险自检清单,每次跑脚本前过一遍:

  • 该操作是否影响其他人的正常使用体验?
  • 是否遵守了目标平台的服务协议?
  • 脚本出错时,是否有紧急停止机制(比如FAILSAFE)?
  • 涉及个人数据的,是否只保存了本次任务必需的信息?
  • 如果脚本被公开,是否会让你的账号或平台产生风险?

最后说一句我自己的体会。Python自动化脚本的价值不在于“替代人”,而在于把人的精力从重复劳动中解放出来,去做机器做不了的事——比如收到余票提醒后,综合时间、价格、换乘方案做出的购票决策;比如看完名单后,想想今年到底该给谁发什么样的祝福。技术解决“怎么做”,但“做什么”和“为什么做”,永远是人的课题。希望这篇文章能让你今年的春节,少一点机械的忙碌,多一点真正属于节日的时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询