码农技术炒股之路——抓取股票基本信息、实时交易信息、主力动向信息
来源:互联网 发布:决策树算法例题经典 编辑:程序博客网 时间:2024/04/28 07:47
从本节开始,我们开始介绍各个抓取和备份业务。(转载请指明出于breaksoftware的csdn博客)
因为我们数据库很多,数据库中表也很多,所以我们需要一个自动检测并创建数据库和表的功能。在《码农技术炒股之路——数据库管理器、正则表达式管理器》一文中,我们介绍了数据库管理器帮我们自动创建数据库,但是没有自动创建表的功能。于是我们需要实现一个。
class prepare_table(): def __init__(self, conn_name, table_template_name): self._conn_name = conn_name self._table_template_name = table_template_name self._create_table_format = "" def prepare(self, table_name): self._create_table_if_not_exist(table_name) def _get_table_template(self): file_path = "./conf/table_template/" + self._table_template_name + ".ttpl" if False == os.path.isfile(file_path): LOG_WARNING("can't read %s" %(file_path)) return fobj = open(file_path) try: self._create_table_format = fobj.read() except: self._create_table_format = "" LOG_WARNING("get table_template file error.path: %s" % (file_path)) finally: fobj.close() def _create_table_if_not_exist(self, table_name): db_manager = mysql_manager() conn = db_manager.get_mysql_conn(self._conn_name) if False == conn.has_table(table_name): if len(self._create_table_format) == 0: self._get_table_template() if len(self._create_table_format) == 0: return sql = self._create_table_format % (table_name) data = conn.execute(sql) conn.refresh_tables_info()如果数据表不存在,prepare_table类根据传入的模板名称在配置文件中读取创建表的SQL,然后执行。如果存在,则什么都不做。
这个功能非常必要。因为每天都有新股产生,我们不能每天手工去创建和该股票相关的表。于是自动检测并创建可以帮我们省去很多麻烦。
股票基本信息
目前我保存的股票基本信息只有股票代码、股票名称和所在市场。由于不定期有新股上市,所以这个信息每天早上要第一个更新。之后业务会根据该表获得所有股票代码,然后才能进行操作。[update_share_base_info]type=cronclass=update_stock_base_infoday_of_week=1-5hour=9minute=30second=10timezone = Asia/Shanghai上面配置意思是每周一到周五,9点30分10秒获取一次。
我们再看下创建表的模板(share_base.ttpl)
CREATE TABLE `%s` ( `share_id` char(6) COLLATE utf8_unicode_ci NOT NULL DEFAULT '000000' COMMENT '股票代码', `share_name` varchar(36) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '股票名称', `market_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '市场 1 沪市 2 深市', PRIMARY KEY (`share_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='股票基本信息';最后我们看下代码。
在构造函数中,我们指定所用到的数据库连接配置为stock_db,表模板是share_base,表名是share_base_info
class update_stock_base_info(job_base): def __init__(self): self._regular_split_manager = regular_split_manager() self._db_manager = mysql_manager() self._conn_name = "stock_db" self._prepare_table = prepare_table(self._conn_name, "share_base") self._table_name = "share_base_info"然后在run函数中检查或新建表,并完成数据抓取和写入
def run(self): data = self._get_data() self._prepare_table.prepare(self._table_name) self._save_data(data) LOG_INFO("run update_stock_base_info")数据我们从东方财富网抓取
def _get_data(self): url = r"http://nufm.dfcfw.com/EM_Finance2014NumericApplication/JS.aspx/JS.aspx?type=ct&st=(FFRank)&sr=1&p=1&ps=3500&js=var%20mozselQI={pages:(pc),data:[(x)]}&token=894050c76af8597a853f5b408b759f5d&cmd=C._AB&sty=DCFFITAM&rt=49461817" res = fetch_data.get_data(fetch_data.query_http(url)) return res然后通过正则表达式管理器,通过指定名称的策略,将结果分解出来
def _save_data(self, data): data_array = self._regular_split_manager.get_split_data(data, "string_comma_regular")然后枚举上面结果,将相应坐标数据和数据库中字段关联,最后写入表中
for item in data_array: share_market_type = item[0] share_id = item[1] share_name = item[2] if len(share_id) > 0 and len(share_name) > 0: share_info = {"share_id":share_id, "share_name":share_name, "market_type":share_market_type} conn = self._db_manager.get_mysql_conn(self._conn_name) conn.insert_onduplicate(self._table_name, share_info, ["share_id"])有了之前介绍的一系列管理器,我们便通过不到40行代码把数据抓取并入库。我们看下抓取结果
股票实时交易信息
股票实时交易信息是保存在一个叫做daily_temp的数据库中
class update_today_trade_info(job_base): def __init__(self): self._db_manager = mysql_manager() self._conn_name = "daily_temp" self._base_conn_name = "stock_db" self._prepare_table = prepare_table(self._conn_name, "today_trade_info") self._pre_share_count = 0 self._share_ids_str_list = []使用today_trade_info模板去准备数据库
CREATE TABLE `%s` ( `seq_id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '自增ID', `share_id` char(6) CHARACTER SET latin1 NOT NULL DEFAULT '000000', `share_name` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '股票名称', `today_open` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '今日开盘价', `yesterday_close` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '昨天收盘价', `cur` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '当前价格', `today_high` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '今日最高', `today_low` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '今日最低', `compete_buy_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '竞买价格(买一价格)', `compete_sale_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '竞卖价格(卖一价格)', `trade_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '成交的股票数', `trade_price` float(32,2) NOT NULL DEFAULT '0.00' COMMENT '成交的金额', `buy_1_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '买一数量', `buy_1_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '买一价格', `buy_2_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '买二数量', `buy_2_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '买二价格', `buy_3_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '买三数量', `buy_3_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '买三价格', `buy_4_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '买四数量', `buy_4_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '买四价格', `buy_5_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '买五数量', `buy_5_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '买五价格', `sale_1_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '卖一数量', `sale_1_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '卖一价格', `sale_2_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '卖二数量', `sale_2_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '卖二价格', `sale_3_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '卖三数量', `sale_3_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '卖三价格', `sale_4_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '卖四数量', `sale_4_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '卖四价格', `sale_5_num` bigint(64) NOT NULL DEFAULT '0' COMMENT '卖五数量', `sale_5_price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '卖五价格', `time_date_str` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '更新时间(日期)', `time_str` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '更新时间(时间)', `empty` int(16) NOT NULL DEFAULT '0' COMMENT '空占位', PRIMARY KEY (`seq_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='今日交易数据';因为我们要将一天的数据放在一个表中,也就是说每天一张表。于是表要使用日期加以区分
def run(self): date_info = time.strftime('%Y_%m_%d') table_name = "trade_info_%s" % (date_info) self._prepare_table.prepare(table_name)下一步是数据获取。
ids_str_list = self._get_all_share_ids() for ids_str in ids_str_list: data = self._get_data(ids_str) self._parse_data_and_insert_db(table_name, data) LOG_INFO("run update_today_trade_info")
这次我们通过新浪的接口获取数据。由于该接口不能支持一次性拉取三千多支股票信息,所以在拉取前,我需要对拉取的股票代码进行切片。这次我们要使用到股票基本信息表的数据来进行数据组装。
def _get_all_share_ids(self): db_manager = mysql_manager() conn = db_manager.get_mysql_conn(self._base_conn_name) count_info = conn.select("share_base_info", ["count(*)"],{}) count = int(count_info[0][0]) if count == self._pre_share_count: return self._share_ids_str_list #share_ids = conn.select("share_base_info", ["share_id", "market_type"],{"share_id":["601375", "="]}) share_ids = conn.select("share_base_info", ["share_id", "market_type"],{}) ids = [] for item in share_ids: market_type = item[1] pre = "" if 1 == market_type: pre = "sh" elif 2 == market_type: pre = "sz" else: continue new_id = pre + item[0] ids.append(new_id) id_count = len(ids) count_per = 500 page = id_count/count_per ids_str_list = [] for index in range(page+1): ids_list = ids[index*count_per:(index+1)*count_per] ids_str = "," . join(ids_list) ids_str_list.append(ids_str) self._share_ids_str_list = ids_str_list self._pre_share_count = count return self._share_ids_str_list为了尽量减少不同批次股票同步时间的差异,需要每次尽量请求多的数据。我是按500个一批进行切片的。
拉取数据的逻辑很简单,就是发起一次请求
def _get_data(self, ids): url_pre = "http://hq.sinajs.cn/list=" url = url_pre + ids res = fetch_data.get_data(fetch_data.query_http(url)) res = res.decode("gbk").encode("utf-8") return res最后我们将数据通过正则表达式管理器按照hq_sinajs_cn_list策略进行拆分。并通过指定相应位和数据库字段的关系,将其插入到表中
def _parse_data_and_insert_db(self, table_name, data): ret_array = fetch_data.get_data(fetch_data.regular_split("hq_sinajs_cn_list", data)) if 0 == len(ret_array): LOG_WARNING("hg_sinajs_cn_list regular %s empty data" %(data)) return data_array = [] into_db_columns = ["share_id","share_name","today_open","yesterday_close","cur","today_high","today_low","compete_buy_price","compete_sale_price", "trade_num","trade_price","buy_1_num","buy_1_price","buy_2_num","buy_2_price","buy_3_num","buy_3_price","buy_4_num","buy_4_price", "buy_5_num","buy_5_price","sale_1_num","sale_1_price","sale_2_num","sale_2_price","sale_3_num","sale_3_price","sale_4_num","sale_4_price", "sale_5_num","sale_5_price","time_date_str","time_str","empty"] columns_count = len(into_db_columns) for item in ret_array: if len(item) != columns_count: LOG_INFO("%s length is not match for column length %d" %(str(item), columns_count)) continue data_array.append(item) if 0 == len(data_array): return db_manager = mysql_manager() conn = db_manager.get_mysql_conn(self._conn_name) conn.insert_data(table_name ,into_db_columns, data_array)
股票主力动向信息
主力动向信息的获取和实时交易信息获取是类似的。我只列出区别部分。主力动向使用的是today_market_maker模板创建数据表
CREATE TABLE `%s` ( `seq_id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '自增ID', `market_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '1 沪市 2 深市', `share_id` char(6) CHARACTER SET latin1 NOT NULL DEFAULT '' COMMENT '股票代码', `share_name` varchar(36) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '股票名称', `price` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '股票价格', `up_percent` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '涨幅', `market_maker_net_inflow` float(64,2) NOT NULL DEFAULT '0.00' COMMENT '主力净流入', `market_maker_net_inflow_per` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '主力净流入占比', `huge_inflow` float(64,2) NOT NULL DEFAULT '0.00' COMMENT '超大单净流入', `huge_inflow_per` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '超大单净流入占比', `large_inflow` float(64,2) NOT NULL DEFAULT '0.00' COMMENT '大单净流入', `large_inflow_per` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '大单净流入占比', `medium_inflow` float(64,2) NOT NULL DEFAULT '0.00' COMMENT '中单净流入', `medium_inflow_per` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '中单净流入占比', `small_inflow` float(64,2) NOT NULL DEFAULT '0.00' COMMENT '小单净流入', `small_inflow_per` float(16,2) NOT NULL DEFAULT '0.00' COMMENT '小单净流入占比', `time_str` varchar(64) CHARACTER SET latin1 NOT NULL DEFAULT '' COMMENT '时间', PRIMARY KEY (`seq_id`)) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='主力行为统计';这次数据是从东方财富网抓取的。一个不错的消息是,该接口支持三千多支股票同时抓取,于是避免了之前要做切片的问题
def _get_data(self): date_info = time.strftime('%Y-%m-%d') url_fomart = "http://nufm.dfcfw.com/EM_Finance2014NumericApplication/JS.aspx/JS.aspx?type=ct&st=(BalFlowMain)&sr=-1&p=3&ps=%d&js=var%%20vDUaFOen={pages:(pc),date:%%22%s%%22,data:[(x)]}&token=894050c76af8597a853f5b408b759f5d&cmd=C._AB&sty=DCFFITA&rt=49430148" url = format(url_fomart % (3500, date_info)) res = fetch_data.get_data(fetch_data.query_http(url)) return res唯一不好的是部分没有的数据是使用-符号表示,这对我们正则分析提出了挑战。但是我们可以灵活处理,在正则拆分前将其替换成0
data = self._get_data() data = data.replace("-,", "0,") self._parse_data_and_insert_db(table_name, data) LOG_INFO("run update_today_market_maker_info")最后将拆分后的数据与表中字段关联,插入表中即可
def _parse_data_and_insert_db(self, table_name, data): data_array = fetch_data.get_data(fetch_data.regular_split("string_comma_regular", data)) db_manager = mysql_manager() conn = db_manager.get_mysql_conn(self._conn_name) into_db_columns = ["market_type", "share_id", "share_name", "price", "up_percent", "market_maker_net_inflow", "market_maker_net_inflow_per", "huge_inflow", "huge_inflow_per", "large_inflow", "large_inflow_per", "medium_inflow", "medium_inflow_per", "small_inflow", "small_inflow_per", "time_str"] conn.insert_data(table_name ,into_db_columns, data_array)
实时交易和主力动向数据都是30秒抓取一次,这儿只列出主力动向的任务配置。它分为上午和下午,由于存在整点问题,所以上午和下午的配置还是有点区别的
[update_today_market_maker_info_am_part1]type=cronclass=update_today_market_maker_infoday_of_week=1-5hour=9minute=30-59second = */30timezone = Asia/Shanghai[update_today_market_maker_info_am_part2]type=cronclass=update_today_market_maker_infoday_of_week=1-5hour=10second = */30timezone = Asia/Shanghai[update_today_market_maker_info_am_part3]type=cronclass=update_today_market_maker_infoday_of_week=1-5hour=11minute=0-30second = */30timezone = Asia/Shanghai
[update_today_market_maker_info_pm_1]type=cronclass=update_today_market_maker_infoday_of_week=1-5hour=13-14second = */30timezone = Asia/Shanghai[update_today_market_maker_info_pm_2]type=cronclass=update_today_market_maker_infoday_of_week=1-5hour=15minute=0second=30timezone = Asia/Shanghai
1 0
- 码农技术炒股之路——抓取股票基本信息、实时交易信息、主力动向信息
- 码农技术炒股之路——实时交易信息、主力动向信息分库备份
- 码农技术炒股之路——任务管理器
- 码农技术炒股之路——抓取日线数据、计算均线和除权数据
- 码农技术炒股之路——配置管理器、日志管理器
- 码农技术炒股之路——数据库管理器、正则表达式管理器
- 码农技术炒股之路——选股策略样例
- 抓取腾讯股票信息
- 抓取股票当日信息
- go爬虫:抓取股票实时股份信息发送到邮箱
- AJAX实例之股票实时信息显示
- 股票模拟交易软件之手机炒股软件排行榜
- Python之抓取股票信息,单继承,多继承,方法
- 新浪实时股票信息查询(JavaScript代码)
- 股票信息
- 世界信息技术发展重要动向
- Python机器学习2-股票信息简单抓取
- Ajax实时显示股票信息实例中的问题
- java UDP网络编程
- stack smashing datected.Aborted(core dumped)
- React Native Webview使用
- 如何使用SpannableString自定义文本样式
- 会用到的下载地址
- 码农技术炒股之路——抓取股票基本信息、实时交易信息、主力动向信息
- curl http get
- 顺时针打印矩阵
- Java UDP网络编程
- 穿越到未来的人工智能时代,生活是这样的...
- PAT 乙级 1052. 卖个萌 (20)
- 练习
- 配置Python 环境 eclipse for python +Pydev
- node里面连接mongodb查询返回一天的数据(根据时间段查询)