TuShare中源码分析(获取个股数据和基本面宏观数据)
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中我们可以查看新浪的宏观数据,如果需要,我们需要自己扩展。
本文地址:https://blog.csdn.net/weixin_41245990/article/details/108242485