VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 网站开发 > JavaScript >
  • JavaScript教程之一个基于chrome扩展的自动答题器

1、写在前面

首先感谢小茗同学的文章-【干货】Chrome插件(扩展)开发全攻略,

基于这篇入门教程和demo,我才能写出这款

基于chrome扩展的自动答题器。

git地址: https://gitee.com/cifang/lighthouse_answering_machine.git

2、开发背景

去年12月,某省委组织部举办了一系列学习竞赛活动,第一期时,参加人数寥寥,在第二期时,便通过党组织渠道要求所有党员保质保量的参加。

该活动每期10天,每天有一次答题机会,每一期通过分享可获得额外两次。每次答题则是在题库中随机抽取(后来发现并不那么随机)单选和多选共20道题。

该活动可在专门的app上参加,也可通过官方网站参加。

既然是基于网页的并且支持chrome内核的考试系统,那自然能从前端入手进行操作。

3、主要功能迭代

1月11日,开发出脚本版本答题器。通过控制台(F12)运行脚本并自动作答。2月初,开始学习chrome扩展相关内容

2月21日,发布第一版答题器,主要功能有

  • 1、打开活动主页、用户登录页;
  • 2、清除登录信息;
  • 3、记录并切换帐号;
  • 4、自动标记正确答案;
  • 5、自动答题并交卷。 

3月4日,增加了了添加自定义试题及答案的功能。

3月12日,增加了用户信息导入导出功能,自动分享获取答题次数功能。

3月20日,增加了全自动答题功能。

4月20日,增加了伪造回传鼠标点击坐标的功能。

5月14日,增加了在线更新的功能

至此,答题器的功能已基本成熟,最终答题器的界面如下:

4、结构拆解与代码分析

chrome扩展的文档结构在小茗同学的文章中描述的很清楚了。为了便于开发,我最终决定使用popup,content 和 inject 相互配合通讯来实现本程序的功能。

整个程序的存储由 content 部分来处理,存放于 chrome.storage.local 中,popup和inject在需要时从 content 更新数据,同时如果用户修改了设置也及时反映给 content 进行保存。

popup的js代码如下:(我觉得我备注的还可以)

