news 2026/9/13 13:23:49

Python问卷星自动填写:requests构造HTTP请求实现批量提交

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python问卷星自动填写:requests构造HTTP请求实现批量提交

简介:这份基于Python实现的问卷星自动填写工具,主要面向希望学习自动化脚本编写的小白与进阶学习者,可作为毕业设计、课程设计或工程实训项目。资源共7个文件,包含2个Python核心脚本、3个XML配置、1个说明文档及1个工程文件,压缩包仅9KB,结构轻量、便于阅读。目前已有541人学习下载。通过源码和说明文档,读者能了解问卷页面元素的定位思路、表单数据自动填充与提交的完整流程;README给出运行指引,.idea配置方便直接导入PyCharm调试。整个项目虽小,却具备小型自动化工具的典型工程结构,从可实现自动填写问卷的核心脚本到项目配置文件一应俱全,非常适合作为学习Python自动化方向的第一个实战练手项目。

1. 用Python把问卷星提交链路拆开,批量填写才谈得上可控

手动填写问卷星的痛苦,做过调研的人都懂:一份问卷十几个题,单选多选填空矩阵混在一起,页面还要等动画、点验证、等提交,五十份样本意味着一个下午搭进去,而且手点出来的答案往往集中在“A、B、C”上,后台一查质量分直接飘红。这个基于Python实现的问卷星调查问卷自动填写工具,本质上是把浏览器里“读题、选题、点提交”这一整条链路抽出来,直接构造合法的HTTP数据包发给问卷星服务器。它解决的不是“破解问卷星”,而是“高效、可控地生成有效样本”这件事,适合做问卷调查数据采集的运营、做毕设需要批量样本的学生、以及想练手HTTP协议与表单自动化的Python学习者。换装Selenium那种重型方案,这个工具用纯requests实现,对运行环境的要求低得多,逻辑也更贴近问卷星的真实请求模型。

2. 问卷星提交背后的请求模型:surveyId、rn 与 POST 载荷

2.1 先抓页面源:题面JSON就在HTML里

问卷星的问卷页面虽然是动态渲染的,但题面数据并没有走额外的异步接口,而是直接以JSON形式嵌入在HTML源码中。常见做法是用requests把https://www.wjx.cn/vm/xxxxx.aspx这个地址抓下来,然后通过正则或者简单的字符串截取拿到surveyIdshortId,再往后就是构造提交请求的核心参数。我一般会先写一个探测器,把页面源码里的关键字段脚本片段打印出来确认格式,再去写正式的解析逻辑。

import re import requests headers = { "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" } def fetch_question_page(url): resp = requests.get(url, headers=headers, timeout=10) resp.encoding = "utf-8" html = resp.text # 问卷星会在HTML里写 r.config = {...},surveyId 在其中 match = re.search(r"surveyId[^\d]+(\d+)", html) if not match: raise RuntimeError("未在页面中定位到 surveyId,请确认链接类型") return html, match.group(1) page_html, survey_id = fetch_question_page("https://www.wjx.cn/vm/example.aspx") print("surveyId:", survey_id)

这里surveyId是问卷的唯一标识,提交时服务器靠它找到对应的问卷定义。resp.encoding必须设置成utf-8,问卷星返回的页面带有中文题面,如果不处理编码,后续正则提取和答案生成都会出现乱码错位。

2.2 提交接口与必带参数

拿到题面后,下一步是构造POST请求。问卷星的提交地址是https://www.wjx.cn/joinnew/processjq.ashx,常见的表单字段包括submittypecurIDtstartTimernhlvsjqnonce等。这里面最关键的是rn,这是一个随机数,用来标记本次作答的会话;startTime是问卷打开的Unix时间戳;t是本次作答消耗的秒数。还有要把题型答案合并成joinAnswer字段,字段值以特定的分隔符拼接。

我一般建议在浏览器开发者工具里手动提交一次问卷,把Form Data完整复制出来比对。因为问卷星的字段会随站点改版调整,项目里的wjx_auto_submit.py如果某天提交失效,第一步不是改代码,而是重新核对这张表单的参数名。以下是工具里构造基础载荷的骨架:

