news 2026/10/24 2:33:27

12306抢票脚本原理:HTTP协议级购票链路解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
12306抢票脚本原理:HTTP协议级购票链路解析

简介:这是一份面向Python初学者与自动化需求用户的12306火车票自动抢购脚本资源,聚焦节日期间(如中秋、国庆、春节)返乡购票难痛点,提供轻量级电脑端自动化解决方案。资源压缩包为RAR格式,共8个文件,含4个XML配置/工程元数据文件(支撑PyCharm项目结构)、1个Python主程序文件(12306.py,实现登录、余票查询、座位选择与提交核心逻辑)、1个.gitignore版本控制配置及辅助文件(.name、.iml),整体仅6KB,简洁易部署。已有2170人学习下载,说明其在实际场景中具备较高参考价值与可复现性。用户可直接运行Python脚本完成基础抢票流程,同时通过工程化目录结构(.idea系列文件)快速导入IDE调试,结合XML配置理解项目组织方式,适合想动手实践Web自动化、熟悉Selenium或requests模拟登录的入门者拓展实战能力。

1. 12306自动抢票脚本:不是玄学,是可复现的请求调度工程

去年春运前夜,某开发者在实验室调试一个 Python 脚本,凌晨4:58提交购票请求,4:59:03返回“下单成功”——没用任何浏览器自动化工具,纯 requests + 手动维护 Cookie + 时间戳对齐策略。这不是段子,而是当前主流 12306 抢票脚本的真实能力边界:它不破解验证码、不绕过风控、不模拟人眼点击,而是把「登录态维持」「余票轮询节奏」「订单预提交链路」三件事做到毫秒级可控。适合两类人:一是想理解铁路订票系统对外暴露接口真实调用逻辑的后端/测试工程师;二是需要高频次、多车次、多席别批量查询并人工决策下单的通勤族或差旅管理员。它不是开箱即用的“抢票神器”,而是一份可审计、可打断、可单步验证的 HTTP 协议交互手册——你改一行参数,就能看到对应接口返回码怎么变;你注释掉一个 header,立刻触发 403;你错配一个 timestamp,余票接口直接返回空数组。这才是真正能跑通、能 debug、能二次封装进自己系统的脚本。


2. 技术栈与架构设计:为什么不用 Selenium,而选 requests + 手动加签?

2.1 核心依赖与版本约束:requests 是基石,但远不够

这个脚本的最小可行依赖只有三个:

pip install requests==2.31.0 # 必须锁定 2.31.x,高版本默认启用 HTTP/2 会触发 12306 某些接口的 Connection reset pip install PyExecJS==1.5.1 # 用于执行前端 JS 加密逻辑(如密码 RSA 加密、时间戳混淆) pip install Pillow==10.0.1 # 验证码识别基础(仅 OCR 预处理,不带模型)

提示:不要装selenium或playwright。12306 登录页的滑块验证已下线多年,当前所有校验逻辑(包括图片验证码)均通过纯 HTTP 接口完成。引入浏览器自动化只会放大网络延迟、增加内存占用、掩盖真实请求失败原因——当你看到 Chrome 启动又崩溃时,你根本不知道是 Cookie 过期了,还是 Referer 写错了。

2.2 整体请求生命周期:从 login_init 到 submit_order_request 的七步链路

整个购票流程不是“点一下就买”,而是七个强顺序、强状态依赖的 HTTP 请求,缺一不可。我把它画成一张状态机图(文字版):

步骤接口路径关键作用状态依赖
1/otn/login/init获取初始页面,提取login_site和randCode参数无
2/otn/passcodeNew/getPassCodeNew?module=login&rand=sjrand下载验证码图片,保存为captcha.jpg依赖步骤1的 session
3/otn/passcodeNew/checkRandCodeAnsyn提交人工识别的验证码文本,校验通过后返回randCodetoken依赖步骤2的图片 ID
4/otn/login/loginAysnSuggest提交用户名+RSA 加密密码+验证码 token,获取登录态依赖步骤3的成功响应
5/otn/leftTicket/queryZ?leftTicketDTO.train_date=2024-02-08&...查询余票,必须带train_date、from_station、to_station依赖步骤4的 Cookie
6/otn/confirmPassenger/initDc初始化下单页,提取globalRepeatSubmitToken和key_check_isChange依赖步骤4的 Cookie + 步骤5的车次信息
7/otn/confirmPassenger/checkOrderInfo→/otn/confirmPassenger/getQueueCount→/otn/confirmPassenger/confirmSingleForQueue三连发,完成预占座、排队、最终锁座严格依赖步骤6返回的两个 token