复制代码
  1 var config;//设置
  2 var auto_all_ans=0;//全自动答题标志
  3 
  4 $(function() {
  5 
  6     // 加载设置
  7     //config = {'set':{'save_login': 1, 'sign_ans': 1, 'auto_ans': 0}, 'login_info':{}, 'active':''}; // 默认配置
  8 
  9     //打开活动页面
 10     $('#open_page').click(function()
 11     {
 12         chrome.tabs.create({url: 'http://xxjs.dtdjzx.gov.cn/index.html'});
 13     })
 14     //打开登陆页面
 15     $('#open_login_page').click(function()
 16     {
 17         getCurrentTabId(tabId => {
 18             chrome.tabs.update(tabId, {url: 'https://sso.dtdjzx.gov.cn/sso/login'});
 19         });
 20     })        
 21     //清除登录信息
 22     $('#open_logout_page').click(function()
 23     {
 24             sendMessageToContentScript(    
 25             {'cmd':'logout','data':{}},
 26             //回调函数
 27             function(response){if(response) {}}
 28             );
 29             //删除active类
 30             $('.active').removeClass('active');
 31     })
 32 
 33     //显示、隐藏设置区域
 34     $('#hide_config').click(function(){
 35         $('#hide_config').hide();
 36         $('#show_config').show();
 37         $('#config').hide(500);    
 38     })
 39     $('#show_config').click(function(){
 40         $('#show_config').hide();
 41         $('#hide_config').show();
 42         $('#config').show(500);    
 43     })    
 44 
 45         
 46     //手动更新
 47     $('#update').click(function(){
 48         $(this).html('更新中...');
 49         $(this).css('pointer-events','none');
 50 
 51         var xhr = new XMLHttpRequest();
 52         xhr.open("GET", "http://mydomain/dengta/update.php?v="+config['set']['date_version'], true);
 53         xhr.onreadystatechange = function() {
 54             if (xhr.readyState == 4) {
 55             // JSON解析器不会执行攻击者设计的脚本.
 56                 //var resp = JSON.parse(xhr.responseText);
 57                 //console.log(resp);
 58                 if(resp=xhr.responseText)
 59                 {
 60                     //console.log(resp);
 61                     
 62                     //清空原有扩展题库
 63                     sendMessageToContentScript({'cmd':'del_new_ques'}),
 64 
 65                     //第一行是最新的版本号,并保存设置
 66                     setTimeout(()=>{
 67                         config['set']['date_version']=resp.match(/(\/\/)(\S*)/)[2];
 68                         console.log(config);
 69                         save_set();
 70                     },1000);
 71                         
 72 
 73                     //通过update函数向content更新补充题库
 74                     setTimeout(()=>{update(xhr.responseText);},2000);
 75 
 76                     //弹出提醒
 77                     //alert('已更新数据至'+config['set']['date_version'])
 78                 }
 79                 else
 80                 {
 81                     alert('已是最新版本')
 82                 }
 83             }
 84         }
 85         xhr.send();
 86 
 87         setTimeout(()=>{$(this).html('已更新'+config['set']['date_version']);},2000);
 88     })    
 89 
 90     //切换上一人、下一人功能
 91     $('#prev_one').click(function(){
 92         $('#login_info_conf .active').prev().find('.login_info_change').click();                
 93     });
 94     $('#next_one').click(()=>{
 95         $('#login_info_conf .active').next().find('.login_info_change').click();                
 96     })
 97 
 98     //导入导出功能
 99     $('#input_login_info').click(()=>{
100     
101         var new_login_info=$('#input_login_info_box').val();
102         //测试是否有效
103         try
104         {
105             new_login_info=JSON.parse(new_login_info);
106         }
107         catch (err)
108         {
109               txt="您输入的字符串有误,请重新查证。";
110               alert(txt);        
111         }
112         //成功转化的字符串
113         //console.log(new_login_info);
114         if(typeof new_login_info === 'object')
115         {
116             console.log(new_login_info);
117             $.extend(config['login_info'],new_login_info);
118             //向content_script报告新加入的用户
119             sendMessageToContentScript(    
120                 {'cmd':'add','data':new_login_info},
121                 //回调函数
122                 function(response){if(response) {
123                 }}
124             );
125             alert('导入完成');
126         }
127     });
128     //登录信息导出
129     $('#output_login_info').click(()=>{
130         $('#input_login_info_box').val(JSON.stringify(config['login_info']));        
131     });
132     //全自动答题功能
133     $('#auto_all_ans').click(()=>{
134         auto_all_ans=1;
135         $('.login_info_change').each((i,v)=>{
136             
137             setTimeout(()=>{
138                 $(v).click();
139             },(config['set']['dtime']*1000+500)*53*i+1000);
140                 
141         });
142     })
143 
144     //函数:向content保存设置
145     function save_set(){                
146         var res={
147                 'cmd':'set_conf',
148                 'data':{
149                     'save_login': $('#save_login').get(0).checked?1:0,
150                     'sign_ans': $('#sign_ans').get(0).checked?1:0,
151                     'sign_ans_mouseover': $('#sign_ans_mouseover').get(0).checked?1:0,
152                     'auto_ans': $('#auto_ans').get(0).checked?1:0,
153                     'dtime':parseFloat($('#dtime').val()?$('#dtime').val():3),
154                     'date_version':config['set']['date_version']
155                 }
156         };
157         console.log(res);
158         sendMessageToContentScript(    
159             res,
160             //回调函数
161             function(response)
162             {
163                 if(response) 
164                 {
165                     
166                 
167                 }
168             }
169         );
170         //chrome.storage.local.set(res['data']);
171         config['set']=res['data'];
172         console.log(res);
173     }
174 
175     //函数:向content递交补充题库
176     function update(data){
177         var new_data=data.split(/[\n]+/g);
178         console.log(new_data);
179         var len=new_data.length;
180         var j=0;//题目答案计数器
181         var new_question='';
182         var new_answer='';
183         var new_ques_arr=[];
184 
185         //第一个不为空的数组为试题
186         for(var i=0;i<len;i++){
187             //如果是备注的话,就跳过改行
188             if(new_data[i].match(/^\/\//))
189                 continue;
190             //第0、2、4、6..行是题目
191             //第1、3、5、7..行是答案
192             if(j%2==0)
193             {
194                 new_question=new_data[i].replace(/[ABCD. \r\n]/g,'');
195             }
196             else
197             {
198                 new_answer=new_data[i].replace(/[ABCD. \r\n]/g,'');
199                 new_ques_arr.push([new_question,new_answer]);
200 
201                 new_question='';
202                 new_answer='';                        
203             }
204             j++;
205         };
206         //向前端发送命令
207         if(new_ques_arr.length>0)
208         {
209             //对无关信息过滤
210             var res={
211                 'cmd':'set_new_ques',
212                 'data':new_ques_arr
213             };
214             
215 
216             sendMessageToContentScript(    
217                 res,
218