提交 c5fd71a4 authored 作者: ”name“'s avatar ”name“

first init

上级
# ĬϺԵļ
/shelf/
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
<serverData>
<paths name="root@119.3.226.174:22 password">
<serverdata>
<mappings>
<mapping local="$PROJECT_DIR$" web="/" />
</mappings>
</serverdata>
</paths>
</serverData>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
<file url="file://$PROJECT_DIR$/clx_products/huibiao_wisdom/configuration_data.yml" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/huibiao_wisdom_run.py" charset="UTF-8" />
<file url="PROJECT" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPep8Inspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="E501" />
</list>
</option>
</inspection_tool>
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredIdentifiers">
<list>
<option value="Tests.ui_automation.ui_actions" />
<option value="超差计算器.calculate_Qgrad.Qgrad" />
<option value="dispatch_center.task_chart.transport_flow" />
<option value="page.rewards_punishments_page.calculate_total_price.total_price" />
<option value="coal_blending_tool.tonnes" />
<option value="coal_blending_tool.*" />
<option value="random.random.*" />
</list>
</option>
</inspection_tool>
</profile>
</component>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.9 (trading_platform_test)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/trading_platform_test.iml" filepath="$PROJECT_DIR$/.idea/trading_platform_test.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.9" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
\ No newline at end of file
'''
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
'''
"""
分别封装requests、selenium、pymysql、redis
"""
\ No newline at end of file
'''
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
'''
import queue
import time
import redis
from config import *
from pymysql import *
# 装饰redis类的方法, 作用是返回redis连接对象
def redis_obj(func):
def func_in(*args, **kwargs):
args_copy = args # 将参数拷贝一份,原因:下面有删除操作,如果取数据报异常,重新从队列进行连接时,将参数复原
redis_nodes = REDIS_CON
redis_queue = queue.Queue() # 创建队列对象
for i in redis_nodes:
redis_queue.put(i) # 将redis连接集群添加到队列里
while redis_queue.empty() is not True: # 队列不为空,轮询
self = args[0] # 取出来,再放进去,为了不影响redis的连接对象r
r = args[1] # 解包 取出r,后面进行赋值使用, 类方法第一个参数为self,所以取的是索引1
args = list(args) # 转换为list,删除元素r,目的是后面将r进行单独传参,否则会报参数错误
args.pop(0)
args.pop(0) # 删除前两个元素
args = tuple(args)
redis_con = redis_queue.get() # 取出一个值进行连接
r = redis.Redis(host=redis_con.get('host'), password=redis_con.get('password'), port=redis_con.get('port'))
try:
return func(self, r, *args, **kwargs) # 调用被装饰的函数,
except Exception as f:
args = args_copy
return func_in
class ConnectRedis(object):
"""
创建redis连接对象,定义所有方法参数除了第一个self是默认的,还需传一个“r”,并且使用“redis_obj()”进行装饰
使用的时候,参数“r”随便传一个什么值都可以,在装饰器里面会处理成为redis连接对象返回
"""""
def __init__(self):
pass
@redis_obj
def write_hash_headers(self, r, role, mobile, data={}):
# 在redis中求存储各端请头, 时间为7天
r.hmset('test:headers:{}:{}'.format(role, mobile), data)
r.expire('test:headers:{}:{}'.format(role, mobile), REDIS_SAVE_TIME)
@redis_obj
def read_headers(self, r, role, mobile):
# 将读取出来的请求头(byte类型)转换成为字典
byte_dict = r.hgetall('test:headers:{}:{}'.format(role, mobile))
headers = {}
for i in byte_dict:
headers[i.decode()] = byte_dict[i].decode()
return headers
@redis_obj
def del_headers(self, r, role, mobile):
# 删除请求头
r.delete('test:headers:{}:{}'.format(role, mobile))
return
@redis_obj
def set_wallet(self, r, user_id, wallet):
# 将用户钱包账号写入redis
r.set('test:user_wallet:{}'.format(user_id), str(wallet), ex=REDIS_SAVE_TIME)
@redis_obj
def get_wallet(self, r, user_id):
# 取出钱包账号
return r.get('test:user_wallet:{}'.format(user_id))
@redis_obj
def get_test_mobile(self, r):
# 获取一个测试用的手机号,然后重新设置
mobile = r.get('test:mobile')
if not mobile:
r.set('test:mobile', 16100000100)
new_mobile = int(mobile) + 1
r.set('test:mobile', new_mobile)
return mobile.decode()
@redis_obj
def search_captcha(self, r, mobile):
# 查询图片验证码
# try:
name = 'login:owner:captcha:{}'.format(mobile)
captcha = r.get(name)
if captcha is None:
# name = 'login:{}:captcha:null'.format(role) # 特殊原因,验证码无法携带手机号
name = 'login:owner:captcha:null'
captcha = r.get(name)
return captcha.decode()
# except Exception as f:
# logger.info('查询验证码失败,手机号:{},返回1234'.format(mobile))
# # return 1234
@redis_obj
def verify_mobile(self, r, mobile):
# 查询短信验证码
name = 'verify:mobile:{}:1'.format(mobile)
mobile_code = r.get(name)
if mobile_code is not None:
return mobile_code.decode()
@redis_obj
def get_user_name(self, r):
# 用于用户注册,取出一个名字
return r.blpop('test:reg_name')[1].decode()
@redis_obj
def write_auto_test_child(self, r, child_no):
# 自动化测试跑的运单写入redis
r.lpush('test:auto_test:child_msg', child_no)
@redis_obj
def read_auto_test_child(self, r):
# 读取自动化测试跑的运单
child_list = r.lrange('test:auto_test:child_msg', 0, -1)
for i in range(len(child_list)):
child_list[i] = child_list[i].decode()
return child_list
@redis_obj
def del_auto_test_child(self, r):
# 删除自动化测试跑的运单
while r.llen('test:auto_test:child_msg') > 0:
r.lpop('test:auto_test:child_msg')
@redis_obj
def auto_test_child_time(self, r, type, time):
# 保存自动化测试运单执行的开始和结束时间,作为统计筛选的时间范围,type:start_time or end_time
r.set('test:auto_test:{}'.format(type), time)
@redis_obj
def read_auto_test_child_time(self, r, type):
# 读取自动化测试运单执行的开始和结束时间,作为统计筛选的时间范围,type:start_time or end_time
name = 'test:auto_test:{}'.format(type)
date = r.get(name)
return date.decode()
class ConnectMysql(object):
def __init__(self, SQL_HOST, SQL_PORT, SQL_USERNAME, SQL_PASSWORD, database):
# 留一点数据库更新的时间
time.sleep(0.5)
# 创建连接对象
self.conn = connect(host=SQL_HOST, port=int(SQL_PORT), user=SQL_USERNAME, password=SQL_PASSWORD,
database=database, charset='gb2312')
# 创建游标对象
self.cs = self.conn.cursor()
def __del__(self):
# 关闭连接
self.cs.close()
self.conn.close()
def delete(self, sql):
self.cs.execute(sql)
self.conn.commit()
def update(self, sql):
self.cs.execute(sql)
self.conn.commit()
def search(self, sql):
# 执行sql
self.cs.execute(sql)
return self.see_list
# for i in self.cs.fetchall():
# print(i)
@property
def see_list(self):
# 返回列表数据
result = []
data = self.cs.fetchall()
for tuple_data in data: # 查询出一个元组
if len(tuple_data) == 1:
for content in tuple_data:
result.append(content)
else:
result.append(tuple_data)
return result
'''
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
'''
from selenium import webdriver
from config.constant import CHROME_DRIVER
class WebDriver(object):
def __init__(self):
pass
def open_browser(self, set_headless_browser=True):
"""
创建chrome参数对象
:param set_headless_browser: 是否设置无头浏览器
:return: driver对象
"""
opt = webdriver.ChromeOptions()
if set_headless_browser is True:
# 把chrome设置成无界面模式,不论windows还是linux都可以,自动适配对应参数
opt.set_headless()
# 设置窗口大小
chrome_options = opt.add_argument("--window-size=1920,1080")
driver = webdriver.Chrome(executable_path=CHROME_DRIVER, options=opt, chrome_options=chrome_options)
driver.implicitly_wait(2) # 隐式等待时间2秒
return driver
'''
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
'''
# -*- coding: utf-8 -*-
import json
import re
from requests import request
from config import ENV_PATH, DATA_UPLOADER
class BoxRequest():
def __init__(self, url, method, headers, data=None, content_type='json'):
self.url = self.url_path(url)
self.method = self.check_method(method)
self.data = data
self.content_type = content_type
self.headers = self.check_headers(headers)
self._resp_msg = self._send_request() # 把发送请求提成属性,目的是保证只会调用一次
def url_path(self, url):
# 给接口拼接ip+端口
if url.find('http') >= 0: # 判断请求url是否携带了ip和端口
raise Exception('url{}不需要携带ip和端口'.format(url))
try:
service = re.search(r'(.*?)/', url).group(1)
if service in DATA_UPLOADER: # 如果是数据中心的服务
url = ENV_PATH.get('data_uploader')+url
return url
except Exception as f:
raise Exception('未解析到接口所对应的服务端口号')
def check_method(self, method):
# 校验请求方法是否符合要求
standard_method = ('get', 'post', 'put', 'delete')
if method not in standard_method:
raise Exception('请求方法错误')
return method
def check_headers(self, headers):
"""
校验请求头,
content_type为form,将content-type改为form-data格式,params接参数
content_type为form_url,将content-type改为form-url格式,data接参数,需将参数拼接为str
:param headers:
:return:
"""
if self.content_type == 'form':
headers['content-type'] = 'multipart/form-data; boundary=----WebKitFormBoundary22qc0YeSzHAJnSOL'
elif self.content_type == 'form_url':
headers['content-type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
else:
headers['content-type'] = 'application/json'
return headers
def check_data(self, data):
"""
校验参数
:param data:
:return:
"""
# 判断请求类型是json,非get请求 并且是列表或字典类型,转换为json数据
if self.headers.get('content-type') == 'application/json' and self.method != 'get' and (isinstance(data, list) or isinstance(data, dict)):
return json.dumps(data)
elif self.headers.get('content-type').find('form-url') >= 0 and (isinstance(data, list) or isinstance(data, dict)):
# form-url类型,将参数转成字符串,汉字转换成latin1格式
new_data = ''
for k, v in data.items():
new_data += '{}={}&'.format(k, v)
return new_data.encode('utf-8').decode('latin1')
else:
return data
def _send_request(self):
# 如果是get请求 或者 表单传参数,用params接
if self.method == 'get' or self.method == 'delete' or self.headers['content-type'].find('multipart/form-data') >= 0:
resp = request(self.method, self.url, headers=self.headers, params=self.data)
# 其他情况都将参数转换为json类型
else:
data = self.check_data(self.data)
resp = request(self.method, self.url, headers=self.headers, data=data)
return resp
@property
def resp_result(self):
# 返回bool值,适用于新增或修改接口,校验是否请求成功
# 如果返回值是一张图片,防止报错
try:
resp_content = self._resp_msg.json().get('msg')
if self._resp_msg.status_code == 200 and resp_content == 'success':
result = True
else:
result = False
return result
except Exception as f:
pass
@property
def resp_info(self):
# 返回所有响应结果,适用于查询接口
resp = self._resp_msg.json()
if self._resp_msg.status_code == 200 and resp.get('msg') == 'success':
return resp
else:
raise Exception('接口返回错误,url:{},状态码:{},错误信息:{},详细参数:{}'.format(self.url, self._resp_msg.status_code, resp.get('msg'), self.data))
@property
def resp_con(self):
# 不做任何处理
return self._resp_msg
\ No newline at end of file
"""
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
"""
# -*- coding: utf-8 -*-
"""
根据setting里面执行的环境从constant读取相关的数据
"""
from config.constant import *
from config.setting import Execute
env = Execute()
if env.environment == 'test':
DISPATCH_CENTER_USER_MESSAGE = TEST_DISPATCH_CENTER_USER_MESSAGE # 账号配置信息
ENV_PATH = TEST_PATh # 产品地址信息
REDIS_CON = TEST_REDIS_CON # rides库地址信息
SQL_HOST = TEST_HOST # 下面是MySQL库的地址及信息
SQL_PORT = TEST_PORT
SQL_USERNAME = TEST_USERNAME
SQL_PASSWORD = TEST_SQL_PASSWORD
elif env.environment == 'pre':
DISPATCH_CENTER_USER_MESSAGE = PRE_DISPATCH_CENTER_USER_MESSAGE
ENV_PATH = PRE_PATH
REDIS_CON = PRE_REDIS_CON
SQL_HOST = PRE_HOST
SQL_PORT = PRE_PORT
SQL_USERNAME = PRE_USERNAME
SQL_PASSWORD = PRE_SQL_PASSWORD
elif env.environment == 'dev':
DISPATCH_CENTER_USER_MESSAGE = DEV_DISPATCH_CENTER_USER_MESSAGE
ENV_PATH = DEV_PATH
REDIS_CON = DEV_REDIS_CON
SQL_HOST = DEV_HOST
SQL_PORT = DEV_PORT
SQL_USERNAME = DEV_USERNAME
SQL_PASSWORD = DEV_SQL_PASSWORD
"""
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
"""
"""
配置用户常量等信息
"""
from os import path
CHROME_DRIVER = r'C:\Users\clx\AppData\Local\Google\Chrome\Application' # chrome driver 路径
# 慧标化验账号信息配置
TEST_DISPATCH_CENTER_USER_MESSAGE = {
'data_uploader_app': {'mobile': '16600000000', 'password': '000000', 'product_code': 'trade-client-app', 'Client-Type': 'android'}
}
PRE_DISPATCH_CENTER_USER_MESSAGE = {
'data_uploader_app': {'mobile': '16600000000', 'password': '000000', 'product_code': 'coal-analysis-report-app', 'Client-Type': 'android'}
}
DEV_DISPATCH_CENTER_USER_MESSAGE = {}
# 测试环境地址
TEST_PATh = {
'data_uploader': 'https://gateway.testclx.cn/'
}
# 预发布环境地址
PRE_PATH = {
'data_uploader': 'https://gateway.preclx.cn/'
}
# 开发环境地址
DEV_PATH = {
'data_uploader': 'https://gateway.devclx.cn/'
}
# 数据中心服务列表
DATA_UPLOADER = ('coal-price-analysis')
# 测试redis连接ip和password
TEST_REDIS_CON = [{'host': '8.152.101.138', 'port': 6379, 'password': 'clx!2022clx'}]
# 测试mysql配置
TEST_HOST = 'rm-2zeubi7yjy6c88urjco.rwlb.rds.aliyuncs.com'
TEST_PORT = 3306
TEST_USERNAME = 'clxjava'
TEST_SQL_PASSWORD = 'CLXjava#2023'
# 预发布redis连接ip和password
# PRE_REDIS_CON = [{'host': '47.92.112.22', 'port': 6379, 'password': 'clxclxclx'},
# {'host': '47.92.112.22', 'port': 6380, 'password': 'clxclxclx'},
# {'host': '47.92.112.22', 'port': 6381, 'password': 'clxclxclx'},
# {'host': '47.92.112.22', 'port': 6391, 'password': 'clxclxclx'}
# ]
PRE_REDIS_CON = [{'host': '8.152.102.77', 'port': 6379, 'password': 'clx!2022clx'}]
# 预发布mysql配置
PRE_HOST = 'rm-2ze3n0w9y62w3or865o.mysql.rds.aliyuncs.com'
PRE_PORT = 3306
PRE_USERNAME = 'clxjava'
PRE_SQL_PASSWORD = 'CLXjava#2023'
# 开发环境redis连接ip和password
DEV_REDIS_CON = [{'host': '39.103.223.102', 'port': 6379, 'password': 'clx!2022clx'}]
# 开发mysql配置
DEV_HOST = '47.92.136.150'
DEV_PORT = 8066
DEV_USERNAME = 'clx'
DEV_SQL_PASSWORD = 'clx#0622'
BASE_PATH = path.abspath(path.dirname(path.dirname(__file__))) # 获取项目的根路径
# mac使用
LOG_PATH = path.join(BASE_PATH, r'log/') # 日志文件存储路径
IMAGES_PATH = path.join(BASE_PATH, r'lib/static_image/') # 图片路径
# windows使用
# LOG_PATH = path.join(BASE_PATH,'log\\') # 日志文件存储路径
# IMAGES_PATH = path.join(BASE_PATH, 'lib\\static_image\\') # 图片路径
# redis中请求头保存时间
REDIS_SAVE_TIME = 604800
# 慧标化验app版本
REPORT_APP_Content_Type = 'application/json'
# 慧标化验app版本号
REPORT_APP_client_type = 'android'
# 慧标化验操作系统
REPORT_APP_device_id = '23840fd613d453c89936ac21f8f44eee9'
REPORT_APP_versionCode = '15'
REPORT_APP_versionName = '1.0.7'
REPORT_APP_model = 'V2313A'
REPORT_APP_imei = '23840fd613d453c89936ac21f8f44eee9'
REPORT_APP_product_code = 'coal-analysis-report-app'
REPORT_APP_productType = 'coal-analysis-report-app'
REPORT_APP_productChannel = 'android_app'
REPORT_APP_contentType = 'application/json'
"""
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
"""
from lib.random_tool import MethodTool
from config.constant import TEST_HOST
class Execute(object):
# file_path = r'D:\Tool\Jenkins\trading_platform_test\Jenkins\jenkins_data.yaml'
# values_data = MethodTool.read_yaml(file_path)
# ENVIRONMENT = values_data.get('运行环境')
# logger.info(f"当前环境:{ENVIRONMENT}")
ENVIRONMENT = "test"
def __init__(self, environment=ENVIRONMENT):
self.environment = self._default(environment)
def _default(self, environment):
return environment
差异被折叠。
'''
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
'''
"""
本模块封装一些支持类、函数
例如:csv操作方法、各种随机值等
"""
'''
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
'''
import base64
import hashlib
from base.box_requests import BoxRequest
def md5(data):
"""
使用md5进行加密
:param data:
:return:
"""
if not isinstance(data, str):
password = str(data)
m = hashlib.new('md5')
m.update(b'%s' % data.encode())
return m.hexdigest()
def dispatch_center_load_images(headers, file_path):
"""
上传图片通用接口
:param headers: 请求头
:param file_path: 文件路径
:return: 完整的图片地址
"""
with open(file_path, 'rb') as fin:
image_data = fin.read()
base64_data = base64.b64encode(image_data).decode() # 图片编码为base64
url = r'msl-message/file/uploadForm'
method = 'post'
data = {
'file': base64_data
}
resp = BoxRequest(url, method, headers, data, content_type='form').resp_info
return resp.get('data')
def update_images(headers, file_path, role):
"""
接口上传的图片需要经过这个接口处理,返回存储到服务器图片的路径
:param headers: 请求头
:param file_path: 文件路径
:param role: 角色
:return: 完整的图片地址
"""
with open(file_path, 'rb') as fin:
image_data = fin.read()
base64_data = base64.b64encode(image_data).decode() # 图片编码为base64
url = r'message-service/file/base64ImageList'
method = 'post'
base64_image = 'data:image/jpeg;base64,' + base64_data
if role == 'owner':
role = 'user'
elif role == 'driver':
role = 'truck'
elif role == 'weight': # 云磅房
role = 'order'
elif role == 'vip': # VIP
role = 'order'
data = {'base64FileList': [base64_image], 'type': role}
resp = BoxRequest(url, method, headers, data).resp_info
return resp.get('data').get('pathList')[0]
'''
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
'''
"""
日志文件,使用方法:直接调用logger对象即可,例如:logger.info()
"""
import datetime
import sys
import logging
from config.constant import LOG_PATH
# 日志默认的配置
DEFAULT_LOG_LEVEL = logging.INFO # 默认等级
DEFAULT_LOG_FMT = '%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s: %(message)s' # 默认日志格式
DEFUALT_LOG_DATEFMT = '%Y-%m-%d %H:%M:%S' # 默认时间格式
DEFAULT_LOG_FILENAME = LOG_PATH + '/%s.log' % (datetime.datetime.today().date()) # 默认日志文件名称,绝对路径
class Logger(object):
def __init__(self):
# 1. 获取一个logger对象
self._logger = logging.getLogger()
# 2. 设置format对象
self.formatter = logging.Formatter(fmt=DEFAULT_LOG_FMT, datefmt=DEFUALT_LOG_DATEFMT)
# 3. 设置日志输出
# 3.1 设置文件日志模式
self._logger.addHandler(self._get_file_handler(DEFAULT_LOG_FILENAME))
# 3.2 设置终端日志模式
self._logger.addHandler(self._get_console_handler())
# 4. 设置日志等级
self._logger.setLevel(DEFAULT_LOG_LEVEL)
def _get_file_handler(self, filename):
"""
返回一个文件日志handler
:param filename:
:return:
"""
# 1. 获取一个文件日志handler
filehandler = logging.FileHandler(filename=filename, encoding="utf-8")
# 2. 设置日志格式
filehandler.setFormatter(self.formatter)
# 3. 返回
return filehandler
def _get_console_handler(self):
"""返回一个输出到终端日志handler"""
# 1. 获取一个输出到终端日志handler
console_handler = logging.StreamHandler(sys.stdout)
# 2. 设置日志格式
console_handler.setFormatter(self.formatter)
# 3. 返回handler
return console_handler
@property
def logger(self):
return self._logger
# 初始化并配一个logger对象,达到单例效果
# 使用时,直接导入logger就可以使用
logger = Logger().logger
\ No newline at end of file
"""
@-*- coding: utf-8 -*-
@ python:python 3.9
@ 创建人员:libaofeng
@ 创建时间:2023/11/24
"""
import chardet
import random
import time
import string
import pymysql
import yaml
from urllib.parse import quote
from numpy.core.tests.test_simd import cls
from datetime import datetime, timedelta
class MethodTool:
@staticmethod
def get_current_time():
"""
生成当前时间精确到秒
:return:
"""
# 获取当前时间精确到秒
current_time = datetime.now()
# 格式化时间字符串,精确到秒
formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
return formatted_time
@staticmethod
def current_time():
"""
生成当前时间 精确到分
:return:
"""
current_time = datetime.now()
formatted_time = current_time.strftime("%Y-%m-%d %H:%M") # 格式化日期时间字符串
return formatted_time
@staticmethod
def current_time_tow():
"""
生成当前时间 精确到日
:return:
"""
current_time = datetime.now()
formatted_time = current_time.strftime("%Y-%m-%d") # 格式化日期时间字符串
return formatted_time
@staticmethod
def get_start_of_day(hour, point, second):
"""
生成当前日期及自定义时分秒
:param hour: 时
:param point: 分
:param second: 秒
:return:
"""
now = datetime.now()
start_of_day = datetime(now.year, now.month, now.day, hour, point, second)
return start_of_day
@staticmethod
def process_number_advanced(value, reduction_factor=10, adjustment_range=10):
"""
传入一个数值,对这个数值缩小十倍后再对这个数据加减10以内的数,保留两位小数
用于产地信息上报的价格
参数:
value: 输入的数值
reduction_factor: 缩小倍数 (默认10)
adjustment_range: 随机调整范围 (默认10)
返回:
处理后的结果
"""
try:
num = float(value)
reduced = num / reduction_factor
adjustment = random.uniform(-adjustment_range, adjustment_range)
return round(reduced + adjustment, 2)
except (TypeError, ValueError):
raise ValueError("输入必须是可以转换为数字的值")
@staticmethod
def process_number_integer(value, reduction_factor=10, adjustment_range=10):
"""
传入一个数值,对这个数值缩小十倍后再对这个数据加减10以内的整数
用于产地信息上报的价格
参数:
value: 输入的数值
reduction_factor: 缩小倍数 (默认10)
adjustment_range: 随机调整范围 (默认10)
返回:
处理后的整数结果
"""
try:
num = float(value)
reduced = num / reduction_factor
adjustment = random.uniform(-adjustment_range, adjustment_range)
result = reduced + adjustment
return round(result, 2) # 先四舍五入再转换为整数
except (TypeError, ValueError):
raise ValueError("输入必须是可以转换为数字的值")
@staticmethod
def generate_random_number_custom(min_val=30, max_val=85, multiplier=100):
"""
生成指定范围内的随机整数,然后乘以指定倍数返回
参数:
min_val: 最小值(默认30)
max_val: 最大值(默认85)
multiplier: 倍数(默认100)
返回:
float: 处理后的随机数
"""
# 生成指定范围内的随机数
random_num = int(random.uniform(min_val, max_val))
# 乘以指定倍数
result = random_num * multiplier
return result
@staticmethod
def generate_random_range(min_val=10, max_val=22, decimal_places=2):
"""
生成指定范围内的随机数
参数:
min_val: 最小值(默认10)
max_val: 最大值(默认22)
decimal_places: 小数位数(默认2)
返回:
float: 指定范围内的随机数
"""
random_num = random.uniform(min_val, max_val)
return round(random_num, decimal_places)
@classmethod
def reads_yaml(self, yaml_file_path):
"""
读取yaml文件并将值组成列表
:param yaml_file_path: 文件路径
:return:
"""
# 尝试多种编码
try_encodings = ['utf-8', 'gbk', 'iso-8859-1']
# 读取YAML文件
for encoding in try_encodings:
try:
with open(yaml_file_path, 'r', encoding=encoding) as file:
yaml_content = yaml.safe_load(file)
break
except UnicodeDecodeError:
continue
# 如果尝试了所有编码仍然无法解码,使用 chardet 进行检测
else:
detected_encoding = cls.detect_encoding(yaml_file_path)
with open(yaml_file_path, 'r', encoding=detected_encoding) as file:
yaml_content = yaml.safe_load(file)
return yaml_content
@staticmethod
def read_yaml(file_path):
"""
读取yaml文件
:param file_path: 文件路径
:return: yaml文件内容
"""
with open(file_path, 'r', encoding='utf-8') as file:
values_data = yaml.safe_load(file)
return values_data
@staticmethod
def write_yaml(file_path, values_data):
"""
将数据写入yaml文件
:param self:
:param yaml_file_path:
:return:
"""
with open(file_path, 'w', encoding='utf-8') as file:
yaml.dump(values_data, file, allow_unicode=True, default_flow_style=False)
@staticmethod
def detect_encoding(file_path):
"""
使用 chardet 检测文件编码
:param file_path: 文件路径
:return: 检测到的编码
"""
with open(file_path, 'rb') as file:
result = chardet.detect(file.read())
return result['encoding']
if __name__ == '__main__':
tool = MethodTool()
random_number = tool.process_number_integer(4700, 10, 10)
print(random_number)
差异被折叠。
2025-09-17 10:57:27 coal_price_analysis_app.py [line:139] INFO: 正在执行第 1/10 次...
2025-09-17 10:57:27 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 巴图塔 煤种:面煤 热值:5000Kcal/kg 价格:490.22元/吨
2025-09-17 10:57:27 coal_price_analysis_app.py [line:139] INFO: 正在执行第 2/10 次...
2025-09-17 10:57:28 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 青草界煤矿 煤种:天隆精块 热值:5100Kcal/kg 价格:516.17元/吨
2025-09-17 10:57:28 coal_price_analysis_app.py [line:139] INFO: 正在执行第 3/10 次...
2025-09-17 10:57:28 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 锦界煤矿 煤种:面煤 热值:5800Kcal/kg 价格:579.0元/吨
2025-09-17 10:57:28 coal_price_analysis_app.py [line:139] INFO: 正在执行第 4/10 次...
2025-09-17 10:57:28 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 青草界煤矿 煤种:面煤3 热值:4400Kcal/kg 价格:441.28元/吨
2025-09-17 10:57:28 coal_price_analysis_app.py [line:139] INFO: 正在执行第 5/10 次...
2025-09-17 10:57:29 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 青草界煤矿 煤种:渣渣煤 热值:600Kcal/kg 价格:57.11元/吨
2025-09-17 10:57:29 coal_price_analysis_app.py [line:139] INFO: 正在执行第 6/10 次...
2025-09-17 10:57:29 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 柠条塔煤矿 煤种:面煤3 热值:4400Kcal/kg 价格:437.02元/吨
2025-09-17 10:57:29 coal_price_analysis_app.py [line:139] INFO: 正在执行第 7/10 次...
2025-09-17 10:57:29 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 柠条塔煤矿 煤种:面煤 热值:5000Kcal/kg 价格:504.42元/吨
2025-09-17 10:57:30 coal_price_analysis_app.py [line:139] INFO: 正在执行第 8/10 次...
2025-09-17 10:57:30 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 黄骅港 煤种:筛面 热值:5300Kcal/kg 价格:531.24元/吨
2025-09-17 10:57:30 coal_price_analysis_app.py [line:139] INFO: 正在执行第 9/10 次...
2025-09-17 10:57:30 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 黄骅港 煤种:块煤 热值:5500Kcal/kg 价格:543.47元/吨
2025-09-17 10:57:30 coal_price_analysis_app.py [line:139] INFO: 正在执行第 10/10 次...
2025-09-17 10:57:30 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 瓦窑坡 煤种:水洗煤 热值:4500Kcal/kg 价格:454.96元/吨
2025-09-17 11:01:40 coal_price_analysis_app.py [line:139] INFO: 正在执行第 1/10 次...
2025-09-17 11:01:40 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 京唐港 煤种:筛面 热值:5500Kcal/kg 价格:544.41元/吨
2025-09-17 11:01:41 coal_price_analysis_app.py [line:139] INFO: 正在执行第 2/10 次...
2025-09-17 11:01:41 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 青草界煤矿 煤种:筛面 热值:5300Kcal/kg 价格:531.42元/吨
2025-09-17 11:01:41 coal_price_analysis_app.py [line:139] INFO: 正在执行第 3/10 次...
2025-09-17 11:01:42 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 柠条塔煤矿 煤种:2-5籽 热值:5000Kcal/kg 价格:505.08元/吨
2025-09-17 11:01:42 coal_price_analysis_app.py [line:139] INFO: 正在执行第 4/10 次...
2025-09-17 11:01:42 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 柠条塔煤矿 煤种:筛面 热值:5500Kcal/kg 价格:559.14元/吨
2025-09-17 11:01:42 coal_price_analysis_app.py [line:139] INFO: 正在执行第 5/10 次...
2025-09-17 11:01:42 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 瓦窑坡 煤种:面煤 热值:4500Kcal/kg 价格:458.34元/吨
2025-09-17 11:01:42 coal_price_analysis_app.py [line:139] INFO: 正在执行第 6/10 次...
2025-09-17 11:01:43 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 黄骅港 煤种:天隆精块 热值:5100Kcal/kg 价格:512.88元/吨
2025-09-17 11:01:43 coal_price_analysis_app.py [line:139] INFO: 正在执行第 7/10 次...
2025-09-17 11:01:43 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 天瑞煤矿 煤种:2-5籽 热值:5000Kcal/kg 价格:494.73元/吨
2025-09-17 11:01:43 coal_price_analysis_app.py [line:139] INFO: 正在执行第 8/10 次...
2025-09-17 11:01:43 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 瓦窑坡 煤种:洗小籽 热值:5600Kcal/kg 价格:550.83元/吨
2025-09-17 11:01:44 coal_price_analysis_app.py [line:139] INFO: 正在执行第 9/10 次...
2025-09-17 11:01:44 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 瓦窑坡 煤种:块煤 热值:2500Kcal/kg 价格:247.55元/吨
2025-09-17 11:01:44 coal_price_analysis_app.py [line:139] INFO: 正在执行第 10/10 次...
2025-09-17 11:01:44 coal_price_analysis_app.py [line:121] INFO: 产地信息上报成功! 产地: 瓦窑坡 煤种:渣渣煤 热值:700Kcal/kg 价格:62.26元/吨
差异被折叠。
差异被折叠。
This source diff could not be displayed because it is too large. You can view the blob instead.
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论