手把手教你学python基础课系列快速回顾:
1、“零基础包学会” 手把手教你学python一:如何快速找到学习资源?
2、手把手教你学python第二课:如何迅速上手马上能run
3、手把手教你学python第三课:数据分析,学会使用pandas大杀器
5、手把手教你学python第五课:各种渠道获取数据,快速学会windpy和网络爬虫
6、手把手教你学python第六课:技术分析入门-talib
手把手教你学python第六课:技术分析入门-talib-成交量及曲线形态
手把手教你学python第六课:技术分析入门-talib-安装及动量指标
手把手教你学python进阶系列快速回顾:
2023
手把手教你学python系列进阶版
写在最初
在新的一年与尔岩说将继续之前的手把手教你学python专栏(停更的原因一部分是因为大家说之前的需要时间消化,所以停了一段时间,另一部分原因是想邀请比我更专业而且实用性更强的王者们来上进阶课程),主笔加入了我的两个非常好的两个朋友(笔名十月和木矛木心),下面是十月写在最初的话:
这里会定期更新一些实际案例和具体用法,如果你和我一样热爱用科技提高工作效率,并想要一起研究一些有意思的事情,欢迎一起来进阶!!
蓬蓬说:爬虫基础部分也讲解过,大家可以先做一下复习
首先,我们在VSCode中新建一个jupyter notebook。并导入本案例中需要用到的模块。
# 导入数据抓取需要使用的Python模块
import requests
import re
import datetime
import pandas as pd
import numpy as np
import os
# 用于显示循环进度条
from tqdm import tqdm
# 用于批量抓取过程中控制抓取速度
from time import sleep
# 用于解析字符串格式的json数据
import json
寻找现券交易数据的真实地址
深交所现券交易月报关键参数
深交所现券交易月报网址:
http://bond.szse.cn/marketdata/statistics/report/trade/index.html
用chrome打开该网页,并打开开发者工具(快捷键Ctrl+Shift+I),切换至Network界面。在网页中选择任一月份并点击查询,在开发者工具的Network界面寻找包含所需数据的链接、请求参数和数据格式。主要查看Headers、Payload和Preview三个界面,其中包含了获取数据的链接、请求参数和返回数据;从示例图片中,可在Headers界面找到现券交易月报数据的真实地址,发起请求的方法为Get,Payload页面明确获取数据的参数共6个,Preview页面则显示数据格式为规整的json格式,即可以直接使用json模块实现数据解析。
# 将上述关键信息设为Python变量
# 获取深交所现券交易月报数据的真实链接
URL_SZSE = "http://bond.szse.cn/api/report/ShowReport/data"
# 获取深交所现券交易月报数据的Headers
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模块实现数据解析。
# 将上述关键信息设为Python变量
# 获取上交所现券交易月报数据的真实链接
URL_SSE = "http://query.sse.com.cn/commonQuery.do"
# 获取上交所现券交易月报数据的Headers
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", # 5位尾数为随机数,抓取时需更新
"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模块即可实现现券交易月报数据的抓取,我们将抓取到的数据保存到指定的文件夹中,以便于后续案例中使用。
# 利用os模块,在Notebook的相同目录下新建Data文件夹,用于存放数据
PATH_BASE = os.path.abspath("./")
PATH_DATA = os.path.join(PATH_BASE, "Data")
# 判断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"),
# 利用numpy.random模块生成随机数
"random": np.random.random(),
})
# 利用requests获取深交所现券交易数据
response_szse = requests.get(
url=URL_SZSE,
headers=HEADERS_SZSE,
params=PARAMS_SZSE,
)
# 根据requests返回值的状态码,判断是否成功获取数据
if response_szse.status_code == 200:
# 利用json模块解析月报数据
data_json_szse = json.loads(response_szse.text)
# 利用pandas整理json数据
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)
# 利用pandas.offsets模块,将报告期设定为当月月末
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)
# 将数据以CSV格式保存到Data文件夹中
# Python默认字符编码为UTF-8格式,若直接保存为CSV,EXCEL打开时中文可能乱码
# 保存时将字符编码修改为GB18030格式
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({
# 采用f-string的形式进行字符串拼接
# 利用numpy.random模块生成随机数
"jsonCallBack": f"jsonpCallback{np.random.randint(10000, 99999)}",
# 采用f-string的形式进行字符串拼接
"TRADEDATE": f"{report_date.year}-{report_date.month}",
# 利用datetime模块获取当前时间戳,并乘以1000转换为JavaScript中的时间戳
"_": int(datetime.datetime.now().timestamp()*1000),
})
# 利用requests获取上交所现券交易数据
response_sse = requests.get(
url=URL_SSE,
headers=HEADERS_SSE,
params=PARAMS_SSE,
)
# 根据requests返回值的状态码,判断是否成功获取数据
if response_sse.status_code == 200:
# 利用正则表达式去除json数据中多余的字符串
data_raw_sse = re.findall("^.+\((\{.+\})\)$", response_sse.text)[0]
data_json_sse = json.loads(data_raw_sse)
# 利用pandas整理json数据
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)
# 利用pandas.offsets模块,将报告期设定为当月月末
data_sse["报告期"] = report_date + pd.offsets.MonthEnd(0)
# 将投资者类别和报告期设定为索引
data_sse.set_index(["投资者类别", "报告期"], inplace=True)
# 强制转换数据类型为浮点数
data_sse = data_sse.astype(float)
# 将数据以CSV格式保存到Data文件夹中
# Python默认字符编码为UTF-8格式,若直接保存为CSV,EXCEL打开时中文可能乱码
# 保存时将字符编码修改为GB18030格式
data_sse.to_csv(f"{PATH_DATA}/bond_trade_sse_{report_date.strftime('%Y%m%d')}.csv", encoding="GB18030")
历史月报数据抓取
上述代码已经实现了沪深交易所现券交易月报数据的单次抓取,若需要对历史上的月报数据进行抓取,可将上述代码分别封装为工具函数,将月报日期设定为函数参数,再对需要抓取的日期循环调用工具函数,即可完成历史月报数据的批量抓取。需要注意的重点,一方面避免重复抓取,另一方面注意通过sleep函数控制抓取速度。
# 利用pandas生成待抓取日期对应的循环进度条
report_dates = pd.date_range(datetime.date(2022, 1, 1), datetime.date(2023, 1, 31), freq="M")
# 利用tqdm生成待抓取日期对应的循环进度条
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修改为深交所现券交易数据抓取代码,注意循环中日期参数为loop_date
pass
# 判断该日期月报是否已抓取,避免重复运行爬虫
if not os.path.exists(f"{PATH_DATA}/bond_trade_sse_{loop_date.strftime('%Y%m%d')}.csv"):
# 此处将pass修改为上交所现券交易数据抓取代码,注意循环中日期参数为loop_date
pass
# 利用sleep函数控制抓取速度,单位为秒
sleep(1)
本次案例以抓取沪深交易所现券交易月报为例,主要展示了用Python实现网络数据抓取的简要流程,以及requests、re、datetime、pandas、numpy、tqdm的初步使用。若有错漏之处,还请各位批评指正。
——文 by 十月