☰
某市政府采购框架协议电子平台逆向-练习
2026/10/30 1:23:33 网站建设 项目流程

声明:仅供学习参考

  • 本次练习的网站为:武汉市政府采购框架协议电子平台
  • 网站网址为:https://wuhan.hbdzcg.com.cn/#/purchaseAnnouncement
  • 目标:采用逆向非自动化方式获取采购公告数据
  • 注意:不要干扰目标网站正常运行!!!此项目进作为数据采集练习,能够获取几页数据就行。
    网站首页图

1. 抓包分析

连续多次的去点击换页,会发现该网站有专门返回数据的接口,并且数据是以json的格式,
接口地址为:

https://wuhan.hbdzcg.com.cn/e-business/act/purchaseAnnouncement/listPage


携带的参数当中有明显的参数:page是代表页码的意思

随后利用爬虫工具复制curl(bach) 转requests请求

代码运行发现出现错误,虽然相应状态是200

该提示说的是时间戳无效,请求参数当中没有携带时间戳参数,但是请求头当中有,随后就发现请求头中不仅有时间戳timestamp,还有signature、nonceStr两个的值也在变化,如下图所示:

这里可以确认的是:Timestamp是一个时间戳。其他的两个猜测是加密得到,但是Noncestr看着像是随机数,不确定,等到下面查看js代码的时候再确定。

2. 逆向分析

分析目标:

  • nonceStr:是如何来的。
  • timestamp:时间戳参数是否参与了加密
  • signature:怎样加密的

首先最简单的就是直接搜索signature这个关键字,清空网络请求并重新请求该网站之后再点击翻页,然后搜索signature情况如下图所示:

很明显这里有赋值的操作,点击该js文件,然后到该赋值地方打上断点后,点击翻页查看:

方框框选的则是关键步骤,这里可以看到变量S是t()(g)处理后的函数返回的结果。同时我们也可以发现noncestr是对应的变量s的值,暂时先没看到变量s的出现,等一会查看该函数的看看是否有该变量

控制台中输出变量查看,从输出信息当中可以看到h这个变量就是请求参数,变量g一直在做的操作就是拼接,用python代码实现如下所示

"body="+json.dumps(datas,separators=(',',':'),ensure_ascii=False)+"&"+"timestamp="+c+"&nonceStr="+s+"&key="+d

这里的拼接还有变量s和d我们是不知道的,接下来看该函数的开始部分,如下所示:

这里有以下发现:

  • 变量s是一个随机数,是0-1之间的小数,然后乘以 1000000。
  • 变量d是固定的一个字符串
    随后我们可以在python代码当中模拟变量s的值:
s=str(1e6*random.random())

同时变量c也就是一个13位的时间戳

=str(int(round(datetime.now().timestamp()*1000,0)))

现在只剩下变量S也就是请求头当中的signature不知道他的加密逻辑。
随后鼠标放到**t()**上查看该函数所在的代码文件名称

点击该代码文件跳转到对应的函数上,这里看到有md5的字样,先怀疑下md5算法。


跳转过来以后发现真的是关于MD5算法的。为了保险,放掉所有断点后点击翻页,让断点进入到当前这个函数。

update是方法用来添加需要加密的内容,t代表的是调用**hex()**方法,获取MD5加密之后的16进制值。
!0不知道啥意思,最简单的方法就是使用该方法加密一下字符1,看看结果

从结果来看没有区别。

分析总结:

  • nonceStr 对应的是一个随机数,是0-1之间的小数,然后乘以 1000000
  • timestamp是13位的时间戳
  • signature是md5(“body=” + json.dumps(datas, separators=(‘,’, ‘:’),ensure_ascii=False) + “&” + “timestamp=” + c + “&nonceStr=” + s + “&key=” + d)之后得到的结果。
    解析返回的数据json串就不多介绍了。

3. 整合代码

整理之后的爬虫代码如下:

# 获取10页的数据,数据写入mysql数据库importrequestsimportjsonfromhashlibimportmd5importtracebackfromfake_useragentimportUserAgentfromurllibimportparseimporttimefromdatetimeimportdatetime,timedeltaimporturllib3importpymysqlimportrandom urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)db=pymysql.connect(host='127.0.0.1',port=3306,user='',password='',db='',charset='utf8')cursor=db.cursor()d='MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIQ3aWYA'# 固定proxy={'http':''}defget_md5(text):obj=md5()obj.update(text.encode('utf-8'))returnobj.hexdigest()defwriter_mysql(projectCode,announcementTitle,createdTime,bidTime):sql="insert into wuhan_hbdzcg(projectCode,announcementTitle,createdTime,bidTime) values(%s,%s,%s,%s )"values=(projectCode,announcementTitle,createdTime,bidTime)try:cursor.execute(sql,values)exceptpymysql.err.IntegrityErrorase:print(f"数据插入失败,错误信息:{e}")db.rollback()else:print(f"数据:{announcementTitle}插入成功!")db.commit()defget_page_home(page_url,headers,datas):datas=json.dumps(datas,separators=(',',':'),ensure_ascii=False)response=requests.post(page_url,headers=headers,data=datas,proxies=proxy,verify=False)ifresponse.status_code==200:print(f"相应数据:{response.json()}")# 解析数据json_data=response.json()['body']['data']['list']forone_datainjson_data:# 项目编号projectCode=one_data['projectCode']# 标题announcementTitle=one_data['announcementTitle']# 竞价时间createdTime=one_data['createdTime']# 竞价时间标准格式bidTime=one_data['bidTime']try:writer_mysql(projectCode,announcementTitle,createdTime,bidTime)exceptExceptionase:print(f"{announcementTitle}插入数据失败,错误信息:{e}")else:print(f"请求失败,响应码为:{response.status_code}")defmain():url="https://wuhan.hbdzcg.com.cn/e-business/act/purchaseAnnouncement/listPage"datas={"page":1,"pageSize":10,"unitId":1,"announcementTitle":"","announcementState":"","announcementType":"1"}forpagesinrange(1,11):datas['page']=pages# 处理请求参数s=str(1e6*random.random())c=str(int(round(datetime.now().timestamp()*1000,0)))# 13位时间戳signature_str="body="+json.dumps(datas,separators=(',',':'),ensure_ascii=False)+"&"+"timestamp="+c+"&nonceStr="+s+"&key="+d headers={"Accept":"application/json, text/plain, */*","Accept-Language":"zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6","Connection":"keep-alive","Content-Type":"application/json","Origin":"https://wuhan.hbdzcg.com.cn","Referer":"https://wuhan.hbdzcg.com.cn/","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin","User-Agent":UserAgent().random,"nonceStr":"","sec-ch-ua":"\"Not(A:Brand\";v=\"99\", \"Microsoft Edge\";v=\"133\", \"Chromium\";v=\"133\"","sec-ch-ua-mobile":"?0","sec-ch-ua-platform":"\"Windows\"","signature":"","timestamp":""}signature=get_md5(signature_str)headers['timestamp']=c headers['nonceStr']=s headers['signature']=signature headers['User-Agent']=UserAgent().randomprint(f"开始请求第{pages}页数据")try:get_page_home(url,headers,datas)exceptExceptionase:print(f"get_page_home 函数请求第{pages}页出现错误:{traceback.format_exc()}")print(f"{pages}页的数据请求完毕!\n")time.sleep(random.randint(10,15))cursor.close()db.close()if__name__=='__main__':main()

入库效果图:

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询