TuShare中源码分析
今天,我们来分析下TuShare中的源码,TuShare源码的入口是__init__.py文件,我们从这个文件开始分析,找到获取个股历史交易记录并进行分析。
1、入口
# -*- coding:utf-8 -*-
import codecs
import os
__version__ = codecs.open(os.path.join(os.path.dirname(__file__), 'VERSION.txt')).read()
__author__ = 'Jimmy Liu'
上面的代码是TuShare的版本和作者
2、个股交易数据
"""
for trading data
"""
from tushare.stock.trading import (get_hist_data, get_tick_data,
get_today_all, get_realtime_quotes,
get_h_data, get_today_ticks,
get_index, get_hists,
get_k_data, get_day_all,
get_sina_dd, bar, tick,
get_markets, quotes,
get_instrument, reset_instrument)
上面代码说明TuShare的16个交易数据API是从stock下的trading模块打包出来的。
我们打开源码stock目录下的trading.py文件,先分析trading.py的依赖项
from __future__ import division
import time
import json
import lxml.html
from lxml import etree
import pandas as pd
import numpy as np
import datetime
from tushare.stock import cons as ct # 引入cons.py,包含股票相关常量定义
import re
from pandas.compat import StringIO
from tushare.util import dateu as du # 引入dateu.py,日期、交易日历的处理
from tushare.util.formula import MA # 引入formula.py,包含股票常用指标
import os
from tushare.util.conns import get_apis, close_apis # 引入conns.py,连接爬取外部数据的API
from tushare.stock.fundamental import get_stock_basics # 引入fundamental.py,包含基本面数据接口
try:
from urllib.request import urlopen, Request
except ImportError:
from urllib2 import urlopen, Request
我们可以看出,引入了5个模块:cons.py包含股票相关常量定义,dateu.py包含对日期、交易日历的处理,formula.py包含股票常用指标,conns.py包含连接爬取外部数据的API,fundamental.py包含基本面数据接口 。
2.1、API:获取凤凰财经个股历史交易记录
def get_hist_data(code=None, start=None, end=None,
ktype='D', retry_count=3,
pause=0.001):
代码中有获取个股历史交易记录API的详细说明:
"""
获取个股历史交易记录
Parameters
------
code:string
股票代码 e.g. 600848
start:string
开始日期 format:YYYY-MM-DD 为空时取到API所提供的最早日期数据
end:string
结束日期 format:YYYY-MM-DD 为空时取到最近一个交易日数据
ktype:string
数据类型,D=日k线 W=周 M=月 5=5分钟 15=15分钟 30=30分钟 60=60分钟,默认为D
retry_count : int, 默认 3
如遇网络等问题重复执行的次数
pause : int, 默认 0
重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
return
-------
DataFrame
属性:日期 ,开盘价, 最高价, 收盘价, 最低价, 成交量, 价格变动 ,涨跌幅,5日均价,10日均价,20日均价,5日均量,10日均量,20日均量,换手率
"""
参数 | 缺省值 | 说明 |
---|---|---|
ktype | ‘D’ | 表示数据类型缺省是日线 |
retry_count | 3 | 表示爬取外部数据请求时最多尝试3次 |
pause | 0.001 | 表示多次尝试爬取请求过程中暂停0.001秒 |
symbol = ct._code_to_symbol(code)
我们在cons.py中找到_code_to_symbol
def _code_to_symbol(code):
'''
生成symbol代码标志
'''
if code in INDEX_LABELS:
return INDEX_LIST[code]
elif code[:3] == 'gb_':
return code
else:
if len(code) != 6 : # 如果输入的不是一个6位数的股票代码
return code # 直接返回代码
else:
return 'sh%s'%code if code[:1] in ['5', '6', '9'] or code[:2] in ['11', '13'] else 'sz%s'%code
# 输入的是一个6位数的股票代码,代码前1位是5、6、9,或者前2位是11、13,是上证股票代码,
# 否则是深证股票代码,返回带市场的股票代码
_code_to_symbol主要是对输入的股票代码进行判断,然后格式化成股票代码的标准格式,例如:sh600000
代码 | cons.py中对应内容 | 说明 |
---|---|---|
return INDEX_LIST[code] | INDEX_LABELS = [‘sh’, ‘sz’, ‘hs300’, ‘sz50’, ‘cyb’, ‘zxb’, ‘zx300’, ‘zh500’] \n INDEX_LIST = {‘sh’: ‘sh000001’, ‘sz’: ‘sz399001’, ‘hs300’: ‘sh000300’,‘sz50’: ‘sh000016’, ‘zxb’: ‘sz399005’, ‘cyb’: ‘sz399006’, ‘zx300’: ‘sz399008’, ‘zh500’:‘sh000905’} | 根据缩写指标代码返回指标对应的完整指标代码 |
url = ''
if ktype.upper() in ct.K_LABELS:
url = ct.DAY_PRICE_URL%(ct.P_TYPE['http'], ct.DOMAINS['ifeng'],
ct.K_TYPE[ktype.upper()], symbol)
# 拼装日线对应凤凰网数据请求API的url
代码 | cons.py中对应内容 | 说明 |
---|---|---|
ct.K_LABELS | K_LABELS = [‘D’, ‘W’, ‘M’] | 数据类型,D:日线,W:周线,M:月线 |
ct.DAY_PRICE_URL | DAY_PRICE_URL = ‘%sapi.finance.%s/%s/?code=%s&type=last’ | 凤凰网获取日线的URL |
ct.P_TYPE[‘http’]- | P_TYPE = {‘http’: ‘http://’, ‘ftp’: ‘ftp://’}- | http请求类型 |
ct.DOMAINS[‘ifeng’]- | ‘ifeng’: ‘ifeng.com’- | 数据来源凤凰 |
ct.K_TYPE | K_TYPE = {‘D’: ‘akdaily’, ‘W’: ‘akweekly’, ‘M’: ‘akmonthly’} | 数据类型和凤凰网对应的数据类型,D:日线,W:周线,M:月线 |
elif ktype in ct.K_MIN_LABELS:
url = ct.DAY_PRICE_MIN_URL%(ct.P_TYPE['http'], ct.DOMAINS['ifeng'],
symbol, ktype)
# 拼装分钟线对应凤凰网数据请求API的url
else:
raise TypeError('ktype input error.')
代码 | cons.py中对应内容 | 说明 |
---|---|---|
ct.K_MIN_LABELS | K_MIN_LABELS = [‘5’, ‘15’, ‘30’, ‘60’] | 分钟线:5分钟线、15分钟线、30分钟线、小时线 |
ct.DAY_PRICE_MIN_URL | DAY_PRICE_MIN_URL = ‘%sapi.finance.%s/akmin?scode=%s&type=%s’ | 凤凰网获取分钟线的URL |
ct.P_TYPE[‘http’]- | P_TYPE = {‘http’: ‘http://’, ‘ftp’: ‘ftp://’}- | http请求类型 |
ct.DOMAINS[‘ifeng’]- | ‘ifeng’: ‘ifeng.com’- | 数据来源凤凰财经 |
ct.K_TYPE | K_TYPE = {‘D’: ‘akdaily’, ‘W’: ‘akweekly’, ‘M’: ‘akmonthly’} | 数据类型,D:日线,W:周线,M:月线 |
我们在这里给出两上请求凤凰网数据的示例,
a、请求上海证券交易所600000浦发银行的日线数据对应的URL:
http://api.finance.ifeng.com/akdaily/?code=sh600000&type=last
b、请求上海证券交易所600000浦发银行的周线数据对应的URL:
http://api.finance.ifeng.com/akweekly/?code=sh600000&type=last
c、请求一个不个不存在的股票数据,返回空数据
http://api.finance.ifeng.com/akdaily/?code=sh69999&type=last
返回内容为13个字节的空记录内容
{"record":{}}
在这里,我们展开说一下,我们可以通过凤凰财经的页面来分析爬取数据的URL,我们以浦发银行sh600000为例,打开浦发银行的行情页面:
http://finance.ifeng.com/app/hq/stock/sh600000/
按F12打开开发者工具,切换到Network页面,在行情页面点击日k、周k、月k、15分、30分等进行数据类型切换,在Network页面查看请求的变化,分析对应的请求,我们就可以找到数据请求的API。
for _ in range(retry_count): # 尝试爬取retry_count次
time.sleep(pause) # 休眠pause秒
try:
request = Request(url) # 请求打开URL页面
lines = urlopen(request, timeout = 10).read() # 保存返回页面内容到lines中
if len(lines) < 15: # 根据返回内容的长度来判断是否有数据,空数据返回{"record":{}}
return None
except Exception as e:
print(e) # 如果出现异常,打印异常信息
else:
凤凰财经返回的数据是JSON格式,下面代码是对爬取数据的处理
js = json.loads(lines.decode('utf-8') if ct.PY3 else lines)
cols = []
if (code in ct.INDEX_LABELS) & (ktype.upper() in ct.K_LABELS):
cols = ct.INX_DAY_PRICE_COLUMNS
else:
cols = ct.DAY_PRICE_COLUMNS
if len(js['record'][0]) == 14: # 如果第列是14个元素,代表是指标数据
cols = ct.INX_DAY_PRICE_COLUMNS
# 根据行记录数据创建DataFrame对象
df = pd.DataFrame(js['record'], columns=cols)
if ktype.upper() in ['D', 'W', 'M']:
df = df.applymap(lambda x: x.replace(u',', u''))
df[df==''] = 0
for col in cols[1:]:
df[col] = df[col].astype(float) # 进行类型转换
if start is not None:
df = df[df.date >= start] # 保留开始时间之后的数据
if end is not None:
df = df[df.date <= end] # 保留结束时间之前的数据
if (code in ct.INDEX_LABELS) & (ktype in ct.K_MIN_LABELS):
df = df.drop('turnover', axis=1)
df = df.set_index('date') # 按date字段设置索引
df = df.sort_index(ascending = False) # 按索引进行排序
return df
raise IOError(ct.NETWORK_URL_ERROR_MSG)
代码 | cons.py中对应内容 | 说明 |
---|---|---|
ct.INDEX_LABELS | INDEX_LABELS = [‘sh’, ‘sz’, ‘hs300’, ‘sz50’, ‘cyb’, ‘zxb’, ‘zx300’, ‘zh500’] | 凤凰财经对应的指数代码 |
ct.INX_DAY_PRICE_COLUMNS | INX_DAY_PRICE_COLUMNS = [‘date’, ‘open’, ‘high’, ‘close’, ‘low’, ‘volume’, ‘price_change’, ‘p_change’,‘ma5’, ‘ma10’, ‘ma20’, ‘v_ma5’, ‘v_ma10’, ‘v_ma20’] | 指标日线数据每列的元素 |
ct.DAY_PRICE_COLUMNS | DAY_PRICE_COLUMNS = [‘date’, ‘open’, ‘high’, ‘close’, ‘low’, ‘volume’, ‘price_change’, ‘p_change’,‘ma5’, ‘ma10’, ‘ma20’, ‘v_ma5’, ‘v_ma10’, ‘v_ma20’, ‘turnover’] | 股票日线数据每列的元素 |
2.2、API:获取分笔数据
def get_tick_data(code=None, date=None, retry_count=3, pause=0.001,
src='sn'):
代码中有获取分笔数据API的详细说明:
"""
获取分笔数据
Parameters
------
code:string
股票代码 e.g. 600848
date:string
日期 format: YYYY-MM-DD
retry_count : int, 默认 3
如遇网络等问题重复执行的次数
pause : int, 默认 0
重复请求数据过程中暂停的秒数,防止请求间隔时间太短出现的问题
src : 数据源选择,可输入sn(新浪)、tt(腾讯)、nt(网易),默认sn
return
-------
DataFrame 当日所有股票交易数据(DataFrame)
属性:成交时间、成交价格、价格变动,成交手、成交金额(元),买卖类型
"""
参数 | 缺省值 | 说明 |
---|---|---|
retry_count | 3 | 表示爬取外部数据请求时最多尝试3次 |
pause | 0.001 | 表示多次尝试爬取请求过程中暂停0.001秒 |
src | ‘sn’ | 表示数据源选择新浪 |
if (src.strip() not in ct.TICK_SRCS):
print(ct.TICK_SRC_ERROR)
return None # 非法数据源,返回None
symbol = ct._code_to_symbol(code) # 根据code获取symbol代码
symbol_dgt = ct._code_to_symbol_dgt(code) # 根据code获取symbol_dgt代码
datestr = date.replace('-', '') # 日期YYYY-MM-DD格式调整至YYYYMMDD格式
代码 | cons.py中对应内容 | 说明 |
---|---|---|
ct.TICK_SRCS | TICK_SRCS = [‘sn’, ‘tt’, ‘nt’] | 分笔数据源,sn(新浪)、tt(腾讯)、nt(网易) |
ct.INX_DAY_PRICE_COLUMNS | INX_DAY_PRICE_COLUMNS = [‘date’, ‘open’, ‘high’, ‘close’, ‘low’, ‘volume’, ‘price_change’, ‘p_change’,‘ma5’, ‘ma10’, ‘ma20’, ‘v_ma5’, ‘v_ma10’, ‘v_ma20’] | 指标日线数据每列的元素 |
ct.DAY_PRICE_COLUMNS | DAY_PRICE_COLUMNS = [‘date’, ‘open’, ‘high’, ‘close’, ‘low’, ‘volume’, ‘price_change’, ‘p_change’,‘ma5’, ‘ma10’, ‘ma20’, ‘v_ma5’, ‘v_ma10’, ‘v_ma20’, ‘turnover’] | 股票日线数据每列的元素 |
url = {
ct.TICK_SRCS[0] : ct.TICK_PRICE_URL % (ct.P_TYPE['http'], ct.DOMAINS['sf'], ct.PAGES['dl'],
date, symbol),
ct.TICK_SRCS[1] : ct.TICK_PRICE_URL_TT % (ct.P_TYPE['http'], ct.DOMAINS['tt'], ct.PAGES['idx'],
symbol, datestr),
ct.TICK_SRCS[2] : ct.TICK_PRICE_URL_NT % (ct.P_TYPE['http'], ct.DOMAINS['163'], date[0:4],
datestr, symbol_dgt)
}
# 拼装分笔数据请求的URL
代码 | cons.py中对应内容 | 说明 |
---|---|---|
ct.TICK_PRICE_URL | TICK_PRICE_URL = ‘%smarket.%s/%s?date=%s&symbol=%s’ | 新浪分笔数据请求 |
ct.DOMAINS[‘sf’] | ‘sf’: ‘finance.sina.com.cn’ | 数据来源新浪 |
ct.PAGES[‘dl’] | ‘dl’: ‘downxls.php’ | 数据来源页面 |
ct.TICK_PRICE_URL_TT | TICK_PRICE_URL_TT = ‘%sstock.%s/data/%s?appn=detail&action=download&c=%s&d=%s’ | 腾讯分笔数据请求 |
ct.DOMAINS[‘tt’] | ‘tt’: ‘gtimg.cn’ | 数据来源腾讯 |
ct.PAGES[‘idx’] | ‘idx’: ‘index.php’ | 数据来源页面 |
ct.TICK_PRICE_URL_NT | TICK_PRICE_URL_NT = ‘%squotes.%s/cjmx/%s/%s/%s.xls’ | 网易分笔数据请求 |
ct.DOMAINS[‘163’] | ‘163’: ‘money.163.com’ | 数据来源网易 |
新浪分笔数据请求示例:
http://market.finance.sina.com.cn/downxls.php?date=20200826&symbol=sh600000
服务已经下线,可惜。
腾讯分笔数据请求示例:
http://stock.gtimg.cn/data/index.php?appn=detail&action=download&c=sh600000&d=20200826
请求的Excel数据如下:
网易分笔数据请求示例:
http://quotes.money.163.com/cjmx/2020/20200826/0600000.xls
说明:
http://quotes.money.163.com/cjmx/[今年年份]/[日期]/[股票代码].xls
返回结果:获取历史成交明细XLS文件。
注意,只能获取5日内的数据,之前的数据不会存在。
注意,该方法为网易公开获取数据方法,推荐使用。
下面代码是对爬取数据的处理
for _ in range(retry_count): # 尝试爬取retry_count次
time.sleep(pause) # 休眠pause秒
try:
if src == ct.TICK_SRCS[2]:
df = pd.read_excel(url[src]) # 操作读取excel文件
df.columns = ct.TICK_COLUMNS
else:
re = Request(url[src]) # 请求打开URL页面
lines = urlopen(re, timeout=10).read() # 保存返回页面内容到lines中
lines = lines.decode('GBK')
if len(lines) < 20:
return None
df = pd.read_table(StringIO(lines), names=ct.TICK_COLUMNS,
skiprows=[0])
except Exception as e:
print(e)
else:
return df
raise IOError(ct.NETWORK_URL_ERROR_MSG)
3、基本面数据
"""
for trading data
"""
from tushare.stock.fundamental import (get_stock_basics, get_report_data,
get_profit_data,
get_operation_data, get_growth_data,
get_debtpaying_data, get_cashflow_data,
get_balance_sheet, get_profit_statement, get_cash_flow)
上面代码说明TuShare的10个基本面数据API是从stock下的fundamental模块打包出来的。
我们打开源码stock目录下的fundamental.py文件,先分析fundamental.py的依赖项
import pandas as pd
from tushare.stock import cons as ct # 引入cons.py,包含股票相关常量定义
import lxml.html
from lxml import etree
import re
import time
from pandas.compat import StringIO
from tushare.util import dateu as du # 引入dateu.py,日期、交易日历的处理
try:
from urllib.request import urlopen, Request
except ImportError:
from urllib2 import urlopen, Request
3.1、API:获取沪深上市公司基本情况
def get_stock_basics(date=None):
代码中有获取获取沪深上市公司基本情况API的详细说明:
"""
获取沪深上市公司基本情况
Parameters
date:日期YYYY-MM-DD,默认为上一个交易日,目前只能提供2016-08-09之后的历史数据
Return
--------
DataFrame
code,代码
name,名称
industry,细分行业
area,地区
pe,市盈率
outstanding,流通股本
totals,总股本(万)
totalAssets,总资产(万)
liquidAssets,流动资产
fixedAssets,固定资产
reserved,公积金
reservedPerShare,每股公积金
eps,每股收益
bvps,每股净资
pb,市净率
timeToMarket,上市日期
"""
wdate = du.last_tddate() if date is None else date # 获取最后一个交易日
wdate = wdate.replace('-', '') # 日期YYYY-MM-DD格式调整至YYYYMMDD格式
if wdate < '20160809':
return None // 2016年8月9日之前没有数据
# 获取日期前缀,格式如:'201608/'
datepre = '' if date is None else wdate[0:4] + wdate[4:6] + '/'
# 拼接URL并Request
request = Request(ct.ALL_STOCK_BASICS_FILE%(datepre, '' if date is None else wdate))
text = urlopen(request, timeout=10).read() # 保存返回的内容到text中
text = text.decode('GBK')
text = text.replace('--', '')
df = pd.read_csv(StringIO(text), dtype={'code':'object'}) # 读取vsv文件
df = df.set_index('code') # 设置code字段为索引
return df
我们在dateu.py中找到last_tddate,这个函数用于获取最后一个交易日
def last_tddate():
today = datetime.datetime.today().date() # 获取当天的日期
today=int(today.strftime("%w")) # %w 星期(0-6),获取当天是星期几
if today == 0:
return day_last_week(-2) # 周日,返回上这个星期的两一天的日期(周五)
else:
return day_last_week(-1) # 非周日,返回上这个星期的上一天的日期
我们在dateu.py中找到day_last_week,这个函数用于获取最后一个星期第几天的日期
def day_last_week(days=-7):
lasty = datetime.datetime.today().date() + datetime.timedelta(days)
return str(lasty)
代码 | cons.py中对应内容 | 说明 |
---|---|---|
ct.ALL_STOCK_BASICS_FILE | ALL_STOCK_BASICS_FILE = P_TYPE[‘http’] + DOMAINS[‘oss’] + ‘/tsdata/%sall%s.csv’ | Tushare财经数据包拼接URL格式 |
DOMAINS[‘oss’] | ‘oss’: ‘file.tushare.org’ | Tushare财经数据包 |
示例,获取2020年8月26日的沪深上市公司基本情况:
http://file.tushare.org/tsdata/202008/all20200826.csv
返回csv结果文件如下:
3.2、API:获取业绩报表数据
我们打开源码stock目录下的fundamental.py文件,找到获取业绩报表数据API函数get_report_data
def get_report_data(year, quarter):
代码中有获取业绩报表数据API的详细说明:
"""
获取业绩报表数据
Parameters
--------
year:int 年度 e.g:2014
quarter:int 季度 :1、2、3、4,只能输入这4个季度
说明:由于是从网站获取的数据,需要一页页抓取,速度取决于您当前网络速度
Return
--------
DataFrame
code,代码
name,名称
eps,每股收益
eps_yoy,每股收益同比(%)
bvps,每股净资产
roe,净资产收益率(%)
epcf,每股现金流量(元)
net_profits,净利润(万元)
profits_yoy,净利润同比(%)
distrib,分配方案
report_date,发布日期
"""
if ct._check_input(year,quarter) is True: # 检查输入的年度、季度是否准确
ct._write_head()
df = _get_report_data(year, quarter, 1, pd.DataFrame())
if df is not None:
# df = df.drop_duplicates('code')
df['code'] = df['code'].map(lambda x:str(x).zfill(6))
return df
我们在cons.py中找到_check_input,这个函数用于校验输入的年度、季度
def _check_input(year, quarter):
if isinstance(year, str) or year < 1989 :
# 年度不是字符串或年小于1989,抛出类型错误异常
# DATE_CHK_MSG = '年度输入错误:请输入1989年以后的年份数字,格式:YYYY'
raise TypeError(DATE_CHK_MSG)
elif quarter is None or isinstance(quarter, str) or quarter not in [1, 2, 3, 4]:
# 季度不是字符串或不是1、2、3、4,抛出类型错误异常
# DATE_CHK_Q_MSG = '季度输入错误:请输入1、2、3或4数字'
raise TypeError(DATE_CHK_Q_MSG)
else:
return True
我们在cons.py中找到_write_head,这个函数用于写头部标识
def _write_head():
sys.stdout.write(DATA_GETTING_TIPS) # DATA_GETTING_TIPS = '[Getting data:]'
sys.stdout.flush()
我们在fundamental.py中找到_get_report_data,这个函数用于获取业绩报表数据
def _get_report_data(year, quarter, pageNo, dataArr,
retry_count=3, pause=0.001):
参数 | 说明 |
---|---|
year | 年度 |
quarter | 季度 |
pageNo | 分页编码,编号从1开始 |
retry_count | 爬取数据重连次数 |
pause | 爬取数据重连时睡眠秒数 |
ct._write_console()
for _ in range(retry_count):
time.sleep(pause)
try:
# 拼接获取业绩报表数据URL并Request
request = Request(ct.REPORT_URL%(ct.P_TYPE['http'], ct.DOMAINS['vsf'], ct.PAGES['fd'],
year, quarter, pageNo, ct.PAGE_NUM[1]))
text = urlopen(request, timeout=10).read() # 保存业绩报表数据
text = text.decode('GBK')
text = text.replace('--', '') # 清除<td>--</td>格式数据
html = lxml.html.parse(StringIO(text))
# 解析<table class="list_table" id="dataTable">中的数据内容
res = html.xpath("//table[@class=\"list_table\"]/tr")
if ct.PY3:
sarr = [etree.tostring(node).decode('utf-8') for node in res]
else:
sarr = [etree.tostring(node) for node in res]
sarr = ''.join(sarr)
sarr = '<table>%s</table>'%sarr # 把list_table中的数据再拼接成一个table
# 通过read_html直接获取表格数据,得到table表格的list集合。
df = pd.read_html(sarr)[0]
df = df.drop(11, axis=1)
df.columns = ct.REPORT_COLS
# 把表格数据保存到DataFrame对象dataArr中
dataArr = dataArr.append(df, ignore_index=True)
nextPage = html.xpath('//div[@class=\"pages\"]/a[last()]/@onclick')
if len(nextPage)>0:
pageNo = re.findall(r'\d+', nextPage[0])[0] # 通过正则查找下一页的页码
# 继续获取下一页的业绩报表数据
return _get_report_data(year, quarter, pageNo, dataArr)
else:
return dataArr
except Exception as e:
pass
raise IOError(ct.NETWORK_URL_ERROR_MSG)
代码 | cons.py中对应内容 | 说明 |
---|---|---|
ct.PORT_URL | REPORT_URL = ‘%s%s/q/go.php/vFinanceAnalyze/kind/mainindex/%s?s_i=&s_a=&s_c=&reportdate=%s&quarter=%s&p=%s&num=%s’ | 新浪业绩报表URL格式 |
ct.DOMAINS[‘vsf’] | ‘vsf’: ‘vip.stock.finance.sina.com.cn’ | 新浪财经股票数据中心 |
ct.PAGE_NUM[1] | PAGE_NUM = [40, 60, 80, 100] | 第页包含的数据记录条数 |
示例,获取2020年1季度的业绩报表数据:
http://vip.stock.finance.sina.com.cn/q/go.php/vFinanceAnalyze/kind/mainindex/2020?s_i=&s_a=&s_c=&reportdate=%s&quarter=1&p=1&num=40
返回结果页面如下:
我们查看页面源代码,业绩报表数据都在table中
4、宏观数据
for macro data
"""
from tushare.stock.macro import (get_gdp_year, get_gdp_quarter,
get_gdp_for, get_gdp_pull,
get_gdp_contrib, get_cpi,
get_ppi, get_deposit_rate,
get_loan_rate, get_rrr,
get_money_supply, get_money_supply_bal,
get_gold_and_foreign_reserves)
上面代码说明TuShare的13个宏观数据API是从stock下的macro模块打包出来的。
我们打开源码stock目录下的macro.py文件,先分析macro.py的依赖项
import pandas as pd
import numpy as np
import re
import json
from tushare.stock import macro_vars as vs # 引入macro_vars.py,包含宏观数据相关常量定义
from tushare.stock import cons as ct # 引入cons.py,包含股票相关常量定义
try:
from urllib.request import urlopen, Request
except ImportError:
from urllib2 import urlopen, Request
4.1、API:获取年度国内生产总值数据
def get_gdp_year():
代码中有获取年度国内生产总值数据API的详细说明:
"""
获取年度国内生产总值数据
Return
--------
DataFrame
year :统计年度
gdp :国内生产总值(亿元)
pc_gdp :人均国内生产总值(元)
gnp :国民生产总值(亿元)
pi :第一产业(亿元)
si :第二产业(亿元)
industry :工业(亿元)
cons_industry :建筑业(亿元)
ti :第三产业(亿元)
trans_industry :交通运输仓储邮电通信业(亿元)
lbdy :批发零售贸易及餐饮业(亿元)
"""
rdint = vs.random()
# 拼接获取年度国内生产总值数据的URL
request = Request(vs.MACRO_URL%(vs.P_TYPE['http'], vs.DOMAINS['sina'],
rdint, vs.MACRO_TYPE[0], 0, 70,
rdint))
text = urlopen(request, timeout=10).read()
text = text.decode('gbk') if ct.PY3 else text
regSym = re.compile(r'\,count:(.*?)\}')
datastr = regSym.findall(text)
datastr = datastr[0]
datastr = datastr.split('data:')[1]
datastr = datastr.replace('"', '').replace('null', '0')
js = json.loads(datastr)
df = pd.DataFrame(js, columns=vs.GDP_YEAR_COLS)
df[df==0] = np.NaN
return df
代码 | cons.py中对应内容 | 说明 |
---|---|---|
vs.MACRO_URL | MACRO_URL = ‘%smoney.finance.%s/mac/api/jsonp.php/SINAREMOTECALLCALLBACK%s/MacPage_Service.get_pagedata?cate=%s&event=%s&from=0&num=%s&condition=&_=%s’ | 新浪获取年度国内生产总值数据URL格式 |
ct.DOMAINS[‘sina’] | ‘sina’: ‘sina.com.cn’ | 新浪财经股票数据中心 |
vs.MACRO_TYPE[0] | MACRO_TYPE = [‘nation’,‘price’,‘fininfo’] |
示例,获取年度国内生产总值数据:
http://money.finance.sina.com.cn/mac/api/jsonp.php/SINAREMOTECALLCALLBACK5564253726144/MacPage_Service.get_pagedata?cate=nation&event=0&from=0&num=70&condition=&_=5564253726144
这个地址无法正常获取,代码还需要完善。
在http://finance.sina.com.cn/mac/#nation-0-0-31-1中我们可以查看新浪的宏观数据,如果需要,我们需要自己扩展。