一行命令自动提交:用 Python 把本地代码秒交评测机
作者:jason日期:2025-07-27
1. 为什么需要“命令行交题”?
刷算法题时,最常见的动作是:
[*]本地写完代码
[*]打开浏览器 → 登录 → 选语言 → 选文件 → 点击 Submit
[*]等待结果 →回到 IDE 继续 Debug
整个链路里有大量机械点击。
如果能把第 2 步压缩成 一条命令,效率立刻翻倍,而且还能:
[*]在 Vim/VS Code 里一键绑定快捷键
[*]CI 里做回归测试,定时把模板题跑一遍
[*]比赛时批量交暴力,对拍数据
2. 脚本功能一览
脚本 submit.py 只有 100 行不到,却能:
功能实现方式登录 OJrequests.Session + Cookie自动提取 CSRF-tokenBeautifulSoup 双策略(meta/input)语言缩写自动映射cpp → cc.cc14o2 …提交后返回记录号解析 302 Location3. 运行姿势
# 把 1000 题的 C++ 代码交上去
python3 submit.py \
https://oj.example.com \
1000 \
alice \
secret \
~/a.cpp \
cpp输出示例:
提交成功!记录号:123456
查看结果:https://oj.example.com/record/1234564. 代码精讲
4.1 参数检查
if len(sys.argv) != 7:
print("用法:python submit.py <BASE> <PID> <USER> <PASS> <FILE> <LANG>")
sys.exit(1)
[*]位置参数比交互式 input() 更适合脚本化,易与编辑器/CI 集成。
[*]7 个参数正好是 BASE PID USER PASS FILE LANG + 脚本本身 sys.argv。
4.2 会话初始化
s = requests.Session()
s.headers.update({
'User-Agent': 'Mozilla/5.0 ...',
'Referer': SUBMIT_URL
})
[*]Session 自动管理 Cookie,后续请求无需手动带 sid。
[*]Referer 很多 OJ 会检查,防止 CSRF。
4.3 CSRF-token 双保险
# 1) meta 标签
meta = soup.find('meta', attrs={'name': 'csrf-token'})
...
# 2) 隐藏域
inp = soup.find('input', attrs={'name': re.compile(r'csrf|_csrf')})
# 3) 兜底 Cookie
csrf_submit = s.cookies.get('sid.sig', '')
[*]不同 OJ 的 CSRF 位置不一样,脚本做了 三级回退。
[*]如果全部失败,打印页面源码方便 Debug。
4.4 语言映射
if LANG == 'cpp':
LANG = 'cc.cc14o2'
elif LANG in ('python', 'py'):
LANG = 'py.py3'
[*]命令行里敲 cpp、py 即可,无需记住评测机内部代号。
[*]想支持更多语言,直接加 elif 即可。
4.5 提交与结果
resp = s.post(SUBMIT_URL, data=payload, allow_redirects=False)
if resp.status_code == 302:
rid = resp.headers['Location'].split('/')[-1]
[*]评测机成功接收后通常 302 到 /record/{rid}。
[*]解析 Location 即可拿到记录号,再拼成可点击的 URL。
4.6 完整代码
请在写一篇文章
#!/usr/bin/env python3
import sys, requests, re
from bs4 import BeautifulSoup
def main():
if len(sys.argv) != 7:
print("用法:python submit.py <BASE> <PID> <USER> <PASS> <FILE> <LANG>")
sys.exit(1)
BASE, PID, USER, PASS, FILE, LANG = sys.argv
LOGIN_URL= f"{BASE.rstrip('/')}/login"
SUBMIT_URL = f"{BASE.rstrip('/')}/p/{PID}/submit"
# 1. 建立会话
s = requests.Session()
s.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/120.0.0.0 Safari/537.36',
'Referer': SUBMIT_URL
})
# 2. 首次 GET 登录页 → 取 Cookie 中的 CSRF
s.get(LOGIN_URL)
csrf_login = s.cookies.get('sid.sig', '')
# 3. 登录
resp = s.post(LOGIN_URL, data={
'uname': USER,
'password': PASS,
'_csrf': csrf_login
}, allow_redirects=False)
if resp.status_code != 302:
raise RuntimeError('登录失败')
# 4. GET 提交页 → 取新的 CSRF
submit_html = s.get(SUBMIT_URL).text
soup = BeautifulSoup(submit_html, 'lxml')
csrf_submit = None
# 1) meta 标签
meta = soup.find('meta', attrs={'name': 'csrf-token'})
if meta:
csrf_submit = meta['content']
# 2) 隐藏域
else:
inp = soup.find('input', attrs={'name': re.compile(r'csrf|_csrf')})
csrf_submit = inp['value'] if inp else None
# 3) 兜底:如果都没有,就直接用 Cookie 里的 sid.sig
if not csrf_submit:
csrf_submit = s.cookies.get('sid.sig', '')
if not csrf_submit:
print('⚠️ 无法提取 CSRF,页面预览:')
print(submit_html)
sys.exit(1)
# 5. 读源码
with open(FILE, encoding='utf-8') as f:
code = f.read()
# 6. POST 提交
# 6.1 转换 LANG
if LANG =='cpp':
LANG = 'cc.cc14o2'
elif LANG == 'python' or LANG == 'py':
LANG = 'py.py3'
payload = {'_csrf': csrf_submit, 'lang': LANG, 'code': code}
resp = s.post(SUBMIT_URL, data=payload, allow_redirects=False)
if resp.status_code == 302:
rid = resp.headers['Location'].split('/')[-1]
print(f'提交成功!记录号:{rid}')
print(f'查看结果:{BASE}/record/{rid}')
else:
print('提交失败,状态码', resp.status_code)
if __name__ == '__main__':
main()5. 进阶玩法
5.1 VS Code 一键绑定
在 .vscode/tasks.json 里加:
{
"label": "submit",
"type": "shell",
"command": "python3",
"args": [
"${workspaceFolder}/submit.py",
"https://oj.example.com",
"${fileBasenameNoExtension}",
"alice",
"secret",
"${file}",
"cpp"
],
"group": "build"
}写完后 Ctrl+Shift+B 直接交题。
5.2 CI 自动回归
GitHub Actions 每晚跑模板题:
- name: 提交模板题
run: |
python3 submit.py https://oj.example.com 1000 bot bot template.cpp cpp
python3 submit.py https://oj.example.com 1001 bot bot template.py py5.3 多账号/多 OJ 配置
把账号密码写到 .env,脚本里用 python-dotenv 读取,避免明文泄露。
6. 常见坑 & 解决办法
现象原因解决登录 200 不 302密码错误或字段名不对浏览器抓包对比 uname/password/_csrf提交返回 403CSRF 失效确认 Referer,重新 GET 页面语言无效评测机代号变化打开下拉框查看 option value7. 一句话总结
把机械化的“点鼠标”变成可编程的“HTTP 请求”,
你就能在 任何地方、任何工具链 里完成“写完即交”。
脚本虽小,却能把刷题体验提升一个数量级。
Happy hacking,愿每一次 ./submit.py 都是一次愉快的 AC!
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]