不光问卷搜集, 还让别人的女朋友叫我爸爸 !!!
本帖最后由 miss85246 于 2020-9-13 06:11 编辑## 震惊!别人的女朋友改口叫我爸爸!!!
### 写在前面的话:
>我是一个潜水多年的水友, 这么多年来都是需要工具的时候才来, 也没有什么贡献, 今天在浏览论坛的时候突然发现一个惊人的事情, 创造太阳的女票居然喊他爸爸!!!! 这可亮瞎了我的钛金狗眼, 经过一番思绪后, 我决定抢走他的女票, 让他的女票喊我爸爸。于是就有了现在这篇文章。
在看我这篇文章之前如果你不明白我在干什么的话, 可以先去看一下这篇 `创造太阳` 的文章
[女朋友急的叫“爸爸”了,我只好用python帮女朋友迅速完成问卷搜集任务...](https://www.52pojie.cn/forum.php ... tpost%26typeid%3D29)好了, 该废话的都废话了, 下面我们开始来正式的讨论问题吧。
### 对问卷星页面的逆向
首先我们来打开这个调查问卷的[页面](https://www.wjx.cn/jq/88736026.aspx)
我们按 F12 先简单的看一看页面的 `html`, 看一下有没有什么有用的信息:
![](https://gitee.com/Connor_Zhang/Blog/raw/master/Pics/%E5%98%8E%E5%AD%90-1599927962255.png)
这个时候我们发现这个提交按钮的 `class` 样式是 `submitButton`
了解了这里以后我们可以先随便提交一个, 看一看 devtools 能不能抓到像样的包, 有没有我们想要的数据
![](https://gitee.com/Connor_Zhang/Blog/raw/master/Pics/%E5%98%8E%E5%AD%90-1599928738323.png)
可以看到, 它在提交之后立刻做了一个刷新, 我并没有抓到想要的包, 当然,如果有不信邪的小伙伴可以自己试一下,
其实只要你手速够快, 完全可以抓住那个包的(手动滑稽)
那这里就很大可能性的说明这个提交信息的函数也包含有`submit` 的字样, 我们再来看一下它的资源
![](https://gitee.com/Connor_Zhang/Blog/raw/master/Pics/%E5%98%8E%E5%AD%90-1599928109081.png)
发现这里有一些js文件, 我们可以逐步的去每个js文件里面搜索一下看有没有 `submit` 相关的字样
![](https://gitee.com/Connor_Zhang/Blog/raw/master/Pics/%E5%98%8E%E5%AD%90-1599928320579.png)
功夫不负有心人, 在 `jqnew2.js?v=1328` 这个文件中有135个包含有 `submit` 的地方
我们逐一的进行排除一下, 发现在第 3194 行 出现了一个 function, 名为 `submit` 还带了一个参数 `a`
可以推测大概率是这里, 先在函数内部任意一个位置打上断点. 然后再随便填写一份问卷进行提交
![](https://gitee.com/Connor_Zhang/Blog/raw/master/Pics/%E5%98%8E%E5%AD%90-1599929594137.png)
我们可以看到, 在我们打断点的地方, 浏览器停了下来, 说明提交就是通过这里来的, 我们再仔细的看一下这个
函数, 发现最后有一行这样的内容:
```javascript
d.send("submitdata=" + l)
```
说明这里是最终发送数据的地方, 我们在这里打上断点, 再次进行调试
![](https://gitee.com/Connor_Zhang/Blog/raw/master/Pics/%E5%98%8E%E5%AD%90-1599929875041.png)
截住后,我们通过控制台, 输入 `l` 来查看它发送的内容
```text
"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, 看一下具体的内容是什么吧
```text
"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$啊啊啊"
```
可以和我们的内容对比一下, 可以轻松的发现内容的格式就是
```text
单选题, 填空题 的格式是:
题号$所选内容
多选题的格式是:
题号$所选内容1,所选内容2...
多行的选择题(不知道怎么描述了,如下图)的格式是 :
题号$行号!选项,行号!选项...
```
![](https://gitee.com/Connor_Zhang/Blog/raw/master/Pics/%E5%98%8E%E5%AD%90-1599930286964.png)
好的, 现在我们已经掌握了钥匙的大概样子了, 但是我们貌似还不知道门在哪里, 我们需要继续来调试, 找到大门最终的位置
我们看到了 请求是由 `d` 这个对象发出的, 我们来打印一下 `d` 对象, 看看能不能找到想要的内容:
![](https://gitee.com/Connor_Zhang/Blog/raw/master/Pics/%E5%98%8E%E5%AD%90-1599930549543.png)
看了一下打印结果, 貌似没有我们想要的内容, 那没有办法, 只能去翻看源码了, 看一下在哪里设置了什么东西
![](https://gitee.com/Connor_Zhang/Blog/raw/master/Pics/%E5%98%8E%E5%AD%90-1599930757234.png)
通过这里我们发现了他在发送请求之前先设置了请求头, 我们全局搜索一下, 发现只有这一个地方设置了请求头,
记录下请求头的内容,以备不时之需
```python
headers = {"Content-Type": "application/x-www-form-urlencoded"}
```
再向上看, 发现有一句 这样的语句:
```javascript
d.open(v, x, !1)
```
我们打印一下 `v` 的内容, 返回了一个 `post` 这下好了, 知道去大门的方式了, 但是走那条路呢?
还有一个 `x` 对象, 我们也打印出来看一下.
打印之后, 就会发现, `x` 对象是一个 url, 我们在控制台打印一下就会得到这个东西:
```text
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 看一下究竟是什么内容:
```text
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, 有了 参数, 我们就可以开始动手写代码了:
```python
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(, randint(1, 9))),
11: ",".join()]),
12: ",".join()]),
13: randint(1, 2),
14: randint(1, 5),
15: ",".join()]),
16: ",".join()]),
17: ",".join()]),
18: ",".join()]),
19: randint(1, 3),
20: ",".join()]),
21: randint(1, 3),
22: ",".join()]),
23: "".join(sample(ascii_letters, randint(1, 26)))
}
return parse.quote("}".join())
@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)
jqnonce = re.findall(r'var jqnonce="(.*?)";', page)
rn = re.findall(r'var rndnum="(.*?)";', page)
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())
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()
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 ! 到这里就结束了,效率提高了, 速度变快了, 人也不虚了, 还等什么? 找他女朋友去, 让她叫我爸爸!!!!
哈哈哈哈 {:1_886:}{:1_886:}{:1_886:}
注 : 本文不针对任何人发出敌对信号, 所有言辞均为写作效果, 请勿当真, 如果感觉不适请联系我删除 本帖最后由 miss85246 于 2020-9-13 09:55 编辑
hill_king 发表于 2020-9-13 09:29
勾选一下F12的保留日志不就抓到包了
其实就算抓住了包, 不清楚参数的大概意思还是需要去里面解析的, 只不过能消耗更少一点的时间 (强行安慰自己) 现在又改了,增加了:
"jcn=%E7%8E%83%E8%8A%B9%E8%8A%B9&"
"jqpram=1QYJWJOA&"
"u_atype=2"
这种参数,LZ如果能解密出来。。求分享。 太牛了,好棒 牛逼,支持! 这是个真正的大佬 城里人就是会玩 谢谢分享 看完一脸蒙逼,大神就是牛比!1 我只想看女友 wushengli 发表于 2020-9-13 08:45
看的复杂,还是支持下!
还好了, 其实就是那么一个流程, 说复杂也没太复杂