问题发现
前几天我一个做安全的哥们儿,做了个简单的数据展示平台,他让我做下反爬测试,我当即一堆操作就开始搞了,结果就遇到一个非常奇葩的问题。看截图:
这个是正常的请求:
这个是我用Python做的模拟请求:
结果就是提示签名错误,我对比了不下于几十遍,请求头只是顺序不太一致,其他没有任何区别,该有的都有,而且请求头里的那个sign参数也都带上了的
我又用抓包工具做数据重放编辑请求,该不行还是不行。
最后我用了以下来比对:
看出以上的区别了吗,我标记出来了的,如果我没什么经验的话,就把这个问题忽略了,不过我还是发现了不同,什么不同呢,请求参数里【,】和【:】左右不应该有空格
原因剖析
卧槽,脑子里突然惊叹了下,因为Python的pep8规范了,符号之间是必须要带上空格的,并且用过pycharm都知道,我们用快捷键格式化代码的时候,像 【=】 ,【==】,【,】,【!=】,【{}】等等的符号左右都会给出一些空格,因为这是Python界的默认规范,当然你也可以不遵守,只不过相信大部分pythoner都习惯这种代码风格
比如下面这个:
格式化代码后:
那么上面那个请求参数也就会按照这种格式来,其实对于大部分平台的话,有没有空格是不影响的,因为它后端是直接获取请求参数然后根据键获取值即可,获取到的数据符合规范即可。
而我哥们儿做的这个平台的话,我估计就是来这一手,等着我往下跳呢,他为了防止我,故意做了这方面的处理,你看他提示的,签名参数有误,其实我用的sign跟他正常请求是一致,反正故意误导你,让你的注意力集中在签名参数那里,然后一般人的话,看到请求参数是正常的,就会忽略这个问题,转而跑去攻克签名参数去了,结果肯定是不行的,因为一开始就走了一条错误的路。
上面说了出现空格的根本,那么,这种情况实际的原因是什么呢。我们知道,python模拟请求参数的话,就两种,一个字典形式,一个键值对形式:
- {'x':1,'y':2}
- x=1&y=2
字典形式的话,用requests写法就是:
import requests
url = ''
data = {'x':1,'y':23}
req = requests.get(url,json=data)
这种情况还有另外一种写法:
import requests
import json
url = ''
data = {'x':1,'y':23}
req = requests.get(url,data=json.dumps(data))
键值形式的话:
import requests
url = ''
data = {'x':1,'y':23}
req = requests.get(url,data=data)
键值形式就不多说了,因为我遇到的那个问题是用字典形式的。具体的原因就是requests库的源码里默认也不会给上空格的。源码具体位置我就不贴出来了,自己找吧。
解决
那么怎么解决呢:
json.dumps的时候,给个separators参数
import requests
import json
url = ''
data = {'x':1,'y':23}
req = requests.get(url,data=json.dumps(data,separators=(',',':'))
这样的话,就能正常获取数据了:
结语
整个过程从发现问题到解决问题,用了大概二三十分钟吧,我跟我哥们儿说,你这个确实挺奇葩的,也挺实用的,知道对方用的什么开发语言写爬虫程序,还能针对性的处理,挺不错的,我哥们儿投来失望的眼神,他说他还以为我要搞一天呢,正在窃喜呢,就被我搞定了。
最后我想说,其实这个请求方式用来反爬确实挺好的,针对一些没什么经验的爬虫工作者来说,还确实算是一个好招。