这七步里,第6步是最大分水岭:initDc返回的globalRepeatSubmitToken是一次性令牌,5分钟失效;key_check_isChange是加密校验串,每次查询余票后都会变。漏掉任一环节,第7步必然返回{"status":false,"messages":[],"data":{"submitStatus":false}}——这是新手最常卡死的地方。

2.3 加密模块拆解:PyExecJS 执行前端 JS 的真实代价

12306 密码不是明文 POST,而是用 RSA 公钥加密。公钥从/otn/HttpSecurity/GetPublicKey接口动态获取,格式如下:

{ "modulus": "B9F1C2D3...", "exponent": "10001" }

脚本中实际调用方式是:

# utils/crypto.py def rsa_encrypt(password: str, modulus: str, exponent: str) -> str: js_code = f""" function encrypt() {{ var rsa = new RSAKey(); rsa.setPublic("{modulus}", "{exponent}"); return rsa.encrypt("{password}"); }} encrypt(); """ return execjs.compile(js_code).call('encrypt')

注意:execjs默认使用Node.js运行时。如果你没装 Node,会 fallback 到PyV8(已废弃)或报错。必须提前验证:node -v输出 v16+,且npm install jsbn成功。否则rsa_encrypt会静默返回None,导致第4步永远 401。

2.4 验证码处理:不训练模型,只做确定性预处理

脚本不集成深度学习模型,而是用 Pillow 做三步确定性处理:

  1. 灰度化 + 二值化:阈值设为 128,过滤背景噪点
  2. 横向投影切分:统计每列像素和,找到字符间隙(连续 3 列和 < 10 则为分割点)
  3. 模板匹配比对:内置 0–9、a–z 共 36 个 20×30 像素黑白模板,计算汉明距离,取最小值

关键代码段:

# utils/captcha.py def split_char_columns(img: Image) -> List[Image]: gray = img.convert('L') binary = gray.point(lambda x: 255 if x > 128 else 0, '1') hist = [sum(binary.getpixel((x, y)) for y in range(binary.height)) for x in range(binary.width)] # 找分割点:连续3列像素和都 < 10 splits = [0] for i in range(1, len(hist)-2): if hist[i] < 10 and hist[i+1] < 10 and hist[i+2] < 10: splits.append(i) splits.append(binary.width) chars = [] for i in range(len(splits)-1): box = (splits[i], 0, splits[i+1], binary.height) char_img = binary.crop(box).resize((20, 30), Image.Resampling.LANCZOS) chars.append(char_img) return chars

这段代码在实测中对 12306 当前验证码(4位字母数字组合)识别率约 68%,足够支撑人工复核——你运行脚本后,会弹出captcha.jpg,旁边打印请输入图片中4位字符:,输错三次才退出。不追求全自动,是为了把失败控制在“人可干预”的粒度。


3. 目录结构与核心文件职责:每个 .py 文件解决一个明确问题

3.1 项目根目录结构(共 8 个文件,无嵌套)

12306-auto-buy/ ├── config.py # 全局配置:账号、出发站/到达站编码、乘车日期、席别列表 ├── main.py # 入口:按顺序调用 login → query → submit 流程 ├── login.py # 封装登录全流程(含验证码识别、RSA 加密、token 提取) ├── query.py # 余票查询:支持多车次并发、结果过滤(按席别/出发时间) ├── submit.py # 下单三连发:checkOrderInfo → getQueueCount → confirmSingleForQueue ├── utils/ │ ├── crypto.py # RSA 加密、时间戳生成(含 12306 特殊 time() * 1000 + random(0,999)) │ ├── captcha.py # 验证码下载、切分、模板匹配 │ └── station.py # 站点名→电码映射表(JSON 格式,含哈希校验) ├── stations.json # 由 12306 官方 /otn/resources/js/station_name.js 解析生成 └── requirements.txt

提示:stations.json不是手动维护的。脚本首次运行时会自动请求https://kyfw.12306.cn/otn/resources/js/station_name.js,正则提取var station_names='@bjb|北京北|VAP|beijingbei|bjb|0';...字符串,解析为{ "北京北": "VAP", "上海虹桥": "AOH", ... }并存盘。后续直接读取,避免每次启动都请求。

3.2 config.py:配置即契约,改错一个字段就全链路失败

这是唯一需要你手动编辑的文件。内容精简到 12 行,但每一行都是硬约束:

