震惊!别人的女朋友改口叫我爸爸!!!
写在前面的话:
我是一个潜水多年的水友, 这么多年来都是需要工具的时候才来, 也没有什么贡献, 今天在浏览论坛的时候突然发现一个惊人的事情, 创造太阳的女票居然喊他爸爸!!!! 这可亮瞎了我的钛金狗眼, 经过一番思绪后, 我决定抢走他的女票, 让他的女票喊我爸爸。于是就有了现在这篇文章。
在看我这篇文章之前如果你不明白我在干什么的话, 可以先去看一下这篇 创造太阳
的文章
女朋友急的叫“爸爸”了,我只好用python帮女朋友迅速完成问卷搜集任务... 好了, 该废话的都废话了, 下面我们开始来正式的讨论问题吧。
对问卷星页面的逆向
首先我们来打开这个调查问卷的页面
我们按 F12 先简单的看一看页面的 html
, 看一下有没有什么有用的信息:
这个时候我们发现这个提交按钮的 class
样式是 submitButton
了解了这里以后我们可以先随便提交一个, 看一看 devtools 能不能抓到像样的包, 有没有我们想要的数据
可以看到, 它在提交之后立刻做了一个刷新, 我并没有抓到想要的包, 当然,如果有不信邪的小伙伴可以自己试一下,
其实只要你手速够快, 完全可以抓住那个包的(手动滑稽)
那这里就很大可能性的说明这个提交信息的函数也包含有submit
的字样, 我们再来看一下它的资源
发现这里有一些js文件, 我们可以逐步的去每个js文件里面搜索一下看有没有 submit
相关的字样
功夫不负有心人, 在 jqnew2.js?v=1328
这个文件中有135个包含有 submit
的地方
我们逐一的进行排除一下, 发现在第 3194 行 出现了一个 function, 名为 submit
还带了一个参数 a
可以推测大概率是这里, 先在函数内部任意一个位置打上断点. 然后再随便填写一份问卷进行提交
我们可以看到, 在我们打断点的地方, 浏览器停了下来, 说明提交就是通过这里来的, 我们再仔细的看一下这个
函数, 发现最后有一行这样的内容:
d.send("submitdata=" + l)
说明这里是最终发送数据的地方, 我们在这里打上断点, 再次进行调试
截住后,我们通过控制台, 输入 l
来查看它发送的内容
"1%241%7D2%2445%7D3%244%7D4%244%7D5%241%7D6%241%7D7%244%7D8%242%7D9%242%7D10%247%7D11%241!1%2C2!1%2C3!1%2C4!1%2C5!1%2C6!1%2C7!1%7D12%241!1%2C2!1%2C3!1%2C4!1%2C5!1%2C6!1%7D13%242%7D14%241%7D15%241!1%2C2!1%2C3!1%2C4!1%2C5!1%2C6!1%7D16%241!1%2C2!1%2C3!1%2C4!1%2C5!1%2C6!1%2C7!1%2C8!1%7D17%241!1%2C2!1%2C3!1%2C4!1%2C5!1%2C6!1%2C7!1%2C8!1%2C9!1%2C10!1%7D18%241!1%2C2!1%2C3!1%2C4!1%2C5!1%2C6!1%2C7!1%2C8!1%2C9!1%2C10!1%7D19%241%7D20%241!1%2C2!1%2C3!1%2C4!1%2C5!1%2C6!1%2C7!1%7D21%241%7D22%241!1%2C2!1%2C3!1%2C4!1%2C5!1%2C6!1%2C7!1%2C8!1%2C9!1%2C10!1%2C11!1%2C12!1%7D23%24%E5%95%8A%E5%95%8A%E5%95%8A"
我们拿到了这样一段字符串, 很奇怪是吗? 我们来进行一下 urldecode, 看一下具体的内容是什么吧
"1$1}2$45}3$4}4$4}5$1}6$1}7$4}8$2}9$2}10$7}11$1!1,2!1,3!1,4!1,5!1,6!1,7!1}12$1!1,2!1,3!1,4!1,5!1,6!1}13$2}14$1}15$1!1,2!1,3!1,4!1,5!1,6!1}16$1!1,2!1,3!1,4!1,5!1,6!1,7!1,8!1}17$1!1,2!1,3!1,4!1,5!1,6!1,7!1,8!1,9!1,10!1}18$1!1,2!1,3!1,4!1,5!1,6!1,7!1,8!1,9!1,10!1}19$1}20$1!1,2!1,3!1,4!1,5!1,6!1,7!1}21$1}22$1!1,2!1,3!1,4!1,5!1,6!1,7!1,8!1,9!1,10!1,11!1,12!1}23$啊啊啊"
可以和我们的内容对比一下, 可以轻松的发现内容的格式就是
单选题, 填空题 的格式是:
题号$所选内容
多选题的格式是:
题号$所选内容1,所选内容2...
多行的选择题(不知道怎么描述了,如下图)的格式是 :
题号$行号!选项,行号!选项...
好的, 现在我们已经掌握了钥匙的大概样子了, 但是我们貌似还不知道门在哪里, 我们需要继续来调试, 找到大门最终的位置
我们看到了 请求是由 d
这个对象发出的, 我们来打印一下 d
对象, 看看能不能找到想要的内容:
看了一下打印结果, 貌似没有我们想要的内容, 那没有办法, 只能去翻看源码了, 看一下在哪里设置了什么东西
通过这里我们发现了他在发送请求之前先设置了请求头, 我们全局搜索一下, 发现只有这一个地方设置了请求头,
记录下请求头的内容,以备不时之需
headers = {"Content-Type": "application/x-www-form-urlencoded"}
再向上看, 发现有一句 这样的语句:
d.open(v, x, !1)
我们打印一下 v
的内容, 返回了一个 post
这下好了, 知道去大门的方式了, 但是走那条路呢?
还有一个 x
对象, 我们也打印出来看一下.
打印之后, 就会发现, x
对象是一个 url, 我们在控制台打印一下就会得到这个东西:
submittype=1&curID=88736026&t=1599929576059&starttime=2020%2F9%2F13%200%3A42%3A03&ktimes=851&rn=2006085889.87028755&hlv=1&jqnonce=9f0955dc-ee33-40a1-9950-e7f0cad9bde8&jqsign=8g1844eb%2Cdd22%2C51%600%2C8841%2Cd6g1b%60e8ced9&jpm=13
老规矩, 使用 url decode 看一下究竟是什么内容:
submittype=1&curID=88736026&t=1599929576059&starttime=2020/9/13 0:42:03&ktimes=851&rn=2006085889.87028755&hlv=1&jqnonce=9f0955dc-ee33-40a1-9950-e7f0cad9bde8&jqsign=8g1844eb,dd22,51`0,8841,d6g1b`e8ced9&jpm=13
好了, 这下子钥匙的完整样子都有了, 剩下的就是搞明白这些参数是干什么的, 然后进行模拟了.
具体的分析过程我就不说了, 有兴趣的小伙伴可以多多留言, 评论要是多的话, 我就发出怎么判断的
参数 |
猜测作用 |
submittype |
提交类型 |
curID |
问卷的标识id |
t |
提交时间戳 |
starttime |
文件开始的时间 |
ktimes |
相对于所有问卷,这是第几份问卷 |
rn |
系统变量, 直接填写就行了 |
hlv |
固定写 1 即可 |
jqnonce |
系统变量, 直接填写 |
jqsign |
jqnonce的签名信息 |
jpm |
尚不清楚是什么,影响不大 |
好, 有了 headers, 有了 参数, 我们就可以开始动手写代码了:
import re
import time
import requests
from urllib import parse
from string import ascii_letters
from random import randint, choice, sample
class WJXSimulHelper:
@staticmethod
def data_creator():
data = {
1: randint(1, 2),
2: choice(range(1995, 2010)),
3: randint(1, 5),
4: randint(1, 6),
5: randint(1, 2),
6: randint(1, 2),
7: "|".join(sample(['1', '2', '3', '4', '5'], randint(1, 5))),
8: "|".join(sample(['1', '2', '3'], randint(1, 3))),
9: "|".join(sample(['1', '2', '3', '4'], randint(1, 4))),
10: "|".join(sample([str(i) for i in range(1, 10)], randint(1, 9))),
11: ",".join([f"{index + 1}!{value}" for index, value in enumerate([randint(1, 6) for _ in range(1, 8)])]),
12: ",".join([f"{index + 1}!{value}" for index, value in enumerate([randint(1, 6) for _ in range(1, 7)])]),
13: randint(1, 2),
14: randint(1, 5),
15: ",".join([f"{index + 1}!{value}" for index, value in enumerate([randint(1, 6) for _ in range(1, 7)])]),
16: ",".join([f"{index + 1}!{value}" for index, value in enumerate([randint(1, 6) for _ in range(1, 8)])]),
17: ",".join([f"{index + 1}!{value}" for index, value in enumerate([randint(1, 6) for _ in range(1, 11)])]),
18: ",".join([f"{index + 1}!{value}" for index, value in enumerate([randint(1, 6) for _ in range(1, 11)])]),
19: randint(1, 3),
20: ",".join([f"{index + 1}!{value}" for index, value in enumerate([randint(1, 6) for _ in range(1, 8)])]),
21: randint(1, 3),
22: ",".join([f"{index + 1}!{value}" for index, value in enumerate([randint(1, 6) for _ in range(1, 13)])]),
23: "".join(sample(ascii_letters, randint(1, 26)))
}
return parse.quote("}".join([str(key) + '$' + str(value) for key, value in data.items()]))
@staticmethod
def param_creator():
questionnaire_url = "https://www.wjx.cn/jq/88736026.aspx"
page = requests.get(questionnaire_url).text
cur_id = re.findall(r" var activityId = '(.*?)';", page)[0]
jqnonce = re.findall(r'var jqnonce="(.*?)";', page)[0]
rn = re.findall(r'var rndnum="(.*?)";', page)[0]
ktime, now = randint(500, 2000), time.time()
t = int(now + randint(20, 70) * 1000)
start_time = parse.quote(time.strftime('%Y/%m/%d %H:%M:%S', time.localtime(now)))
jqsign = parse.quote("".join([chr((ord(char) ^ ktime % 10)) for char in jqnonce]))
params = {"submittype": 1, "curID": cur_id, "t": t, "start_time": start_time, "ktimes": ktime,
"rn": rn, "hlv": 1, "jqnonce": jqnonce, "jqsign": jqsign, "jpm": 13}
return "&".join([f"{key}={value}" for key, value in params.items()])
def data_sender(self):
data, params = self.data_creator(), self.param_creator()
url = f"https://www.wjx.cn/joinnew/processjq.ashx?{params}"
headers = {"Content-Type": "application/x-www-form-urlencoded"}
json_data = {"submitdata": data}
res = requests.post(url, json=json_data, headers=headers)
assert res.status_code == 200, "添加问卷失败"
print("添加问卷成功!")
if __name__ == '__main__':
spider = WJXSimulHelper()
spider.data_sender()
OK ! 到这里就结束了,效率提高了, 速度变快了, 人也不虚了, 还等什么? 找他女朋友去, 让她叫我爸爸!!!!
哈哈哈哈
注 : 本文不针对任何人发出敌对信号, 所有言辞均为写作效果, 请勿当真, 如果感觉不适请联系我删除