碼農技術炒股之路——抓取股票基本資訊、實時交易資訊、主力動向資訊
從本節開始,我們開始介紹各個抓取和備份業務。(轉載請指明出於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=cron
class=update_stock_base_info
day_of_week=1-5
hour=9
minute=30
second=10
timezone = 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=cron
class=update_today_market_maker_info
day_of_week=1-5
hour=9
minute=30-59
second = */30
timezone = Asia/Shanghai
[update_today_market_maker_info_am_part2]
type=cron
class=update_today_market_maker_info
day_of_week=1-5
hour=10
second = */30
timezone = Asia/Shanghai
[update_today_market_maker_info_am_part3]
type=cron
class=update_today_market_maker_info
day_of_week=1-5
hour=11
minute=0-30
second = */30
timezone = Asia/Shanghai
[update_today_market_maker_info_pm_1]
type=cron
class=update_today_market_maker_info
day_of_week=1-5
hour=13-14
second = */30
timezone = Asia/Shanghai
[update_today_market_maker_info_pm_2]
type=cron
class=update_today_market_maker_info
day_of_week=1-5
hour=15
minute=0
second=30
timezone = Asia/Shanghai
相關文章
- Python爬蟲抓取股票資訊Python爬蟲
- DIY技術資訊抓取工具的實踐與研究
- 資訊摘要技術
- Python-抓取股票資訊-尹成-專題視訊課程Python
- 如何抓取網頁資訊?網頁
- 女性成移動應用消費主力——資訊圖
- 【Java】得到當前股票資訊Java
- 資訊熵(夏農熵)熵
- 資訊化中的AT技術
- 資訊挖掘 | 面向科技情報的網際網路資訊源自動發現技術
- Python實現拼多多商品資訊抓取方法Python
- 【炒股技術】股票追漲抓漲停的操作技巧
- 資訊化不唯技術論
- 資訊化技術討論組
- Scrapy框架抓取安居客房源資訊框架
- 夏農熵-互資訊-entropy熵
- Oracle基本資訊檢查Oracle
- 爬蟲app資訊抓取之apk反編譯抓取爬蟲APPAPK編譯
- 資訊抽取(UIE)技術:讓保險理賠資訊處理流程便捷高效UI
- 團隊技術資訊流建設
- 北京農商行創新應用量子技術提升都會網路資訊保安
- SwitchPay:企業移動技術的歷史–資訊圖
- Scrapy爬蟲:實習僧網最新招聘資訊抓取爬蟲
- 資訊加密技術加密
- 最全營銷技術全景圖–資訊圖
- 雲技術絕非不可見–資訊圖
- 三維動畫技術難在哪?——資訊圖動畫
- 美以簽署自動網路資訊共享協定攻擊資訊可“近實時”共享
- 【SCRIPT】Oracle資料庫基本資訊收集指令碼Oracle資料庫指令碼
- 使用python抓取58手機維修資訊Python
- 資訊系統/技術與計量系統/技術
- iResearch:Facebook的IPO之路–資訊圖
- Python爬取股票資訊,並實現視覺化資料Python視覺化
- 以資訊科技推動建築工程行業實現資訊化管理行業
- 爬蟲技術 -- 進階學習(十)網易新聞頁面資訊抓取(htmlagilitypack搭配scrapysharp)爬蟲HTML
- 如何獲取最新安全資訊與技術
- 資訊化 卡兩頭定中央走技術
- 交易資訊被篡改 錯誤碼:CONTEXT_INCONSISTENTContext