1、前面我们已经学过了python和mysql交互,把基金网站的数据插入数据库中。
http://blog.csdn.net/github_26672553/article/details/78530019
并且我们是学习了一个ORM框架sqlalchemy
:
http://blog.csdn.net/github_26672553/article/details/78537605
根据sqlalchemy
的需要,我们需要创建一个实体类来关联数据表(相当于一种映射关系)。
我们先看看建表SQL:
CREATE TABLE `fund` (
`code` varchar(50) NOT NULL DEFAULT '' COMMENT '基金编码',
`name` varchar(255) DEFAULT NULL COMMENT '基因名称',
`NAV` decimal(5,4) DEFAULT NULL COMMENT '单位净值',
`ACCNAV` decimal(5,4) DEFAULT NULL COMMENT '累计净值',
`updated_at` datetime DEFAULT NULL,
`fdate` datetime NOT NULL COMMENT '基金日期',
`DGR` varchar(20) DEFAULT NULL COMMENT '日增长率',
`DGV` varchar(20) DEFAULT NULL COMMENT '日增长值',
`fee` varchar(20) DEFAULT NULL COMMENT '基金手续费',
PRIMARY KEY (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='基金表';
然后创建fund
这个数据表的实体类FundMapper.py
:
# coding: utf-8
from sqlalchemy import Column, DateTime, Numeric, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
metadata = Base.metadata
class FundMapper(Base):
# 数据表名称
__tablename__ = 'fund'
code = Column(String(50), primary_key=True)
name = Column(String(255))
NAV = Column(Numeric(5, 4))
ACCNAV = Column(Numeric(5, 4))
updated_at = Column(DateTime)
fdate = Column(DateTime)
DGR = Column(String(20))
DGV = Column(String(20))
fee = Column(String(20))
def __str__(self):
return "基金代码:{0},基金名称:{1},单位净值:{2},累计净值:{3},基金日期:{4},日增长率:{5},日增长值:{6},费率:{7}"\
.format(self.code,self.name,self.NAV,self.ACCNAV,self.fdate,self.DGR,self.DGV,self.fee)
2、前面我们已经完成了把基金网站html抓取到本地项目的htmls
目录中,最后保存的是.txt
文件。
http://blog.csdn.net/github_26672553/article/details/78602604
因为我们已经修改了表结构,我们来看看现在获取基金数据的代码:
from bs4 import BeautifulSoup
from datetime import datetime
# 读取保存在htmls目录下的txt文件数据
# 此函数是处理特殊文字
def getText(ele):
if ele != None:
txt = ele.get_text()
if str(txt).strip() == "---":
txt = 0
return txt
return ""
def getFundDataByHtml(html):
soup = BeautifulSoup(html,"html.parser")
fund_codes = soup.find("table", id="oTable").tbody.find_all("td", "bzdm") # 基金编码 集合
fdate = soup.find("table", id="oTable").thead.find("td",colspan='2').get_text() #基金日期
result = []
for code in fund_codes:
#print(code)
result.append({"code":code.get_text()
,"name":code.next_sibling.find("a").get_text()
,"NAV":getText(code.next_sibling.next_sibling)
,"ACCNAV":getText(code.next_sibling.next_sibling.next_sibling)
,"DGV":code.parent.find("td","rzzz").get_text() # 日增长值
,"DGR":code.parent.find("td","rzzl").get_text() # 日增长率
,"fee":getText(code.parent.find("div","rate_f")) # 费率,注意这里不要定位到A元素,有的基金没有这个div,所以要做判断
,"updated_at":datetime.now().isoformat(sep=' ',timespec="seconds")
,"fdate":fdate}
)
return result
分析html内容要用BeautifulSoup
这个包。
3、最后就是把读取到的数据 写入到mysql数据库
from sqlalchemy import create_engine,desc,text
from common.config import dbUrl
from sqlalchemy.orm import sessionmaker
import os
from mappers.FundMapper import FundMapper
# 连接数据库
engine = create_engine(dbUrl, echo=True)
# 保存到数据库
def saveToDB():
# 从本地htmls目录中读取
data_dir = "../htmls" # 这里根据你
file_path = os.listdir(data_dir)
mySession = sessionmaker(engine)() # 管理数据库的对象
data_list = []
for p in file_path:
if os.path.isfile(os.path.join(data_dir,p)):
#print(p)
with open(os.path.join(data_dir,p),"rb") as f:
html = f.read().decode("utf-8")
f.close()
result_set = getFundDataByHtml(html) #从html取出需要的基金数据
for res in result_set:
fund = FundMapper(**res) # ORM实体类对象
data_list.append(fund)
# 最后才批量插入
mySession.add_all(data_list)
mySession.commit()
mySession.close()
执行saveToDB
函数就可以了:
saveToDB()