项目介绍
本项目的基金数据来自天天基金网,但该网站用户体验较差,内容冗余,故自己实现一个轻量级网站,从8个指标维度对股票基金和债券基金进行挑选,可对进行收益进行排序,并且可查看基金的同类排名与历史涨跌幅,方便快捷的筛选选出优质基金进行投资,最大化收益率。
网站已部署在 http://134.175.24.108:52571 可点击链接查看效果,为了不影响其他用户的体验,部署的网站只显示前100只基金的数据,删除和自选的操作使用了本地存储,存在浏览器端。下载的代码压缩包中包含了本地存储和服务端存储两种版本。
项目截图如下:
项目文件结构
fund # 代码文件夹
├── exclude.txt # 已删除基金列表
├── own.txt # 自选基金列表
├── requirements.txt # python第三方库依赖文件
├── fund.py # 服务端文件
├── static # 静态文件夹
│ ├── highstock.js
│ ├── index.css
│ ├── index.js
│ └── jj.png
└── templates # 模板文件夹,存放html页面
└── index.html
此外还有一个fund_local
文件夹,结构与fund
文件夹一致,其中的代码为本地存储版本,使用localStorage
项目运行
- 安装python
- 安装python第三方依赖库,项目文件夹中有依赖文件
pip install -r requirements.txt
,依赖的库主要有flask,flask-bootstrap,pandas,gevent,requests。 - 运行
python fund.py
,成功运行会输出Listening at http://localhost:52571
- 访问 http://localhost:52571
代码实现
使用flask框架,网站前端框架使用bootstrap,表格控件为bootstrap-table,趋势图为highstock,文章最后有用到几个框架的文档网址,可自行阅读。
后端实现
首先进行初始化
def __init__(self, fund_type, num=100):
self.app = Flask(__name__)
self.num = num # 基金数量
self.last_time = 0 # 最后一次更新时间
self.app.debug = True
self.fund_type = fund_type # 基金类型,(股票,债券或者混合型)
self.GetExcludeAndOwn() # 获取已删除和自选的基金列表
self.GetData() # 获取数据
Bootstrap(self.app) # 初始化bootstrap
初始化完成之后
# 读取文件,获取删除的基金和自选的基金
def GetExcludeAndOwn(self):
with open("exclude.txt", "a+") as fs:
self.exclude = map(lambda x: x.strip(), fs.readlines())
self.exclude = set(self.exclude)
print("exclude id: ", self.exclude)
with open("own.txt", "a+") as fs:
self.own = map(lambda x: x.strip(), fs.readlines())
self.own = set(self.own)
print("own id: ", self.own)
从天天基金网获取基金数据,通过抓包得到数据的链接,爬虫与抓包这里不做展开,有兴趣可单独联系。
基金数据每天更新一次,获取到基金数据之后,存入DateFrame,去掉多余的列,只保留8个指标,然后将数据转为html,方便后面直接返回给前端展示。
# 获取近一年基金数据
def GetData(self):
now = time.time()
if (now - self.last_time < 60 * 60 * 24): # 24小时更新一次
return self.fund_table
self.last_time = now
s = requests.Session()
now = datetime.today()
# 起始时间为一年前的今天,结束时间为今天
sd = date2str(now - timedelta(days=365)).strftime('%Y-%m-%d')
ed = date2str(now).strftime('%Y-%m-%d')
res = s.get('http://fund.eastmoney.com/data/rankhandler.aspx?op=ph&dt=kf&ft=%s&rs=&gs=0&sc=1yzf&st=desc&sd=%s&ed=%s&qdii=|&tabSubtype=,,,,,&pi=1&pn=%d&dx=1&v=%lf' %
(self.fund_type, sd, ed, self.num, random())).content
res = res[res.find("["):res.rfind("]") + 1]
obj = json.loads(res)
arr = []
for fund in obj