小玩具01:编写WSIS自动投票油猴脚本

这是1月9号的事了,kang哥在群里发了一个消息,说是需要大家帮忙WSIS奖投票。让每位同事都投一遍。我看了下投票步骤说明文档,其实挺麻烦的。最主要的是足足有18项,需要一个个的点击才能完成。旁边的JackyTsuuuy大佬慢悠悠的蠕动着他性感的小胡须,说道可以尝试使用js自动点击完成这18项选择,还提供了最朴素的几行代码。在他几次怂恿下决定实现这一想法。

一、需求

当时发的投票步骤说明文档具体需求如下:

投票页面有18个Category,每完成一个Category的投票就会自动进行下一个Category页面,需要完成所有18个Category的投票。注意:重点在Category5-AL C5选择 Artificial Intelligence (AI) based spam messages and calls prevention solution ,其他Category可以任意选。

二、思路

判断页面是否有内容为“Artificial Intelligence (AI) based spam messages and calls prevention solution”选项的按钮,如果有就点击,没有就随机选择一个选项。然后进入下一页,等待页面加载完成继续重复上面的操作。其实思路很简单,代码实现也不难,但是细节问题却耐人寻味,想给大家分享下。

三、实现

通过前端分析,发现内容为“Artificial Intelligence (AI) based spam messages and calls prevention solution”选项对应着是一个标签名为button,属性value的值为15434938390848023的按钮。

分析要点击的页面元素

注意:定位选择的属性名和属性值在当前页面是唯一的,这样才能保证点击正确。

实现定位目标选项的代码如下:

1
2
3
4
5
6
7
8
9
10
/*定位要点击的页面元素*/
function getTargetByTAV(t_tag,t_attr,t_value){
var target = document.getElementsByTagName(t_tag);
for(var i=0;i <target.length;i++){
if(target[i].getAttribute(t_attr) == t_value){
return target[i];
}
}
}
var target = getTargetByTAV("button","value","15434938390848023");

当页面没有内容为Artificial...solution对应的选项时,就随机选择一项点击。分析页面发现每个选项对应的按钮元素都有name="voteProjectId",我们以此来定位它们。实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
// code refence: https://www.cnblogs.com/phpyangbo/p/6129868.html
function RandomNum(Min, Max) {
var Range = Max - Min;
var Rand = Math.random();
var num = Min + Math.floor(Rand * Range); //舍去
return num;
}

function getTargetByRandom(){
var target = document.getElementsByName("voteProjectId");
var n = RandomNum(0,target.length);
return target[n];
}

最后呢,为了保证点击成功,我们设置每间隔100ms就重复点击一次。实现代码如下:

1
2
3
4
5
setInterval(function() {
if (button) {
button.click();
}
},100);

将以上代码放到浏览器开发者工具的console中执行是可以的,但是会存在一个问题。那就是页面刷新后,我们编写的代码将不会作用于新的页面。为了解决这个问题,当然可以编写一个浏览器插件来解决,但是油猴已经做好了这个工作。我们只需要站在巨人的肩膀上,完成我们的想法即可。

按照油猴的脚本编写规则,最终源码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// ==UserScript==
// @name wsis-auto-vote
// @namespace http://gv7.me
// @version 0.1
// @description wsis 自动投票,自动投"Artificial Intelligence (AI) based spam messages and calls prevention solution"选项。
// @author c0ny1
// @match https://www.itu.int/*
// @grant none
// ==/UserScript==

(function() {
'use strict';

/*定位要点击的页面元素*/
function getTargetByTAV(t_tag,t_attr,t_value){
var target = document.getElementsByTagName(t_tag);
for(var i=0;i <target.length;i++){
if(target[i].getAttribute(t_attr) == t_value){
return target[i];
}
}
}

// code refence: https://www.cnblogs.com/phpyangbo/p/6129868.html
function RandomNum(Min, Max) {
var Range = Max - Min;
var Rand = Math.random();
var num = Min + Math.floor(Rand * Range); //舍去
return num;
}
/*随机获取一个要点击的页面元素*/
function getTargetByRandom(){
var target = document.getElementsByName("voteProjectId");
var n = RandomNum(0,target.length);
return target[n];
}

var btn;
btn = getTargetByTAV("button","value","15434938390848023");
if(btn === undefined){
btn = getTargetByRandom();
}

setInterval(function() {
if (btn !== undefined) {
console.log("[+] click obj: " + btn.innerHTML);
btn.click();
}else{
console.log('[-] click obj is undefined!');
}
},3000);

})();

最终效果

五、延伸

刚才是一个具体场景下的代码实现。但是我思考了下,其实我们生活中还有很多场景,可以通过快速重复点击页面元素来解决。比如春节的刷票,大学的抢课,双11的抢购等等。也许有人有疑问,使用burp多次重放数据包不就可以了么?其实这样不一定行,因为请求可能需要提交token或者其他需要浏览器执行js获取到的数据。

于是我改基于以上代码,编写了一个适合更多场景下快速重复点击页面元素的油猴脚本。该脚本已经在油猴的在线脚本库Greasy Fork发布了,想看最新源码或者使用的朋友请点击这里

该脚本提供了通过以下几种方式获取需要点击的页面元素:

序号 定位方式 描述
1 id 提供页面要点击元素的id,赋值给id变量即可
2 标签名,属性,属性值 提供页面要点击元素的标签名,属性,属性值分别给tag,attr,value即可
3 xpath 提供页面要点击元素的xpath,赋值给str_xpath变量即可
4 selector 提供页面要点击元素的selector,赋值给str_qs变量即可
5 自定义定位函数 以上方式无法定位到目标元素,可以将isCustom变量赋值为true,同时编写getTargetByCustom函数的函数体,返回定位成功的元素即可

具体使用方法请移步Greasy Fork

六、最后

最后给大家留一个思考: 该如何权衡我们脚本点击提交的速度和成功率?

  1. 如果我们的脚本点击按钮过快,可能表单某些必要的值(比如token,需要每次发送ajax请求来更新)还没有被加载。从而导致提交失败。
  2. 如果等待所有资源都加载完成,然后脚本在进行点击操作,这样又太慢展现不了脚本的优势(比如抢购场景下)。

考虑这些特殊情况,会让我们的脚本更加壮硕,欢迎留言讨论。