再进行数据爬取的过程中,有些时候浏览器访问服务端会带上一些加密的参数,爬虫模拟客户端操作,也需要携带加密参数才可以正常获取数据,那这时候就需要我们去观察浏览器是怎么对这个数据加密的,根据不同的加密方式去编写相关的代码。
浏览器获取加密参数基本都是执行了js代码,所以我们先需要分析加密的位置和加密的方式。
优志愿案例
post请求需要携带参数,并且不是携带表单数据,而是请求载荷,表单数据和请求载荷的区别在于请求的
-
表单数据:表单数据通常是通过HTML表单提交的用户输入数据。当用户在网页上填写表单并点击提交按钮时,浏览器会将表单数据封装为一个HTTP POST请求,并将数据作为请求体(Request Body)的一部分发送到服务器。表单数据通常使用键值对(Key-Value)的形式来表示,其中键表示表单字段的名称,值表示用户输入的内容。
1701353418236.png
2.请求载荷(Payload):请求载荷是指在HTTP请求中传递的任意数据。与表单数据不同,请求载荷可以是各种形式的数据,如JSON、XML、二进制数据等。
1701353429051.png
并且通过抓取数据包可以发现第一页和第二页的请求中,u-sign的值不一样,也就意味着,如果使用python代码模拟请求,就没有办法使用同一个u-sign值去请求到结果
url = 'https://uwf7de983aad7a717eb.youzy.cn/youzy.dms.basiclib.api.college.query'
headers = {
'U-Sign': '643ff9499febb3ee34c95ffe0bb29cb0',# 第一页的u-sign值
'Content-Type':'application/json'
}
res_data = '{"keyword":"","provinceNames":[],"natureTypes":[],"eduLevel":"","categories":[],"features":[],"pageIndex":1,"pageSize":20,"sort":11}'
# 第一页的请求参数
res = requests.post(url=url,data=res_data,headers=headers)
print(res.text) # 可以获取第一页的数据
但是如果将res_data换为第二页的请求参数
res_data = '{"keyword":"","provinceNames":[],"natureTypes":[],"eduLevel":"","categories":[],"features":[],"pageIndex":2,"pageSize":20,"sort":11}'
# 获取不到数据,因为u-sign发生了改变
找u-sign加密数据的赋值位置
此时都是匹配的位置,这么多我们可以通过给每个打断点的方式去判断这其中是否生效(断点的作用是在程序执行过程中暂停代码的执行,以便你可以检查程序的状态和调试代码。当程序执行到设置了断点的行时,调试器会中断程序的执行,并进入调试模式,此时你可以逐行执行、观察变量的值、检查程序的执行路径等)
其中发现第三个是会执行的
n函数就是加密函数
联系上下文,可以发现和百度百科中的js md5加密方式很相似,所以基本可以确定为md5加密
测试
与测试工具中的值是一致,所以确定这个u-sign的值就是通过md5加密出来的。通过以上分析,加密调用n函数,传入的是请求载荷中的字符串+&+9sasji5owng41irkisvtjhlxhmrysrp1固定的值 所以,可以使用python模拟过程
python代码实现
data = '{"keyword":"","provincenames":[],"naturetypes":[],"edulevel":"","categories":[],"features":[],"pageindex":1,"pagesize":20,"sort":11}'
def encryption(data):
o = data+"&9sasji5owng41irkisvtjhlxhmrysrp1"
sign = hashlib.md5(o.encode()).hexdigest() # 字符串--》md5--》调用python自带的hashlib.md5方法 传入字节数据 返回对象,用对象.hexdigest()获取最后的md5加密数据
return sign
sign = encryption(data)
完整代码
import hashlib
import requests
def encryption(data):
# 前端js在加密的过程中把所有的请求载荷数据都变为了小写再拼接固定的&9sasji5owng41irkisvtjhlxhmrysrp1
o = data.lower()+'&9sasji5owng41irkisvtjhlxhmrysrp1'
# md方法需要传入一个参数 看得懂的数据
# 获取md5加密的值
sign = hashlib.md5(o.encode()).hexdigest()
print(sign)
# 数据返回
return sign
# 字符串怎么编码?
res_data = '{"keyword":"","provinceNames":[],"natureTypes":[],"eduLevel":"","categories":[],"features":[],"pageIndex":3,"pageSize":20,"sort":11}'
u_sign = encryption(res_data) # 调用加密函数把res_data数据传过去 生成第三页的u-sign
url = 'https://uwf7de983aad7a717eb.youzy.cn/youzy.dms.basiclib.api.college.query'
headers = {
# 请求中携带md5加密值
'U-Sign': u_sign,
'Content-Type':'application/json'
}
# 发送post请求,传递参数
# 请求载荷:
# 表单数据:
res = requests.post(url=url,data=res_data,headers=headers)
data = res.json()
# print(data)
# 获取响应数据
for i in data['result']['items']:
print(i['cnName'],i['logoUrl'],i['provinceName'])
'''
通过断点发现u-sign代码生成位置
"u-sign": o(e.url, e.data)==>643ff9499febb3ee34c95ffe0bb29cb0,
o对应的是js中的一个函数 ,传入了两个参数,e.url="/youzy.dms.basiclib.api.college.query"
e.data = 请求载荷中的参数
o = "{"keyword":"","provincenames":[],"naturetypes":[],"edulevel":"","categories":[],"features":[],"pageindex":1,"pagesize":20,"sort":11}&9sasji5owng41irkisvtjhlxhmrysrp1"
n(o) 调用n函数传入o参数:"{"keyword":"","provincenames":[],"naturetypes":[],"edulevel":"","categories":[],"features":[],"pageindex":1,"pagesize":20,"sort":11}&9sasji5owng41irkisvtjhlxhmrysrp1"
n对应的是md5加密函数
如何在请求的时候带上变动的u-sign
在python中实现md5加密
'''