def build_base_payload(survey_id, start_time, answer_str): return { "submittype": "1", "curID": survey_id, "t": str(int(__import__("time").time()) - start_time), "startTime": str(start_time), "rn": str(__import__("random").randint(100000, 999999)), "hlvs": "", "jqnonce": "", "joinAnswer": answer_str, }

t字段如果填0或一个固定值,后台作答时长分布会异常,容易被判定为机器提交。一般会在生成答案后,用当前时间减去startTime,并且让这个差值落在15到40秒之间,模拟真人阅读和作答的节奏。

2.3 Python环境准备与依赖管理

运行这个工具只需要Python 3.6以上版本,第三方依赖只有requests。如果你还没配置Python环境,可以参考常规的python安装教程,装完后在命令行确认python --version能正常打印版本号。随后在项目目录里执行:

pip install requests

如果网络环境受限,可以换成清华或阿里云的镜像源:

pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple

依赖就这一个,不需要Selenium,不需要浏览器驱动,这也是纯requests方案最大的优势:部署轻、启动快、对服务器环境友好。

3. 实现wjx_auto_submit.py的核心:题型解析与随机答案生成

3.1 题型识别与答案槽位

问卷星的题面JSON虽然字段名是拼音缩写,但结构相对稳定。工具拿到页面源码后,从HTML中截取出QuestionData脚本段,再用json解析。每一道题的结构里都会包含type字段,常见的取值有1(单选)、2(多选)、3(填空)、4(矩阵)以及5(量表)。解析的目标是把每道题的idtype、选项个数提取出来,整理成一组“答案槽位”。

以下是一个简化的解析逻辑,只保留最核心的结构判断,便于理解工具的运行方式:

import json import re def extract_questions(html): # 取出题面JSON m = re.search(r"QuestionData\s*=\s*(\{.*?\});", html, re.S) data = json.loads(m.group(1)) questions = [] for qid, q in data.items(): qtype = q.get("type") # 题号可能要跳过标题说明类占位题 if qtype in (1, 2, 3, 4, 5): questions.append({ "id": qid, "type": qtype, "options": q.get("options", []) }) return questions

这里q.get("options")得到的是选项编号或选项文本列表,具体结构要看问卷编辑器的保存格式。单选和多选题的答案参数最终是选项的编号,填空则是写入的字符串,矩阵题的答案相对复杂,每一行的选项都要单独组成子答案。

3.2 随机答案生成:覆盖维度而不是均匀铺开

“自动填写”的难点在于生成一份看起来像真实用户的答案。如果每题都随机选一个,确实能跑通提交,但样本答案的分布会非常不自然,比如矩阵题全选“非常满意”,或者连续十份问卷的性别比例严重失调。工具里一般会为每一类题型定义独立的生成函数,并在生成时控制分布。

import random def generate_answer_for_question(q): qtype = q["type"] opt_count = len(q["options"]) if q["options"] else 1 if qtype == 1: # 单选,选一个 return random.randint(1, opt_count) elif qtype == 2: # 多选,至少选一个,最多选全部 n = random.randint(1, opt_count) return ",".join( str(i) for i in sorted(random.sample(range(1, opt_count + 1), n)) ) elif qtype == 3: # 填空,从候选词库里抽 return random.choice(["较为满意", "建议优化", "暂无补充"]) elif qtype == 4: # 矩阵题,每行一组选择 row_answers = [] for row in q["options"]: row_answers.append(str(random.randint(1, len(row.get("col", [1]))))) return "|".join(row_answers)

单选答案用randint从1到选项数之间取,多选答案用sample保证不重复。这里有一个容易踩的细节:多选题的选项编号虽然返回的是逗号分隔字符串,但提交到joinAnswer时,不同题型的答案之间由/分隔,多选内部的多个选项之间则是,,这两层分隔符不能混用。矩阵题的每行答案用|连接,整套规则需要对照真实表单参数做一次验证,否则提交时服务器解析答案会错位。

3.3 拼接joinAnswer并组织完整答案串

