情境分析
最近遇到老师用Google表单给了考古题,但是答案要自己找的作业,里面题目也没有附题号,所以如果写完题目后按提交,就不知道自己到底写了啥不能複习(也不能跟同学对答案
于是,我就想要一个可以快速汇出我在Google表单填的资料的方法,假设表单只有一页,可能是大量的单选题。
最初的想法
说到这里,想想大概就是用js,在console印出来是最简单暴力的,所以第一个被我找到的是jQuery的serializeArray(),这个以前也有人讨论过(参考资料)
只要找到form元素的id,jQuery就帮你表单的所有input的value汇整到一个阵列里了,前提是要自己引入jQuery,于是我就迅速写了以下js挂到console上:
var s = "";var formId = "mG61Hd"; //表单元素idvar qNumbers = 50;var ansArray = $("#"+formId).serializeArray();for (var i = 0; i < qNumbers ;i++) {s += (i+1) + ":";s += ansArray[i]["value"];s += "\n";}console.log(s);
谁知道后来发现只有我能用,同学汇出竟然都是乱序的这样就对不了答案了,才知道似乎是Google表单在储存草稿,重新整理后,每个input的name里面的序号会重新打乱,最后serializeArray()照name排列出来的顺序就是乱的,而我是网页一直开着没有重整。
好吧,那只好认真花点时间来研究...
后记(雪上加霜):本来引入jQuery我会暴力地找个CDN,把整个js档内容複製贴到cosole执行,就完成脚本的载入了,后来我写文章的时候发现Google Form更新过,用了TrustedHTML(简单来说就是一个白名单让我没办法轻易地载入外来脚本),所以这个方法就真的失效了(除非哪天我知道可以怎么绕过)
认真一回
认真看了几眼前端程式,我找到"FB_PUBLIC_LOAD_DATA_"这个变数,里面有表单名称,网址等等,有所有题目和其序号的对照在FB_PUBLIC_LOAD_DATA_[1][1]
里。
所以逻辑如下:
FB_PUBLIC_LOAD_DATA_[1][1][题号][4][0][0]
得到每题的专属序号(identifier)蒐集整个表单的所有input元素遍历找到刚刚取得的序号的input元素,得到他的value,就是我们填写的答案现在我们有了对应的题号,作答内容,甚至有题目(在FB_PUBLIC_LOAD_DATA_[1][1][题号][1]
),就可以输出想要的结果了值得一题的是,FB_PUBLIC_LOAD_DATA_[1][1]
里面的顺序不会因为表单的随机决定问题顺序设定打乱,汇出的顺序每个人每一次还是会一样初步写的程式:
var formId = "mG61Hd"; // 表单IDvar form = document.getElementById(formId); // 获取表单元素var shuffledAns = form.getElementsByTagName("input"); // 获取所有input元素var result = "";FB_PUBLIC_LOAD_DATA_[1][1].forEach((question, QNumber) => { var sortedId = question[4][0][0]; // 记录序号的位置 for (var i = 0; i < shuffledAns.length; i++) { if (shuffledAns[i].name == "entry." + sortedId) { result += QNumber + 1 + ":"; result += shuffledAns[i].value; result += "\n"; } }});console.log(result);
试着用些进阶点的语法:
//google表单印出优化版var formId = "mG61Hd"; // 表单IDvar shuffledAns = document.getElementById(formId).getElementsByTagName("input"); // 获取表单中所有的input元素var result = "";FB_PUBLIC_LOAD_DATA_[1][1].forEach((element, questionNumber) => { var sortedId = element[4][0][0]; // 记录序号的位置 Array.prototype.some.call(shuffledAns, (element) => { var findAns = element.name == "entry." + sortedId; if (findAns) { result += questionNumber + 1 + ":"; result += element.value; result += "\n"; } return findAns; // 找到答案时返回true,让some()结束遍历 });});console.log(result);
输出结果:
可惜下面的参考资料再我写完后才找到的,也许就能省下点时间,但他分析的更完整,也有介绍非单选题以外的答案怎么判断和取得,有兴趣的可以参考看看
参考资料
https://theconfuzedsourcecode.wordpress.com/2019/12/15/programmatically-access-your-complete-google-forms-skeleton/