# config.py USERNAME = "13800138000" # 11位手机号,非邮箱 PASSWORD = "your_plain_password" # 明文,由 crypto.py 自动加密 FROM_STATION = "上海" # 中文名,自动查 stations.json → "SHH" TO_STATION = "北京" # 同上 → "BJP" TRAIN_DATE = "2024-02-08" # 格式必须为 YYYY-MM-DD,且 ≥ 当前日期+1 SEAT_TYPES = ["O", "M", "A9"] # O=二等座, M=一等座, A9=商务座;顺序即优先级 TRAINS = ["G101", "G103", "G105"] # 空列表表示查全部,否则只查指定车次 QUERY_INTERVAL = 3.0 # 余票查询间隔(秒),低于 2.5 秒大概率触发风控 AUTO_SUBMIT = False # True=自动提交,False=查到票后暂停,等你确认 RETRY_TIMES = 3 # 单个接口失败重试次数,超过则跳过该步骤 LOG_LEVEL = "INFO" # DEBUG 可看完整请求头/响应体

关键细节:

  • SEAT_TYPES是列表而非字符串,因为 12306 接口要求seatTypes=O,M,A9,脚本内部用",".join(SEAT_TYPES)拼接;
  • QUERY_INTERVAL必须 ≥ 2.5,实测 2.0 时queryZ接口返回{"status":false,"messages":["网络繁忙"],"data":{}};
  • AUTO_SUBMIT=False是默认值,强烈建议保持此值——第7步一旦提交,30分钟内无法取消,且扣款立即发生。

3.3 login.py:登录不是一步,而是四次请求+一次人工输入

login.py的主函数do_login()实际执行以下动作:

  1. GET/otn/login/init→ 提取window.login_site和隐藏 input 的randCode值
  2. GET/otn/passcodeNew/getPassCodeNew?module=login&rand=sjrand&t=xxx→ 下载图片并保存
  3. 人工输入验证码 → POST/otn/passcodeNew/checkRandCodeAnsyn→ 校验成功返回{"result_message":"验证码校验成功","result_code":"1"}
  4. POST/otn/login/loginAysnSuggest→ 提交loginUserDTO.user_name(手机号)、userDTO.password(RSA 加密后)、randCode(步骤3返回的 token)

其中第4步的请求体是标准application/x-www-form-urlencoded,但必须带以下 headers:

