今天分享一个爬虫js逆向案例-国家医保服务平台
需求
目标网站:fuwu.nhsa.gov.cn/nationalHal…
需求:医疗机构名称,医疗机构类型,医疗机构等级,详细地址(保存到excel表中)
请求头加密
找到数据位置
首先肯定是找到数据在哪里?
这个案例有点意思,就是一开始找不到数据,但是看这种表格数据格式,能猜到应该是Fetch/XHR文件中。
只有五个文件,看看这个英文,我猜应该是第五个
抓下来看看
import requests
url='https://fuwu.nhsa.gov.cn/ebus/fuwu/api/nthl/api/CommQuery/queryFixedHospital'
headers={
'Accept':'application/json',
'Accept-Encoding':'gzip, deflate, br, zstd',
'Accept-Language':'zh-CN,zh;q=0.9',
'Connection':'keep-alive',
'Content-Length':'573',
'Content-Type':'application/json',
'Cookie':'Hm_lvt_f7552e20a274f15673cde1deafaa1317=1737083983; yb_header_active=-1; amap_local=360100',
'Host':'fuwu.nhsa.gov.cn',
'Origin':'https://fuwu.nhsa.gov.cn',
'Referer':'https://fuwu.nhsa.gov.cn/nationalHallSt/',
'Sec-Fetch-Dest':'empty',
'Sec-Fetch-Mode':'cors',
'Sec-Fetch-Site':'same-origin',
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
'X-Tingyun':'c=B|4Nl_NnGbjwY;x=d649f8adb663442f',
'channel':'web',
'contentType':'application/x-www-form-urlencoded',
'sec-ch-ua':'"Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"',
'sec-ch-ua-mobile':'?0',
'sec-ch-ua-platform':'"Windows"',
'x-tif-nonce':'I8E51LWl',
'x-tif-paasid':'undefined',
'x-tif-signature':'317f633a61d466ef303678996a1cb9587a4e9b4197d76f9c4d65d7410a6ce432',
'x-tif-timestamp':'1737166229',}
res=requests.get(url,headers=headers)
print(res.text)
这段代码包含了所有的请求头,理论上是抓的到数据的,但是还是报错拿不到数据--请求头错误
这就是这个案例的第一个加密,加密的参数在请求头中
'x-tif-signature':'317f633a61d466ef303678996a1cb9587a4e9b4197d76f9c4d65d7410a6ce432',
应该是这个,因为就它长得像被加密过的。
解加密-请求头加密
搜索参数
点进去-发现两个地方是一样的函数,取一个,这下面headers好像就是请求头,将这个代码扣下来
开始调试
将函数名改一下,改成get_header,方便阅读,毕竟扣下来的代码也是我自己写的代码,还有一点就是,尽量不要传参数进这个函数,能删就删,能写死就写死。
function get_headers() {
var r = n("6c27").sha256
, s = Math.ceil((new Date).getTime() / 1e3)
, h = Object(i.a)()
, f = s + h + s;
return headers["x-tif-paasid"] = l.paasId,
headers["x-tif-signature"] = r(f),
headers["x-tif-timestamp"] = s,
headers["x-tif-nonce"] = h,
headers.Accept = "application/json",
headers.contentType = "application/x-www-form-urlencoded"}
运行,报错
点击跳转
是这个函数
n前面是赋值给了一个r变量,举个例子:假设一个函数demo() 将它赋值给rr=demo(),然后demo()=r()
看到原本的函数,是一个道理,r只用到了下面的r(f),它们两个跳转的函数是一样的,所以将上面的赋值给删了,也是一样的,就避免了找n函数,后面只需要解决r函数就行
好,下一个
跳转(节约篇幅,就不过多展示,直接看到跳转后的代码
扣下来,只用扣i函数,调用i函数,赋值给h,因为
h=Object(i.a)()就可以看作是一个函数调用,选中Object(i.a)跳转到的就是i函数,所以只需要将i调用赋值给h就行
下一个
header没有,这个简单,直接传一个空的进去,它每一个return都是给header赋值,所以可以这样,先赋值,再将headers return出去就行
下一个
这里l是一个对象,先赋值过来
下一个
就是上面遗留的那个问题
将function(n)扣出来,这里是一个构造sha256的方法,可以尝试用一个死方法代替,就是简单的传n进去,再解码就行。
function r(n) {
// return new Sha256(t,!0).update(n)[e]()
Sha256.update(n)
return Sha256.digest('hex')
}
然后,headers就出来了,每一次运行的都不一样
但是将请求头带上,还是得不到数据,因为载荷也进行了加密了。敬请期待下一集