说明
近期写了一个简单的项目,在后台运行获取网上的期货数据并保存到相应的数据库里。由于之前工作很多这种简单的类似调用接口或攫取数据的项目都是用 Python 来写,因此这次也继续用 Python 写。但是这次更换了几个包,此份文档简单来说明一下。
依赖的包
- toml: 用户解析配置文件,配置文件用的是 toml 格式。
- arrow: 用于处理日期相关。
- loguru: 用于日志处理。
- requests: 用于 http 请求响应。
- pandas: 用于数据处理。
- numpy: 用于数据计算。
- mysql-connector-python: 用于操作 MySQL 数据库。
- SQLAlchemy: 用于操作数据库。
- click: 用于命令行参数解析。
项目结构
$ tree -L 2
.
├── README.md
├── config
│ └── config.toml. # 配置文件
├── log # 日志目录
├── app_demo # 程序目录
│ ├── __init__.py
│ ├── config.py # 加载配置信息代码
│ ├── container.py. # 容器类
│ ├── exceptions.py # 异常类
│ ├── log.py # 日志程序
│ └── main.py # 主程序
├── setup.py # 安装程序
└── venv # 虚拟环境
├── bin
├── lib
└── pyvenv.cfg
部分代码示例
1、main.py
import time
import arrow
import numpy as np
import click
import sqlalchemy
from sqlalchemy import text
from app_demp.container import Container
config = None
log = None
db = None
@click.command()
@click.option('--config_file', default='./config.toml', help='Specify config file')
@click.option('--start_date', default=None, help='Specify start date')
@click.option('--end_date', default=None, help='Specify end date')
def main(config_file, start_date, end_date):
global config, log, db
print("Load config file: {}".format(config_file))
container = Container(config_file)
config = container.get_config()
log = container.get_logger()
log.info("Load config file: {}".format(config_file))
db = container.get_db()
if start_date is None or end_date is None:
start_date = arrow.now().format('YYYYMMDD')
end_date = start_date
log.info("Date Info, start date: {}, end date: {}".format(start_date, end_date))
run(start_date, end_date)
if __name__ == '__main__':
main()
2、container.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
class Container(object):
"""
容器类
"""
def __init__(self, config_file):
"""
""" self.config_file = config_file
self.config = None
self.logger = None
self.db = None
def get_config(self):
"""
获取指定配置信息
:return:
""" if self.config is None:
from app_demo.config import get_config
self.config = get_config(self.config_file)
return self.config
def get_logger(self):
"""
获取日志对象
:return:
"""
if self.config is None:
self.get_config()
if self.logger is None:
from app_demo.log import get_logger
self.logger = get_logger(self)
return self.logger
def get_db(self):
if self.config is None:
self.get_config()
if self.db is None:
dsn = "mysql+mysqlconnector://{user}:{password}@{host}:{port}/{database}?auth_plugin=mysql_native_password".format(
user=self.get_config().get('db').get('user'),
password=self.get_config().get('db').get('password'),
host=self.get_config().get('db').get('host'),
port=self.get_config().get('db').get('port'),
database=self.get_config().get('db').get('database'),
)
engine = create_engine(dsn, echo=False)
db_session = sessionmaker(bind=engine, autoflush=True, expire_on_commit=True)
self.db = db_session()
return self.db
3、config.py
import toml
from app_demo.exceptions import *
def get_config(config_file):
if config_file is not None:
with open(config_file) as config_file_handler:
config = toml.loads(config_file_handler.read())
if not all(key in config for key in ['log']):
raise ConfigException('Config error, config file: {file}'.format(file=config_file))
if not (isinstance(config.get('db'), dict) and all(key in config.get('db') for key in
['host', 'port', 'database', 'user', 'password'])):
raise ConfigException('Config error, config file: {file}'.format(file=config_file))
return config
else:
raise Exception('Can not retrieve config file')
4、log.py
from loguru import logger
def get_logger(container):
log_config = container.get_config().get('log')
logger.add(
log_config.get('filename'),
rotation=log_config.get('rotation_size'),
retention=log_config.get('retention'),
compression=log_config.get('compression'),
)
return logger
结论
软件工程方面,软件开发方法学的泰山北斗 Kent Beck 说过一句至理名言: “Make it Work, Make it Right, Make it Fast.”,最重要是先 Make it Work。简单点,大家可以参考这个脚手架先把项目做起来,后面再慢慢完善。