爬取某省公共资源交易中心

通过抓包数据可知

这个data是我们所需要的数据,但是已经通过加密隐藏起来了

分析

  1. 首先这是个json文件,我们可以用请求参数一个一个搜

    但是由于我们已经知道了这是个json

    所以我们可以直接偷个懒
  2. 直接搜索json.parse



然后还看见了state 刚好也是返回的值



3. 根据上述请求参数我们看见了ts是一个时间戳,

然后往周围找找



所以可以判断这是个AES加密

基本这个函数就是AES加密的,我们把代码抠出来就能直接运行了,但是抠出来之后发现

这就是个常规AES加密,所以我们直接通过python改写

Python代码

# -*- coding: utf-8 -*-
# @Time : 2022/7/13 16:39
# @Author : lzc
# @Email : hybpjx@163.com
# @Software: PyCharm
import base64
import datetime
import hashlib
import json
import time
import requests
from Cryptodome.Cipher import AES class PublicResourceCenter: item = {}
session = requests.session() list_url = '(为保证网站安全性)' detail_post_url = "(为保证网站安全性)" API = APIInvoke() secret_key = 'BE45D593014E4A4EB4449737660876CE'[0:32] # 密钥 iv = "A8909931867B0425"[0:16] # 初始向量 # 需要补位,str不是16的倍数那就补足为16的倍数
def add_to_16(self, value):
while len(value) % 16 != 0:
value += '\0'
return str.encode(value) # 解密方法
def aes_decrypt(self, key, t, iv):
aes = AES.new(self.add_to_16(key), AES.MODE_CBC, self.add_to_16(iv)) # 初始化加密器
base64_decrypted = base64.decodebytes(t.encode(encoding='utf-8')) # 优先逆向解密 base64 成 bytes
decrypted_text = str(aes.decrypt(base64_decrypted), encoding='utf-8').replace('\0', '') # 执行解密密并转码返回str
return decrypted_text def less_data(self, less_data):
now = datetime.datetime.now()
# 在获取超过当前时间30天的时间
delta = datetime.timedelta(days=less_data)
n_days = now - delta
return str(n_days).split(' ')[0] def get_sign_data(self, sign):
# md5 加密
portal_sign = hashlib.md5(sign.encode(encoding='utf-8')).hexdigest() return portal_sign def timestamp(self, shijian):
s_t = time.strptime(shijian, "%Y-%m-%d %H:%M:%S")
mkt = int(time.mktime(s_t))
return mkt def parse(self):
padding = lambda detail_decrypted_str: detail_decrypted_str[:detail_decrypted_str.rfind("}") + 1] for url in range(1, 6):
ts = int(time.time() * 1000)
# 封装请求体
js_data = {"pageNo": url, "pageSize": 20, "total": 5679, "AREACODE": "", "M_PROJECT_TYPE": "",
"KIND": "GCJS",
"GGTYPE": "1", "PROTYPE": "", "timeType": "6", "BeginTime": f"{self.less_data(180)} 00:00:00",
"EndTime": f"{self.less_data(0)} 23:59:59", "createTime": [], "ts": ts}
# 伪装sign
sign = f'3637CB36B2E54A72A7002978D0506CDFBeginTime{js_data["BeginTime"]}createTime[]EndTime{js_data["EndTime"]}GGTYPE{js_data["GGTYPE"]}KIND{js_data["KIND"]}pageNo{js_data["pageNo"]}pageSize{js_data["pageSize"]}timeType{js_data["timeType"]}total{js_data["total"]}ts{js_data["ts"]}'
# 执行公用的方法 返回值是未经过加密的 数据
encrypted_str = self.encrypted_str_get(self.list_url, js_data, sign)
# 执行AES解密的方法 把 key 和IV 传入
decrypted_str = self.aes_decrypt(self.secret_key, encrypted_str, self.iv)
js_text = json.loads(padding(decrypted_str))
for data in js_text['Table']:
self.item['title_name'] = data['NAME'].replace("<br>", "")
self.item['title_date'] = data.get('TM')
self.item[
'title_url'] = f"https://ggzyfw.fujian.gov.cn/web/index.html#/business/detail?cid={data['M_ID']}&type={data['KIND']}"
if self.item['title_date'] is None:
self.item['title_date'] = time.strftime('%Y-%m-%d %H:%M:%S')
# 封装请求体
# 1657709230
# 执行js代码
payload = {"m_id": data['M_ID'], "type": data['GGTYPE'], "ts": int(time.time() * 1000)}
# 伪装详情页的sign sign = "3637CB36B2E54A72A7002978D0506CDFm_id216262ts1657708358505type1"
detail_sign = f"3637CB36B2E54A72A7002978D0506CDFm_id{payload['m_id']}ts{payload['ts']}type{payload['type']}"
# 执行公用的方法 返回值是未经过加密的 数据
encrypted_str = self.encrypted_str_get(self.detail_post_url, payload, detail_sign)
# 执行AES解密的方法 把 key 和IV 传入
detail_decrypted_str = self.aes_decrypt(self.secret_key, encrypted_str, self.iv)
content_html = json.loads(padding(detail_decrypted_str))
self.item['content_html'] = content_html.get("Contents", "")
self.API.data_update(self.item)
self.close() def encrypted_str_get(self, url, js_data, sign):
portal_sign = self.get_sign_data(sign)
headers = {
'portal-sign': portal_sign,
'Content-Type': 'application/json;charset=UTF-8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/103.0.0.0 Safari/537.36',
} response = self.session.post(url, headers=headers, json=js_data) encrypted_str = response.json() return encrypted_str['Data'] def close(self):
self.session.close() if __name__ == '__main__':
pr = PublicResourceCenter()
pr.parse()

最新文章

  1. 利用Python进行数据分析(6) NumPy基础: 矢量计算
  2. Typescript基础类型
  3. 搭建IONIC开发环境
  4. SQL Server安全(9/11):透明数据加密(Transparent Data Encryption)
  5. 在centos6.5中安装scp和lrzsz
  6. TextView与Html相结合的具体方法?
  7. 设置360调用样式 IE调用样式
  8. 关于手机微网站ICP备案
  9. golang的helloworld
  10. Java之SPI机制
  11. weka对数据进行预测
  12. SpringData系列二 Repository接口
  13. 基于查表的整数霍夫变换方法实现(matlab)
  14. centos7 nginx安装/启动/进程状态/杀掉进程
  15. HDU 3567 Eight II(八数码 II)
  16. 修改maven的源地址为阿里源
  17. miui获取完整root
  18. ldap集成zabbix
  19. 【转】C# string数组转int数组
  20. mezzanine的page表

热门文章

  1. 使 Word 段落第一行空出两个字符的位置(段落首行缩进)
  2. R型医用变压器为什么越来越受大众喜爱?
  3. 蕞短鹭(artskjid) (⭐通信题/模拟⭐)
  4. CVE-2021-3156 sudo提权复现
  5. 【JDBC】学习路径2-编写第一个JDBC程序
  6. mysql_阻塞和死锁
  7. ACL和NAT
  8. Stream流式计算
  9. ProxySQL Disk库和Stats库
  10. Centos7主机安装Cockpit管理其他主机