CloudApiRequest 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cloud/CloudAPIRequest.py +514 -0
- cloud/CloudApiConfig.py +437 -0
- cloud/CloudLogUtil.py +36 -0
- cloud/CloudRequestUtil.py +107 -0
- cloud/CloudSignUtil.py +152 -0
- cloud/CloudYamlUtil.py +224 -0
- cloud/__init__.py +9 -0
- cloud/cli.py +62 -0
- cloudapirequest-1.2.0.dist-info/LICENSE +21 -0
- cloudapirequest-1.2.0.dist-info/METADATA +21 -0
- cloudapirequest-1.2.0.dist-info/RECORD +13 -0
- cloudapirequest-1.2.0.dist-info/WHEEL +5 -0
- cloudapirequest-1.2.0.dist-info/top_level.txt +1 -0
cloud/CloudApiConfig.py
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
from faker import Faker
|
|
2
|
+
import string
|
|
3
|
+
import time
|
|
4
|
+
import random
|
|
5
|
+
import datetime
|
|
6
|
+
import pytz
|
|
7
|
+
import hashlib
|
|
8
|
+
import base64
|
|
9
|
+
import hmac
|
|
10
|
+
import json
|
|
11
|
+
from urllib.parse import urlencode, urlparse
|
|
12
|
+
from Crypto.Cipher import AES
|
|
13
|
+
from Crypto.Util.Padding import pad, unpad
|
|
14
|
+
|
|
15
|
+
from cloud.CloudRequestUtil import CloudHttpClient
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CloudTimes:
|
|
19
|
+
def __init__(self, dt=None, tz=pytz.timezone('Asia/Shanghai')):
|
|
20
|
+
"""
|
|
21
|
+
初始化时间工具类
|
|
22
|
+
|
|
23
|
+
:param dt: datetime对象,默认使用当前时间
|
|
24
|
+
:param tz: 时区,默认使用本地时区
|
|
25
|
+
"""
|
|
26
|
+
self.tz = tz
|
|
27
|
+
self.dt = dt or datetime.datetime.now(self.tz)
|
|
28
|
+
|
|
29
|
+
def to_datetime(self):
|
|
30
|
+
"""
|
|
31
|
+
返回datetime对象
|
|
32
|
+
|
|
33
|
+
:return: datetime对象
|
|
34
|
+
"""
|
|
35
|
+
return self.dt
|
|
36
|
+
|
|
37
|
+
def to_str(self, fmt='%Y-%m-%dT%H:%M:%SZ'):
|
|
38
|
+
"""
|
|
39
|
+
将datetime对象转换为指定格式的字符串
|
|
40
|
+
|
|
41
|
+
:param fmt: 时间格式,默认为'%Y-%m-%d %H:%M:%S'
|
|
42
|
+
:return: 格式化后的时间字符串
|
|
43
|
+
"""
|
|
44
|
+
return self.dt.strftime(fmt)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class CloudDataGenerator:
|
|
48
|
+
"""
|
|
49
|
+
生成中文数据的工具类
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
# 类级别的计数器,确保cno绝对唯一
|
|
53
|
+
_cno_counter = 0
|
|
54
|
+
|
|
55
|
+
def __init__(self):
|
|
56
|
+
self.fake = Faker(locale='zh_CN')
|
|
57
|
+
|
|
58
|
+
def generate_name(self):
|
|
59
|
+
"""
|
|
60
|
+
生成中文姓名,返回字符串。
|
|
61
|
+
"""
|
|
62
|
+
return self.fake.name()
|
|
63
|
+
|
|
64
|
+
def generate_address(self):
|
|
65
|
+
"""
|
|
66
|
+
生成中文地址,返回字符串。
|
|
67
|
+
"""
|
|
68
|
+
return self.fake.address()
|
|
69
|
+
|
|
70
|
+
def generate_phone_number(self):
|
|
71
|
+
"""
|
|
72
|
+
生成中文手机号,返回字符串。
|
|
73
|
+
"""
|
|
74
|
+
return self.fake.phone_number()
|
|
75
|
+
|
|
76
|
+
def generate_id_number(self):
|
|
77
|
+
"""
|
|
78
|
+
生成中文身份证号码,返回字符串。
|
|
79
|
+
"""
|
|
80
|
+
return self.fake.ssn()
|
|
81
|
+
|
|
82
|
+
def random_number(self, digits=4):
|
|
83
|
+
"""
|
|
84
|
+
生成一个指定位数的随机整数并转换为字符串类型
|
|
85
|
+
如果生成的整数不足指定位数,则在左侧用0进行填充
|
|
86
|
+
"""
|
|
87
|
+
digits = int(digits)
|
|
88
|
+
return f"{{:0{digits}d}}".format(self.fake.random_number(digits=digits))
|
|
89
|
+
|
|
90
|
+
def generate_cno(self, min_digits=3, max_digits=10):
|
|
91
|
+
"""
|
|
92
|
+
生成3-10位纯数字的cno,确保一次运行中不重复
|
|
93
|
+
使用UUID+时间戳+计数器确保绝对唯一性,避免以0开头
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
min_digits (int): 最小位数,默认3
|
|
97
|
+
max_digits (int): 最大位数,默认10
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
str: 生成的cno字符串
|
|
101
|
+
"""
|
|
102
|
+
import uuid
|
|
103
|
+
import time
|
|
104
|
+
|
|
105
|
+
# 增加计数器确保绝对唯一性
|
|
106
|
+
CloudDataGenerator._cno_counter += 1
|
|
107
|
+
|
|
108
|
+
# 生成随机位数(3-10位)
|
|
109
|
+
digits = random.randint(min_digits, max_digits)
|
|
110
|
+
|
|
111
|
+
# 生成UUID并转换为数字
|
|
112
|
+
uuid_str = uuid.uuid4().hex
|
|
113
|
+
# 取UUID的前12位转换为数字
|
|
114
|
+
uuid_num = int(uuid_str[:12], 16)
|
|
115
|
+
|
|
116
|
+
# 添加时间戳确保唯一性(纳秒级精度)
|
|
117
|
+
timestamp = int(time.time() * 1000000000) # 纳秒级时间戳
|
|
118
|
+
|
|
119
|
+
# 添加计数器确保绝对唯一性
|
|
120
|
+
counter = CloudDataGenerator._cno_counter
|
|
121
|
+
|
|
122
|
+
# 组合生成唯一数字
|
|
123
|
+
unique_num = (uuid_num + timestamp + counter) % (10 ** 15) # 限制在15位以内
|
|
124
|
+
|
|
125
|
+
# 确保数字在指定位数范围内且不以0开头
|
|
126
|
+
min_value = 10 ** (digits - 1) # 最小n位数(不以0开头)
|
|
127
|
+
max_value = 10 ** digits - 1 # 最大n位数
|
|
128
|
+
|
|
129
|
+
# 如果超出范围则取模
|
|
130
|
+
if unique_num > max_value:
|
|
131
|
+
unique_num = min_value + (unique_num % (max_value - min_value + 1))
|
|
132
|
+
elif unique_num < min_value:
|
|
133
|
+
unique_num = min_value + (unique_num % (max_value - min_value + 1))
|
|
134
|
+
|
|
135
|
+
return str(unique_num)
|
|
136
|
+
|
|
137
|
+
def generate_cno_range(self, start_digits=3, end_digits=10, count=1):
|
|
138
|
+
"""
|
|
139
|
+
生成cno范围,用于批量操作
|
|
140
|
+
确保endCno > cno且位数一致
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
start_digits (int): 起始位数,默认3
|
|
144
|
+
end_digits (int): 结束位数,默认10
|
|
145
|
+
count (int): 生成数量,默认1
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
tuple: (start_cno, end_cno) 起始和结束cno
|
|
149
|
+
"""
|
|
150
|
+
# 生成随机位数
|
|
151
|
+
digits = random.randint(start_digits, end_digits)
|
|
152
|
+
|
|
153
|
+
# 生成起始cno
|
|
154
|
+
start_cno = self.generate_cno(digits, digits)
|
|
155
|
+
|
|
156
|
+
# 计算结束cno
|
|
157
|
+
start_value = int(start_cno)
|
|
158
|
+
end_value = start_value + count - 1
|
|
159
|
+
|
|
160
|
+
# 确保结束值不超过指定位数的最大值
|
|
161
|
+
max_value = 10 ** digits - 1
|
|
162
|
+
if end_value > max_value:
|
|
163
|
+
# 如果超出范围,重新生成起始值
|
|
164
|
+
start_value = max_value - count + 1
|
|
165
|
+
start_cno = str(start_value)
|
|
166
|
+
end_value = max_value
|
|
167
|
+
|
|
168
|
+
end_cno = str(end_value)
|
|
169
|
+
|
|
170
|
+
return start_cno, end_cno
|
|
171
|
+
|
|
172
|
+
def generate_cno_fixed_digits(self, digits):
|
|
173
|
+
"""
|
|
174
|
+
生成指定位数的cno,保持向后兼容性
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
digits (int): 指定位数
|
|
178
|
+
|
|
179
|
+
Returns:
|
|
180
|
+
str: 生成的cno字符串
|
|
181
|
+
"""
|
|
182
|
+
return self.generate_cno(digits, digits)
|
|
183
|
+
|
|
184
|
+
def get_cloud_password(self):
|
|
185
|
+
"""
|
|
186
|
+
获取初始化的SK 加密后的密码
|
|
187
|
+
:return:
|
|
188
|
+
"""
|
|
189
|
+
# 这里不能直接引用config,因为config类还没有定义
|
|
190
|
+
# 在实际使用时,会通过实例方法调用
|
|
191
|
+
return "default_cloud_password"
|
|
192
|
+
|
|
193
|
+
@staticmethod
|
|
194
|
+
def start_of_day():
|
|
195
|
+
"""
|
|
196
|
+
获取当前时间开始时间戳:eg:2023-06-01 00:00:00
|
|
197
|
+
"""
|
|
198
|
+
now = datetime.datetime.now()
|
|
199
|
+
return datetime.datetime(now.year, now.month, now.day)
|
|
200
|
+
|
|
201
|
+
@staticmethod
|
|
202
|
+
def end_of_day():
|
|
203
|
+
"""
|
|
204
|
+
获取当前时间开始时间戳:eg:2023-06-01 23:59:59
|
|
205
|
+
"""
|
|
206
|
+
return CloudDataGenerator.start_of_day() + datetime.timedelta(days=1) - datetime.timedelta(seconds=1)
|
|
207
|
+
|
|
208
|
+
def start_of_day_s(self):
|
|
209
|
+
"""
|
|
210
|
+
获取当前时间开始时间戳:eg:1685548800 秒级
|
|
211
|
+
"""
|
|
212
|
+
return int(time.mktime(CloudDataGenerator.start_of_day().timetuple()))
|
|
213
|
+
|
|
214
|
+
def end_of_day_s(self):
|
|
215
|
+
"""
|
|
216
|
+
获取当前时间结束时间戳:eg:1685635199 秒级
|
|
217
|
+
"""
|
|
218
|
+
return int(time.mktime(CloudDataGenerator.end_of_day().timetuple()))
|
|
219
|
+
|
|
220
|
+
def random_externalId(self):
|
|
221
|
+
"""
|
|
222
|
+
生成唯一性数据,crm用于 外部企业客户id
|
|
223
|
+
"""
|
|
224
|
+
num = str(random.randint(1000, 9999))
|
|
225
|
+
src_uppercase = string.ascii_uppercase # string_大写字母
|
|
226
|
+
src_lowercase = string.ascii_lowercase # string_小写字母
|
|
227
|
+
chrs = random.sample(src_lowercase + src_uppercase, 3)
|
|
228
|
+
for i in chrs:
|
|
229
|
+
num += i
|
|
230
|
+
return num
|
|
231
|
+
|
|
232
|
+
def encryptPassword(self, plain_text='Aa112233'):
|
|
233
|
+
"""
|
|
234
|
+
加密 - 使用默认密钥
|
|
235
|
+
"""
|
|
236
|
+
# 使用默认密钥进行加密
|
|
237
|
+
password = "default_encryption_key"
|
|
238
|
+
# 设置随机数生成器的种子
|
|
239
|
+
secure_random = hashlib.sha1(password.encode()).digest()
|
|
240
|
+
# 创建对称加密密钥生成器
|
|
241
|
+
kgen = hashlib.sha1(secure_random).digest()[:16]
|
|
242
|
+
# 创建密码器并初始化
|
|
243
|
+
cipher = AES.new(kgen, AES.MODE_ECB)
|
|
244
|
+
# 加密明文(使用PKCS7填充)
|
|
245
|
+
padded_plain_text = pad(plain_text.encode(), AES.block_size)
|
|
246
|
+
encrypted_bytes = cipher.encrypt(padded_plain_text)
|
|
247
|
+
# 将加密结果转换为16进制字符串
|
|
248
|
+
encrypted_text = base64.b16encode(encrypted_bytes).decode().lower()
|
|
249
|
+
return encrypted_text
|
|
250
|
+
|
|
251
|
+
def decrypt(self, encrypted_text, password):
|
|
252
|
+
"""
|
|
253
|
+
# 解密
|
|
254
|
+
"""
|
|
255
|
+
# 设置随机数生成器的种子
|
|
256
|
+
secure_random = hashlib.sha1(password.encode()).digest()
|
|
257
|
+
# 创建对称加密密钥生成器
|
|
258
|
+
kgen = hashlib.sha1(secure_random).digest()[:16]
|
|
259
|
+
# 创建密码器并初始化
|
|
260
|
+
cipher = AES.new(kgen, AES.MODE_ECB)
|
|
261
|
+
# 解密密文(parseHexStr2Byte方法为将16进制字符串转为二进制字节数组)
|
|
262
|
+
encrypted_bytes = base64.b16decode(encrypted_text)
|
|
263
|
+
decrypted_bytes = cipher.decrypt(encrypted_bytes)
|
|
264
|
+
decrypted_text = unpad(decrypted_bytes, AES.block_size).decode()
|
|
265
|
+
return decrypted_text
|
|
266
|
+
|
|
267
|
+
def generate_user_data(self):
|
|
268
|
+
"""
|
|
269
|
+
生成随路数据JSON字符串
|
|
270
|
+
格式:{"key":"value"},不支持数组和嵌套
|
|
271
|
+
"""
|
|
272
|
+
data = {
|
|
273
|
+
"testKey1": f"testValue{self.fake.random_number(digits=3)}",
|
|
274
|
+
"testKey2": f"testValue{self.fake.random_number(digits=3)}",
|
|
275
|
+
"testKey3": f"testValue{self.fake.random_number(digits=3)}"
|
|
276
|
+
}
|
|
277
|
+
return json.dumps(data, ensure_ascii=False)
|
|
278
|
+
|
|
279
|
+
def generate_user_data_keys(self):
|
|
280
|
+
"""
|
|
281
|
+
生成随路数据键值字符串
|
|
282
|
+
格式:key1,key2,key3
|
|
283
|
+
"""
|
|
284
|
+
return "testKey1,testKey2,testKey3"
|
|
285
|
+
|
|
286
|
+
def generate_cloud_signature(self, method, url, params, access_key_id, access_key_secret):
|
|
287
|
+
"""
|
|
288
|
+
生成云服务签名
|
|
289
|
+
"""
|
|
290
|
+
# 获取当前时间戳
|
|
291
|
+
timestamp = int(time.time())
|
|
292
|
+
|
|
293
|
+
# 构建签名字符串
|
|
294
|
+
# 1. 请求方法
|
|
295
|
+
string_to_sign = method.upper() + "\n"
|
|
296
|
+
|
|
297
|
+
# 2. 请求路径
|
|
298
|
+
parsed_url = urlparse(url)
|
|
299
|
+
string_to_sign += parsed_url.path + "\n"
|
|
300
|
+
|
|
301
|
+
# 3. 查询参数(按字典序排序)
|
|
302
|
+
if params:
|
|
303
|
+
sorted_params = sorted(params.items())
|
|
304
|
+
query_string = "&".join([f"{k}={v}" for k, v in sorted_params])
|
|
305
|
+
string_to_sign += query_string + "\n"
|
|
306
|
+
else:
|
|
307
|
+
string_to_sign += "\n"
|
|
308
|
+
|
|
309
|
+
# 4. 时间戳
|
|
310
|
+
string_to_sign += str(timestamp)
|
|
311
|
+
|
|
312
|
+
# 使用HMAC-SHA256进行签名
|
|
313
|
+
signature = hmac.new(
|
|
314
|
+
access_key_secret.encode('utf-8'),
|
|
315
|
+
string_to_sign.encode('utf-8'),
|
|
316
|
+
hashlib.sha256
|
|
317
|
+
).hexdigest()
|
|
318
|
+
|
|
319
|
+
# 构建Authorization头
|
|
320
|
+
auth_header = f"Cloud {access_key_id}:{signature}"
|
|
321
|
+
|
|
322
|
+
return auth_header, timestamp
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class config:
|
|
326
|
+
"""
|
|
327
|
+
配置文件
|
|
328
|
+
"""
|
|
329
|
+
|
|
330
|
+
def __init__(self, baseUrl=None, token=None, CloudPassword=None,
|
|
331
|
+
commonTestCasePath=None, methObj=None, Session: CloudHttpClient = CloudHttpClient(),
|
|
332
|
+
assertFail='stop', tEnv='base', enterpriseId=None, validateType='2', obClids=None):
|
|
333
|
+
"""
|
|
334
|
+
初始化配置文件
|
|
335
|
+
"""
|
|
336
|
+
self._baseUrl = baseUrl
|
|
337
|
+
self._token = token
|
|
338
|
+
self._enterpriseId = enterpriseId
|
|
339
|
+
self._validateType = validateType
|
|
340
|
+
# 加密后的密码
|
|
341
|
+
self._CloudPassword = CloudPassword
|
|
342
|
+
self._commonTestCasePath = commonTestCasePath
|
|
343
|
+
self._methObj = methObj
|
|
344
|
+
self._assertFail = assertFail
|
|
345
|
+
self._tEnv = tEnv
|
|
346
|
+
# 构建全局session
|
|
347
|
+
self._Session = Session
|
|
348
|
+
# 外呼号码配置
|
|
349
|
+
self._obClids = obClids
|
|
350
|
+
|
|
351
|
+
@property
|
|
352
|
+
def Session(self):
|
|
353
|
+
return self._Session
|
|
354
|
+
|
|
355
|
+
@Session.setter
|
|
356
|
+
def Session(self, value):
|
|
357
|
+
self._Session = value
|
|
358
|
+
|
|
359
|
+
@property
|
|
360
|
+
def methObj(self):
|
|
361
|
+
return self._methObj
|
|
362
|
+
|
|
363
|
+
@methObj.setter
|
|
364
|
+
def methObj(self, value):
|
|
365
|
+
self._methObj = value
|
|
366
|
+
|
|
367
|
+
@property
|
|
368
|
+
def CloudPassword(self):
|
|
369
|
+
return self._CloudPassword
|
|
370
|
+
|
|
371
|
+
@CloudPassword.setter
|
|
372
|
+
def CloudPassword(self, value):
|
|
373
|
+
self._CloudPassword = value
|
|
374
|
+
|
|
375
|
+
@property
|
|
376
|
+
def commonTestCasePath(self):
|
|
377
|
+
return self._commonTestCasePath
|
|
378
|
+
|
|
379
|
+
@commonTestCasePath.setter
|
|
380
|
+
def commonTestCasePath(self, value):
|
|
381
|
+
self._commonTestCasePath = value
|
|
382
|
+
|
|
383
|
+
@property
|
|
384
|
+
def baseUrl(self):
|
|
385
|
+
return self._baseUrl
|
|
386
|
+
|
|
387
|
+
@baseUrl.setter
|
|
388
|
+
def baseUrl(self, value):
|
|
389
|
+
self._baseUrl = value
|
|
390
|
+
|
|
391
|
+
@property
|
|
392
|
+
def assertFail(self):
|
|
393
|
+
return self._assertFail
|
|
394
|
+
|
|
395
|
+
@assertFail.setter
|
|
396
|
+
def assertFail(self, value):
|
|
397
|
+
self._assertFail = value
|
|
398
|
+
|
|
399
|
+
@property
|
|
400
|
+
def enterpriseId(self):
|
|
401
|
+
return self._enterpriseId
|
|
402
|
+
|
|
403
|
+
@enterpriseId.setter
|
|
404
|
+
def enterpriseId(self, value):
|
|
405
|
+
self._enterpriseId = value
|
|
406
|
+
|
|
407
|
+
@property
|
|
408
|
+
def tEnv(self):
|
|
409
|
+
return self._tEnv
|
|
410
|
+
|
|
411
|
+
@tEnv.setter
|
|
412
|
+
def tEnv(self, value):
|
|
413
|
+
self._tEnv = value
|
|
414
|
+
|
|
415
|
+
@property
|
|
416
|
+
def validateType(self):
|
|
417
|
+
return self._validateType
|
|
418
|
+
|
|
419
|
+
@validateType.setter
|
|
420
|
+
def validateType(self, value):
|
|
421
|
+
self._validateType = value
|
|
422
|
+
|
|
423
|
+
@property
|
|
424
|
+
def token(self):
|
|
425
|
+
return self._token
|
|
426
|
+
|
|
427
|
+
@token.setter
|
|
428
|
+
def token(self, value):
|
|
429
|
+
self._token = value
|
|
430
|
+
|
|
431
|
+
@property
|
|
432
|
+
def obClids(self):
|
|
433
|
+
return self._obClids
|
|
434
|
+
|
|
435
|
+
@obClids.setter
|
|
436
|
+
def obClids(self, value):
|
|
437
|
+
self._obClids = value
|
cloud/CloudLogUtil.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
cloud日志工具类:
|
|
6
|
+
定义日志输出
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class CloudLogConfig:
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def logger_set():
|
|
14
|
+
# 第一步:创建一个日志收集器
|
|
15
|
+
log = logging.getLogger()
|
|
16
|
+
|
|
17
|
+
# 第二步:设置收集器收集的等级
|
|
18
|
+
log.setLevel(logging.INFO)
|
|
19
|
+
|
|
20
|
+
# 第三步:设置输出渠道以及输出渠道的等级
|
|
21
|
+
curTime = time.strftime("%Y-%m-%d %H-%M-%S", time.localtime())
|
|
22
|
+
|
|
23
|
+
sh = logging.StreamHandler()
|
|
24
|
+
sh.setLevel(logging.INFO)
|
|
25
|
+
log.addHandler(sh)
|
|
26
|
+
|
|
27
|
+
# 创建一个输出格式对象
|
|
28
|
+
formats = '%(thread)d: %(asctime)s -- [%(filename)s-->line:%(lineno)d] - %(levelname)s: %(message)s'
|
|
29
|
+
form = logging.Formatter(formats)
|
|
30
|
+
# 将输出格式添加到输出渠道
|
|
31
|
+
sh.setFormatter(form)
|
|
32
|
+
|
|
33
|
+
return log
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
log = CloudLogConfig.logger_set()
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import jsonpath
|
|
2
|
+
import requests
|
|
3
|
+
from urllib.parse import urlparse
|
|
4
|
+
from requests import Session
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CloudHttpClient:
|
|
8
|
+
"""
|
|
9
|
+
对 requests 库进行简单封装的类,可以方便地进行 HTTP 请求和处理响应。
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, base_url=None):
|
|
13
|
+
"""
|
|
14
|
+
初始化方法,接受一个基础URL参数,并创建一个Session对象
|
|
15
|
+
:param base_url: str 基础URL,例如 https://api.cloud.com
|
|
16
|
+
"""
|
|
17
|
+
if base_url is not None:
|
|
18
|
+
self.base_url = base_url
|
|
19
|
+
|
|
20
|
+
self.session: Session = requests.Session()
|
|
21
|
+
|
|
22
|
+
def request(self, method, url, **kwargs):
|
|
23
|
+
"""
|
|
24
|
+
发送HTTP请求,并返回响应对象
|
|
25
|
+
:param method: str 请求方法,例如 GET、POST、PUT等
|
|
26
|
+
:param url: str 请求URL,会和base_url拼接成完整的URL
|
|
27
|
+
:param kwargs: dict 其他requests.request方法支持的参数
|
|
28
|
+
:return: requests.Response 响应对象
|
|
29
|
+
"""
|
|
30
|
+
response = self.session.request(method, url, **kwargs)
|
|
31
|
+
# 判断请求url 是否包含 openapi_login 用于处理 单点登录到系统后进行系统的接口请求鉴权处理
|
|
32
|
+
# if 'openapi_login' in url:
|
|
33
|
+
# # 需要请求接口 获取 Tsessionid
|
|
34
|
+
# # 先从url 中解析出请求域名
|
|
35
|
+
# parsed_url = urlparse(url)
|
|
36
|
+
# domain = parsed_url.scheme + '://' + parsed_url.netloc
|
|
37
|
+
# # 进行接口请求 拿到响应
|
|
38
|
+
# personalResponse = self.session.request(method='GET', url=domain + '/api/personal/info/get')
|
|
39
|
+
# # 拿响应的$.result.authToken
|
|
40
|
+
# authToken = jsonpath.jsonpath(personalResponse.json(), '$.result.authToken')[0]
|
|
41
|
+
# # 后续的请求头上都需要带上 Tsessionid
|
|
42
|
+
# self.session.headers.update({'Tsessionid': authToken})
|
|
43
|
+
|
|
44
|
+
# 处理HTTP错误
|
|
45
|
+
http_error_msg = None
|
|
46
|
+
if 400 <= response.status_code < 500:
|
|
47
|
+
http_error_msg = (
|
|
48
|
+
f"{response.status_code} 客户端错误 Error: {response.text} for url: {response.url}"
|
|
49
|
+
)
|
|
50
|
+
elif 500 <= response.status_code < 600:
|
|
51
|
+
http_error_msg = (
|
|
52
|
+
f"{response.status_code} 服务端错误 Error: {response.text} for url: {response.url}"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
return response
|
|
56
|
+
|
|
57
|
+
def get(self, url, params=None, **kwargs):
|
|
58
|
+
"""
|
|
59
|
+
发送GET请求,并返回响应对象
|
|
60
|
+
:param url: str 请求URL,会和base_url拼接成完整的URL
|
|
61
|
+
:param params: dict 查询参数,会被转换为?key=value&key=value的形式拼接到URL后面
|
|
62
|
+
:param kwargs: dict 其他requests.get方法支持的参数
|
|
63
|
+
:return: requests.Response 响应对象
|
|
64
|
+
"""
|
|
65
|
+
return self.request('GET', url, params=params, **kwargs)
|
|
66
|
+
|
|
67
|
+
def post(self, url, json=None, data=None, **kwargs):
|
|
68
|
+
"""
|
|
69
|
+
发送POST请求,并返回响应对象
|
|
70
|
+
:param url: str 请求URL,会和base_url拼接成完整的URL
|
|
71
|
+
:param data: dict 请求体参数,以表单形式提交
|
|
72
|
+
:param json: dict 请求体参数,以JSON格式提交
|
|
73
|
+
:param kwargs: dict 其他requests.post方法支持的参数
|
|
74
|
+
:return: requests.Response 响应对象
|
|
75
|
+
"""
|
|
76
|
+
return self.request('POST', url, data=data, json=json, **kwargs)
|
|
77
|
+
|
|
78
|
+
def put(self, url, json=None, data=None, **kwargs):
|
|
79
|
+
"""
|
|
80
|
+
发送PUT请求,并返回响应对象
|
|
81
|
+
:param url: str 请求URL,会和base_url拼接成完整的URL
|
|
82
|
+
:param data: dict 请求体参数,以表单形式提交
|
|
83
|
+
:param json: dict 请求体参数,以JSON格式提交
|
|
84
|
+
:param kwargs: dict 其他requests.put方法支持的参数
|
|
85
|
+
:return: requests.Response 响应对象
|
|
86
|
+
"""
|
|
87
|
+
return self.request('PUT', url, data=data, json=json, **kwargs)
|
|
88
|
+
|
|
89
|
+
def delete(self, url, **kwargs):
|
|
90
|
+
"""
|
|
91
|
+
发送DELETE请求,并返回响应对象
|
|
92
|
+
:param url: str 请求URL,会和base_url拼接成完整的URL
|
|
93
|
+
:param kwargs: dict 其他requests.delete方法支持的参数
|
|
94
|
+
:return: requests.Response 响应对象
|
|
95
|
+
"""
|
|
96
|
+
return self.request('DELETE', url, **kwargs)
|
|
97
|
+
|
|
98
|
+
def patch(self, url, json=None, data=None, **kwargs):
|
|
99
|
+
"""
|
|
100
|
+
发送PATCH请求,并返回响应对象
|
|
101
|
+
:param url: str 请求URL,会和base_url拼接成完整的URL
|
|
102
|
+
:param data: dict 请求体参数,以表单形式提交
|
|
103
|
+
:param json: dict 请求体参数,以JSON格式提交
|
|
104
|
+
:param kwargs: dict 其他requests.patch方法支持的参数
|
|
105
|
+
:return: requests.Response 响应对象
|
|
106
|
+
"""
|
|
107
|
+
return self.request('PATCH', url, data=data, json=json, **kwargs)
|