解析完所有题并生成每题答案后,剩余的工作就是把答案按照问卷顺序拼成joinAnswer。在这个过程中要过滤掉非必答的题,也要把矩阵题和下拉题的格式统一。工具里会维护一个final_answers列表,按题号加大到对应的答案字符串,最后用/连接:

def build_join_answer(questions, answers): parts = [] for q in questions: ans = answers[q["id"]] # 多选题的逗号保持不变,这里只负责外层拼接 parts.append(str(ans)) return "/".join(parts)

这一步越是简单越容易出事。joinAnswer里如果混入某个题的空值占位符,服务器可能直接返回“请完成所有必填题”。所以我在工具里对每道题的生成结果都做了一次断言,确认不是None或空串;如果发现填空题没有落进候选词库、或者多选答案编号超出了选项范围,直接抛异常终止提交,避免把坏数据发给服务器。

4. 提交执行与质量校验:跑通提交并拦截典型错误

4.1 POST提交与响应判断:success字段是唯一的金标准

构造好载荷后,提交逻辑并不复杂。但关键点在于响应判断:问卷星成功接收答卷时,返回的JSON里success字段为true;反之一旦请求被拦截、答案校验失败,返回的会有msg字段来描述失败原因。很多自动填写脚本挂在提交后没有做响应校验,导致“以为是成功的,实际后台是废卷”。工具的提交线程应该有如下结构:

import requests import time def submit_answer(url, payload, headers): submit_url = "https://www.wjx.cn/joinnew/processjq.ashx" try: resp = requests.post(submit_url, data=payload, headers=headers, timeout=10) result = resp.json() except Exception as exc: # 网络波动或返回非JSON时,做一个可重试的标记 return False, f"请求异常: {exc}" if result.get("success"): return True, "提交成功" return False, result.get("msg", "未知失败原因")

提交接口收到响应后,工具把success字段作为记录依据。失败的响应信息通常有比较明显的特征,比如“亲,请完成所有必填题目”说明答案是空串;“请求太频繁”说明发送间隔太短;“参数错误”则往往是surveyId或者joinAnswer组装与当前问卷结构不匹配。后端拿到失败原因后,写入本地日志文件,这样跑批量任务时不用盯着控制台,事后去看日志即可定位问题分布。

4.2 作答节奏控制:别让时间戳暴露脚本特征

问卷星的服务器端有基础的频率识别,同一IP在极短时间内提交几十份问卷,很容易触发“验证码挑战”。工具里常用两种策略规避:一是每一份问卷提交后固定sleep一段随机区间,二是将t(作答时长)与sleep联动,让整体提交节奏贴近人工操作。

import random import time interval = random.uniform(8, 20) print(f"等待 {interval:.1f} 秒后继续...") time.sleep(interval)

间隔的上下限要考虑问卷实际长度,一份40题的问卷,正常人至少需要1到2分钟,8到20秒显然不合理。常见的做法是拿题目数量乘以每题的阅读时间作为下限,同时叠加一个random.uniform(5, 15)的噪声。这样既不会触发频率限制,也不至于让整个批量任务跑得太慢。

4.3 常见拦截场景与工具侧的应对

实际运行中,最常遇到的拦截是“作答时间过短”和“答案格式非法”。作答时间过短已在payload的t字段做了处理;答案格式非法则通常发生在矩阵题与下拉题混合的问卷里。矩阵题提交的joinAnswer子串需要和题面JSON里的col数量严格对齐,多一个或少一个分隔符都会导致服务端解析失败。

另一个容易被忽略的问题是Cookie。浏览器里提交问卷时,页面加载会种下wjx_开头的Cookie,而纯requests方式若完全不携带Cookie,部分问卷模板可能不会报错,但统计后台会记录到异常会话。我在工具里保留了一个requests.Session()来发请求,每次打开问卷页和提交答卷共用同一个Session,让Cookie自然延续。

session = requests.Session() session.headers.update(headers) html, survey_id = fetch_question_page(url, session) # 中间解析与生成答案... ok, msg = submit_answer(url, payload, session.headers)

