URL_SZSE = "http://bond.szse.cn/api/report/ShowReport/data"
HEADERS_SZSE = { "Accept": "application/json, text/javascript, */*; q=0.01", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "Content-Type": "application/json", "DNT": "1", "Host": "bond.szse.cn", "Referer": "http://bond.szse.cn/marketdata/statistics/report/struc/index.html", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36", "X-Request-Type": "ajax", "X-Requested-With": "XMLHttpRequest",}
PARAMS_SZSE = { "SHOWTYPE": "JSON", "CATALOGID": "zqxqjycyyb", "TABKEY": "tab1", "jyrqStart": "2023-01", "jyrqEnd": "2023-01", "random": 0.9926478152057119, }
MAPPING_SZSE = { "tzzlb": "投资者类别", "hjje": "合计金额", "hjzb": "合计占比", "gx": "国债", "dz": "地方政府债", "zj": "政策性金融债", "bj": "政府支持债券", "qx": "企业债券", "sz": "公司债券", "kz": "可转换债券", "hz": "可交换公司债券",
"sm": "非公开发行公司债券", "js": "非公开发行可交换公司债券", "bc": "创新创业可转换债券", "zc": "证券公司次级债券", "zd": "证券公司短期债券", "zr": "企业资产支持证券", "rt": "不动产投资信托"}
上交所现券交易月报网址:
http://bond.sse.com.cn/data/statistics/monthly/bond/
同样用chrome打开网页,并打开开发者工具(快捷键Ctrl+Shift+I),切换至Network界面。在网页中选择任一月份并点击查询,在开发者工具的Network界面寻找包含所需数据的链接、请求参数和数据格式。主要查看Headers、Payload和Preview三个界面,其中包含了获取数据的链接、请求参数和返回数据;从示例图片中,可在Headers界面找到现券交易月报数据的真实地址,发起请求的方法为Get,Payload页面明确获取数据的参数共5个,Preview页面显示数据格式为json,但多了一些字符前缀并不规整,需要先使用re模块进行处理,再使用json模块实现数据解析。
URL_SSE = "http://query.sse.com.cn/commonQuery.do"
HEADERS_SZSE = { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "DNT": "1", "Host": "query.sse.com.cn", "Referer": "http://bond.sse.com.cn", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36",}
PARAMS_SSE = { "jsonCallBack": "jsonpCallback91796", "isPagination": "false", "sqlId": "COMMON_BOND_SCSJ_SCTJ_TJYB_XQJYYB_L", "TRADEDATE": "2023-1", "_": 1676636559107, }
MAPPING_SSE = { "TYPE": "投资者类别", "TRADE_DATE": "报告期", "AMT": "合计金额", "AMT_PERCENT": "合计占比", "JZGZ_AMT": "记账式国债", "DFZ_AMT": "地方政府债券", "JRZ_AMT": "普通金融债", "QYZ_AMT": "企业债券", "SMZ_AMT": "中小企业私募债券",
"GKGSZ_AMT": "公司债券", "FGKGSZ_AMT": "非公开发行公司债券", "KZZ_AMT": "可转换公司债券", "FLZ_AMT": "分离交易的可转换公司债券", "QYZC_AMT": "企业资产支持证券", "XDZC_AMT": "信贷资产支持证券", "BXCJZ_AMT": "可交换公司债券", "OTHER_AMT": "其他债券",}
最新一期现券交易月报数据抓取
结合上述关键参数,利用requests模块即可实现现券交易月报数据的抓取,我们将抓取到的数据保存到指定的文件夹中,以便于后续案例中使用。
PATH_BASE = os.path.abspath("./")PATH_DATA = os.path.join(PATH_BASE, "Data")
if not os.path.exists(PATH_DATA): os.mkdir(PATH_DATA) report_date = datetime.date(2023, 1, 31)
深交所现券交易月报数据抓取
抓取深交所现券交易月报返回的json数据较为规整,主要的处理难点在于数据中包含有千分位符和空字符串。此外,Python默认字符编码为UTF-8格式,利用pandas将数据保存为csv格式时,若未修改字符编码为合适格式,使用Excel查看时可能出现中文乱码;可以通过指定字符编码为GB18030等格式避免这一问题。
PARAMS_SZSE.update({ "jyrqStart": report_date.strftime("%Y-%m"), "jyrqEnd": report_date.strftime("%Y-%m"), "random": np.random.random(), })
response_szse = requests.get( url=URL_SZSE, headers=HEADERS_SZSE, params=PARAMS_SZSE,)
if response_szse.status_code == 200: data_json_szse = json.loads(response_szse.text) data_szse = pd.DataFrame.from_dict(data_json_szse[0]["data"]) data_szse = data_szse.reindex(columns=MAPPING_SZSE.keys()) data_szse.rename(columns=MAPPING_SZSE, inplace=True) data_szse["报告期"] = report_date + pd.offsets.MonthEnd(0) data_szse.set_index(["投资者类别", "报告期"], inplace=True) data_szse = data_szse.applymap(lambda x: x.replace(',', '')).replace("", np.nan).astype(float) data_szse.to_csv(f"{PATH_DATA}/bond_trade_szse_{report_date.strftime('%Y%m%d')}.csv", encoding="GB18030")
上交所现券交易月报数据抓取
抓取上交所现券交易月报返回的json数据前后包含多余的字符串,也是主要的处理难点,可通过正则匹配去除多余字符串。与深交所现券交易月报数据的保存一样,保存为csv文件时,仍需要注意指定字符编码为GB18030等格式,以避免Excel查看时的中文乱码问题。
PARAMS_SSE.update({ "jsonCallBack": f"jsonpCallback{np.random.randint(10000, 99999)}", "TRADEDATE": f"{report_date.year}-{report_date.month}", "_": int(datetime.datetime.now().timestamp()*1000), })
response_sse = requests.get( url=URL_SSE, headers=HEADERS_SSE, params=PARAMS_SSE,)
if response_sse.status_code == 200: data_raw_sse = re.findall("^.+\((\{.+\})\)$", response_sse.text)[0] data_json_sse = json.loads(data_raw_sse) data_sse = pd.DataFrame.from_dict(data_json_sse["result"]) data_sse = data_sse.reindex(columns=MAPPING_SSE.keys()) data_sse.rename(columns=MAPPING_SSE, inplace=True) data_sse["报告期"] = report_date + pd.offsets.MonthEnd(0) data_sse.set_index(["投资者类别", "报告期"], inplace=True) data_sse = data_sse.astype(float) data_sse.to_csv(f"{PATH_DATA}/bond_trade_sse_{report_date.strftime('%Y%m%d')}.csv", encoding="GB18030")
历史月报数据抓取
上述代码已经实现了沪深交易所现券交易月报数据的单次抓取,若需要对历史上的月报数据进行抓取,可将上述代码分别封装为工具函数,将月报日期设定为函数参数,再对需要抓取的日期循环调用工具函数,即可完成历史月报数据的批量抓取。需要注意的重点,一方面避免重复抓取,另一方面注意通过sleep函数控制抓取速度。
report_dates = pd.date_range(datetime.date(2022, 1, 1), datetime.date(2023, 1, 31), freq="M")
pbar = tqdm(report_dates)for loop_date in pbar: pbar.set_description(loop_date.strftime("%Y-%m-%d")) if not os.path.exists(f"{PATH_DATA}/bond_trade_szse_{loop_date.strftime('%Y%m%d')}.csv"): pass if not os.path.exists(f"{PATH_DATA}/bond_trade_sse_{loop_date.strftime('%Y%m%d')}.csv"): pass sleep(1)
本次案例以抓取沪深交易所现券交易月报为例,主要展示了用Python实现网络数据抓取的简要流程,以及requests、re、datetime、pandas、numpy、tqdm的初步使用。若有错漏之处,还请各位批评指正。