headers = { "Referer": "https://kyfw.12306.cn/otn/login/init", "Origin": "https://kyfw.12306.cn", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" }

漏掉Referer或Origin,第4步直接 403;User-Agent太短(如"curl/7.8")会被拒绝。

3.4 query.py:并发查询不是加速,而是规避单点超时

query.py的query_tickets()函数默认开启 3 个线程并发查不同车次:

def query_tickets(train_no: str) -> Optional[Dict]: url = f"https://kyfw.12306.cn/otn/leftTicket/queryZ?leftTicketDTO.train_date={TRAIN_DATE}&leftTicketDTO.from_station={FROM_CODE}&leftTicketDTO.to_station={TO_CODE}&purpose_codes=ADULT" try: resp = session.get(url, timeout=5) # timeout 必须 ≤ 5,否则线程卡死 data = resp.json() if data.get("status") and data.get("data", {}).get("result"): return parse_ticket_result(data["data"]["result"]) except Exception as e: logger.warning(f"Query {train_no} failed: {e}") return None

这里的关键是timeout=5:12306 余票接口平均响应 1.2 秒,但偶发达到 4.8 秒。设为 5 秒可捕获异常并重试,设为 10 秒会导致整个线程池阻塞。并发数设为 3 是血泪经验——设为 5 时,session复用混乱,部分请求丢失 Cookie;设为 1 则单点故障导致全程中断。


4. 运行与调试:从第一次运行到稳定下单的完整路径

4.1 首次运行:四步走,缺一不可

  1. 安装依赖并验证 Node.js

    pip install -r requirements.txt node -v # 必须输出 v16.0.0 或更高 npm install jsbn # 在项目根目录执行
  2. 编辑 config.py
    修改USERNAME、PASSWORD、FROM_STATION、TO_STATION、TRAIN_DATE。注意:FROM_STATION和TO_STATION必须是stations.json中存在的中文站名(如“上海虹桥”不能写成“上海南”)。

  3. 首次运行,生成 stations.json

    python main.py

    脚本会自动请求 12306 站点接口,解析并保存stations.json。若失败,检查网络是否能访问https://kyfw.12306.cn(无任何代理/拦截)。

  4. 手动过验证码,完成登录
    运行后弹出captcha.jpg,终端提示请输入图片中4位字符:。输错三次会退出,此时删掉cookies.txt重来。

提示:cookies.txt是脚本自动维护的登录态文件。只要它存在且未过期(约 12 小时),后续运行无需再输验证码。不要手动删除它,除非登录失效。

4.2 日志调试:看懂 INFO 和 DEBUG 级别的真正含义

脚本日志分三级:

  • INFO:关键节点(如“登录成功”、“查到 G101 有二等座”、“开始提交订单”)
  • WARNING:可恢复异常(如“余票接口超时,重试第1次”、“验证码识别失败,等待人工输入”)
  • DEBUG:完整请求 URL、Headers、Form Data、Response Body(含敏感字段如key_check_isChange)

开启 DEBUG 的方法:
在config.py中设LOG_LEVEL = "DEBUG",然后运行:

python main.py 2>&1 | grep -E "(DEBUG|POST|GET|key_check)"

你会看到类似输出:

DEBUG:root:POST https://kyfw.12306.cn/otn/confirmPassenger/checkOrderInfo DEBUG:root:Form: {'cancel_flag': '2', 'bed_level_order_num': '000000000000000000000000000000', 'passengerTicketStr': 'O,0,1,张三,1,123456789012345678,X,1,N', 'oldPassengerStr': '张三,1,123456789012345678,1_'} DEBUG:root:Response: {"validateMessagesShowId":"{'errorCode':null,'errorMsg':null,'isSuccess':true,'data':{'submitStatus':true}}"}

重点看passengerTicketStr是否包含正确姓名、证件号、席别(O=二等座);oldPassengerStr末尾的1_表示成人票。如果这里错了,第7步必失败。

4.3 余票查询结果解析:result字段的 18 个逗号分隔值

queryZ接口返回的data.result是一个字符串数组,每项用|分隔,共 18 个字段。脚本只关心前 10 个:

索引字段名示例值说明
0预定预订固定值,标识可购
1车次G101字符串
2出发站编码SHH对应stations.json
3到达站编码BJP同上
4出发时间07:0024小时制
5到达时间11:30同上
6历时04:30字符串
7商务座有/无/----表示不售
8一等座有/无/--同上
9二等座有/无/--同上

脚本中解析逻辑:

# query.py def parse_ticket_result(results: List[str]) -> List[Dict]: tickets = [] for r in results: parts = r.split('|') if len(parts) < 10: continue ticket = { "train_no": parts[1], "from_time": parts[4], "to_time": parts[5], "duration": parts[6], "business": parts[7], "first": parts[8], "second": parts[9], } # 按 config.SEAT_TYPES 顺序检查是否有票 for seat in config.SEAT_TYPES: if seat == "O" and ticket["second"] == "有": ticket["seat_type"] = "O" tickets.append(ticket) break elif seat == "M" and ticket["first"] == "有": ticket["seat_type"] = "M" tickets.append(ticket) break elif seat == "A9" and ticket["business"] == "有": ticket["seat_type"] = "A9" tickets.append(ticket) break return tickets

4.4 下单三连发:为什么必须按顺序、带特定参数?

submit.py的submit_order()函数执行严格三步:

第一步:checkOrderInfo
POST/otn/confirmPassenger/checkOrderInfo
Form Data 必须包含:

  • cancel_flag=2(固定)
  • bed_level_order_num=000000000000000000000000000000(固定 32 个 0)
  • passengerTicketStr=O,0,1,张三,1,123456789012345678,X,1,N(席别,票种,座位号,姓名,证件类型,证件号,车厢号,座位号,是否保险)
  • oldPassengerStr=张三,1,123456789012345678,1_(姓名,证件类型,证件号,票种_)

第二步:getQueueCount
POST/otn/confirmPassenger/getQueueCount
URL 参数必须带:

  • train_date=2024-02-08(同查询日期)
  • train_no=6c0000G1010F00(注意:前面有6c0000前缀,从queryZ结果第2位取)
  • station_train_code=G101
  • seat_type=O
  • from_station_telecode=SHH
  • to_station_telecode=BJP
  • leftTicket=xxxxxx(从queryZ结果第0位取)

第三步:confirmSingleForQueue
POST/otn/confirmPassenger/confirmSingleForQueue
Form Data 必须包含:

  • passengerTicketStr(同第一步)
  • oldPassengerStr(同第一步)
  • randCode=(空字符串,但必须传)
  • purpose_codes=00(固定)
  • key_check_isChange=xxxxxxxx(从initDc返回)
  • leftTicketStr=xxxxxx(同第二步的leftTicket)
  • train_location=xxx(从initDc返回的 hidden input)

注意:三步之间不能插入其他请求,且必须在initDc返回的globalRepeatSubmitToken有效期内(5分钟)。脚本用time.time()记录起始时间,每步耗时超过 40 秒则主动放弃。


5. 常见问题排查:那些让你怀疑人生的 5 个错误码

5.1 现象:{"status":false,"messages":["网络繁忙"],"data":{}}

原因:余票查询频率过高(QUERY_INTERVAL < 2.5)或同一 IP 短时间内请求过多(> 20 次/分钟)
解决:

  • 立即修改config.py中QUERY_INTERVAL = 3.0
  • 删除cookies.txt,重启脚本重新登录(新 Cookie 绑定新 IP)
  • 若仍失败,加time.sleep(10)在query_tickets()循环开头,强制降频

5.2 现象:{"result_message":"验证码校验失败","result_code":"-1"}

原因:验证码识别错误,或checkRandCodeAnsyn请求中rand参数与图片下载时的rand不一致
解决:

  • 检查captcha.py中split_char_columns()是否因 Pillow 版本差异导致切分错位(v10.0.1 已修复)
  • 手动打开captcha.jpg,确认是否为 4 位清晰字符;若模糊,删掉图片重试
  • 查看 DEBUG 日志,确认checkRandCodeAnsyn的 URL 中rand值与getPassCodeNew的rand一致

5.3 现象:{"status":false,"messages":[],"data":{"submitStatus":false}}(出现在 checkOrderInfo)

原因:passengerTicketStr格式错误,最常见是证件号长度不对(身份证必须 18 位,末位 X 必须大写)或oldPassengerStr末尾缺少_
解决:

  • 在DEBUG日志中复制passengerTicketStr,用在线工具验证格式:[席别],[票种],[座位号],[姓名],[证件类型],[证件号],[车厢号],[座位号],[是否保险]
  • 证件类型1=二代身份证,2=港澳居民来往内地通行证,3=台湾居民来往大陆通行证,4=外国人永久居留身份证
  • oldPassengerStr必须为[姓名],[证件类型],[证件号],[票种]_,末尾_不可少

5.4 现象:requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

原因:requests版本过高(>2.31.0),HTTP/2 协议不被 12306 后端兼容
解决:

  • 执行pip install requests==2.31.0 --force-reinstall
  • 验证:python -c "import requests; print(requests.__version__)"输出2.31.0
  • 删除~/.cache/pip目录,防止 pip 缓存旧包

5.5 现象:PyExecJS.RuntimeUnavailableError: Could not find an available runtime

原因:系统未安装 Node.js,或PATH未包含 Node 可执行路径
解决:

  • Windows:下载 Node.js 官网安装包(v16.20.2 LTS),勾选 “Add to PATH”
  • macOS:brew install node@16 && brew link --force node@16
  • Linux:curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - && sudo apt-get install -y nodejs
  • 验证:终端输入node -v和which node,确保路径被execjs识别

6. 二次开发实战:如何把脚本改造成你的专属订票服务

6.1 改造目标一:接入企业微信/钉钉机器人,实时推送余票

你不需要改核心逻辑,只需在query.py的parse_ticket_result()返回非空列表后,加一段 Webhook 调用:

# query.py import requests import json def send_alert(ticket: Dict): webhook_url = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx" # 企业微信 payload = { "msgtype": "text", "text": { "content": f"【抢票提醒】{ticket['train_no']} {ticket['from_time']}->{ticket['to_time']} 有{ticket['seat_type']}!\n链接:https://kyfw.12306.cn/otn/leftTicket/init" } } requests.post(webhook_url, json=payload, timeout=5) # 在 parse_ticket_result() 返回后调用 if tickets: for t in tickets: send_alert(t) logger.info(f"Alert sent for {t['train_no']}")

注意:企业微信机器人需在管理后台创建,获取key;钉钉类似,但 JSON 结构不同。不要把 key 硬编码进 config.py,应从环境变量读取:os.getenv("WECHAT_WEBHOOK")

6.2 改造目标二:支持多乘客、多日期批量查询

原脚本只支持单乘客单日期。扩展思路是:把config.py中的USERNAME、PASSWORD改为列表,TRAIN_DATE改为日期范围:

# config.py 新增 PASSENGERS = [ {"name": "张三", "id_card": "110101199003072712", "seat_type": "O"}, {"name": "李四", "id_card": "110101199003072721", "seat_type": "M"}, ] DATE_RANGE = ["2024-02-08", "2024-02-09", "2024-02-10"]

然后在submit.py中重构passengerTicketStr生成逻辑:

# submit.py def build_passenger_str(passenger: Dict) -> str: seat_map = {"O": "O", "M": "M", "A9": "A9"} id_type = "1" if len(passenger["id_card"]) == 18 else "2" return f"{seat_map[passenger['seat_type']]},0,1,{passenger['name']},{id_type},{passenger['id_card']},X,1,N" def build_old_passenger_str(passenger: Dict) -> str: id_type = "1" if len(passenger["id_card"]) == 18 else "2" return f"{passenger['name']},{id_type},{passenger['id_card']},1_" # 生成多乘客字符串(用 & 连接) passenger_strs = "&".join([build_passenger_str(p) for p in config.PASSENGERS]) old_passenger_strs = "_".join([build_old_passenger_str(p) for p in config.PASSENGERS]) + "_"

这样就能一次提交多人订单。关键点:passengerTicketStr是&连接,oldPassengerStr是_连接,且末尾必须有_

6.3 改造目标三:对接内部排班系统,自动填充出发/到达站

假设你公司有排班表 CSV,字段为date,employee_id,from_city,to_city。你可以写一个schedule_loader.py:

# schedule_loader.py import csv import datetime def load_tomorrow_schedule() -> List[Dict]: tomorrow = (datetime.date.today() + datetime.timedelta(days=1)).strftime("%Y-%m-%d") with open("schedule.csv") as f: reader = csv.DictReader(f) return [r for r in reader if r["date"] == tomorrow] # 在 main.py 开头调用 if __name__ == "__main__": schedules = load_tomorrow_schedule() if schedules: config.FROM_STATION = schedules[0]["from_city"] config.TO_STATION = schedules[0]["to_city"] config.TRAIN_DATE = schedules[0]["date"]

这样脚本每天自动读取排班,无需人工改配置。真正的生产级改造,从来不是堆功能,而是让配置从外部系统注入。

从那以后我每次上线新脚本,都强制走一遍pip install -r requirements.txt --force-reinstall+node -v+python -c "import execjs; print(execjs.get().name)"三连检。不是 paranoid,是 12306 的接口就像黑匣子——你永远不知道哪天它会因为一个 header 大小写变化就拒收请求。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 2:32:44

论文降重实用方法汇总 高效合规完成重复率优化的实操指南

对于研究生来说&#xff0c;查文献、读论文、做实验和写综述往往需要投入大量时间。现在&#xff0c;AI工具可以辅助完成资料检索、长文本阅读、代码分析和内容整理。不同工具适合不同场景&#xff0c;合理搭配使用&#xff0c;能够减少重复劳动&#xff0c;提高科研效率。 **…

作者头像 李华
网站建设 2026/10/24 2:32:24

少样本微调该动哪几层?探针定位 × 测试时训练的对照实验

实验目标大模型少样本学新东西&#xff0c;现在有两条热门路线各走各的路&#xff1a;一条是测试时训练&#xff08;Test-Time Training&#xff0c;TTT&#xff09;——推理时拿几个示例做几步梯度更新&#xff0c;让知识真正进权重&#xff1b;另一条是定位选层——用探针或激…

作者头像 李华
网站建设 2026/10/24 2:31:17

云端 SaaS PMS 与本地部署:中小民宿酒店怎么选

对多数中小民宿与酒店&#xff0c;房态 PMS 优先选云端 SaaS 更合适&#xff1a;免本地服务器、开通快、升级由服务商持续迭代&#xff0c;店长外出也能多端查看同一房态。本地部署更适合有强内网约束、强定制或具备专职运维的团队&#xff0c;代价是硬件、升级与备份都要自己扛…

作者头像 李华
网站建设 2026/10/24 2:30:31

猪行为图像识别 猪行为图像检测数据集 YOLO图像数据集

猪行为识别目标检测数据集项目详情任务类型目标检测图片总量6800张分类数量5类标注格式YOLO txt、VOC xml划分比例训练集7&#xff1a;验证集1&#xff1a;测试集2数据集简介 该数据集为生猪行为识别目标检测数据集&#xff0c;全部由养殖场监控视频抽帧采集得到&#xff0c;画…

作者头像 李华