这样处理的理由是,问卷星的rn参数和Cookie存在关联,Session复用时服务端能识别为同一条会话链,降低了“问卷页面还没打开就直接提交”的异常概率。

5. 从单次提交演进到批量任务:命令行参数与多问卷配置

当工具能稳定提交一份问卷后,下一步是把它改造成可批量执行的命令行程序。我在入口处增加了三个参数:-u指定问卷链接,-n指定提交份数,-d指定相邻两次提交的间隔范围。这样不用改代码,就能针对不同问卷、不同样本量做调整。

python wjx_auto_submit.py -u "https://www.wjx.cn/vm/example.aspx" -n 30 -d 10-30

命令行解析用argparse实现,-d接收类似10-30的字符串,程序内部分割成两个浮点数,再传给random.uniform。这样做比写死在代码里灵活很多:上午跑样本量小的预调研,下午跑正式采集,只需换参数,不用动逻辑。

批量模式下还要加一份“运行统计”的小功能,把成功数、失败数、失败原因分类打印到控制台末尾。如果某次任务失败率达到10%以上,工具会主动停下,而不是继续空转浪费请求频率。这个阈值不是拍脑袋定的,问卷星的拦截通常是突发式的,一旦开始返回“请求太频繁”,后面连续提交大概率都会失败,及时熔断比盲目重试有效。

最后,建议在一批问卷提交完成后,用统计后台的“答卷详情”页面做一次人工抽样,核对5到10份答卷的答案分布与提交时间戳。这一步看起来是额外操作,但实际上是对工具本身最好的验证:如果提交时间戳的间隔与t字段差值对不上,说明payload构造仍有偏差;如果答案分布过于均匀,比如每道单选ABCD出现的次数完全一致,那可能是随机种子用得太规整,下一轮任务可以换成基于问卷ID加时间戳的随机种子,让分布更接近自然作答。

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

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

C++与FPGA协同设计:提升嵌入式系统性能的关键

1. 为什么需要C与FPGA协同设计 在嵌入式系统和高性能计算领域,硬件加速已成为突破性能瓶颈的关键手段。FPGA(现场可编程门阵列)因其并行计算能力和可重构特性,成为许多实时处理系统的核心组件。但纯FPGA开发存在两个致命缺陷&…

作者头像 李华
网站建设 2026/9/13 13:21:19

华为OD机试Python环境适配与IO规范实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 13:17:32

从图层思维到节点思维:Substance Designer节点材质制作核心指南

1. 从图层思维到节点思维:这一步迈过去,SD才算真正上手 我第一次打开Substance Designer的时候,说实话是有点懵的。界面里没有图层,没有画笔工具,只有一个空荡荡的图表面板,左边拖一个节点、右边连一根线&a…

作者头像 李华
网站建设 2026/9/13 13:17:03

皮带机设计小软件实操指南:从逐点张力到电机功率校验

简介:面向机械工程师与设备维护人员的皮带机设计轻量级工具包,针对物料搬运、产线输送、散料转运等场景,提供布局绘制、传动参数计算、张力与功率校核、运动仿真等小型化功能,适合需要快速完成皮带输送系统方案验证的日常设计工作…

作者头像 李华
网站建设 2026/9/13 13:15:08

Simulink强化学习机器人自适应控制实现指南

简介:一款面向智能控制研究者与机器人方向学生的 MATLAB Simulink 强化学习控制实现,以自适应控制为主线,结合经验回放等机制,让机器人能在未知或变化环境中实时调整策略。压缩包共 127 个文件,其中 106 个 m 脚本是核…

作者头像 李华
网站建设 2026/9/13 13:14:14

UEFITool-UE固件解析工具深度指南:CSE/RTS/GPT修复与Secure Boot审计

简介:本资源是面向UEFI固件开发者、系统安全工程师及固件逆向研究者的专业工具包,提供UEFITool-UE 0.10.0稳定版本源码,用于深度解析、调试与定制UEFI固件镜像。包内共70个文件,以33个头文件(h)、18个C源码…

作者头像 李华