给自己搭一个金融数据库(五)——网页数据爬取
在给自己搭一个金融数据库(三)中介绍了数据库的定时更新,但数据来源于tushare数据库。tushare上的净利润时常会有更新,并且没有更新时间,即使定时更新也必须每天去更新一次,而我在策略回溯时,为了保证数据的一致性,必须每个策略每天都重新查询数据库。不知道是不是tushare的次数限制变少了,今天更是一大早就碰到了次数限制。为了攻克这个问题,我决定自己去网站上爬数据。
1. 选定数据来源
数据爬取前先要明确数据来源。我现在需要净利润数据,进入东方财富,点“个股”,进入“数据中心”,在年报季报中选择“利润表”https://data.eastmoney.com/bbsj/lrb.html。可以看到这里利润表的数据,不仅仅是净利润,干脆把以后可能用的数据也获取并存入到数据库。
2. 数据源解析
用goole chrome浏览器打开上述网址,按下“ctrl+shift+i”,选中network。
然后刷新网页。
从name下找到数据信息
右击复制link adress可以得到:https://datacenter-web.eastmoney.com/api/data/v1/get?callback=jQuery112305278712291236005_1650693385897&sortColumns=NOTICE_DATE%2CSECURITY_CODE&sortTypes=-1%2C-1&pageSize=50&pageNumber=1&reportName=RPT_DMSK_FN_INCOME&columns=ALL&filter=(SECURITY_TYPE_CODE+in+(%22058001001%22%2C%22058001008%22))(TRADE_MARKET_CODE!%3D%22069001017%22)(REPORT_DATE%3D%272022-03-31%27)
分析这个链接,可以怀疑最后的2022-03-31代表了报告期。为了验证它,再来看一个不同的报告期,看一下2020-09-30。https://datacenter-web.eastmoney.com/api/data/v1/get?callback=jQuery112306160003384628727_1650696412661&sortColumns=NOTICE_DATE%2CSECURITY_CODE&sortTypes=-1%2C-1&pageSize=50&pageNumber=1&reportName=RPT_DMSK_FN_INCOME&columns=ALL&filter=(SECURITY_TYPE_CODE+in+(%22058001001%22%2C%22058001008%22))(TRADE_MARKET_CODE!%3D%22069001017%22)(REPORT_DATE%3D%272021-09-30%27)
可以看到刚刚那个日期确实是报告期。
再来分析一下下一页的链接有什么样的变化:https://datacenter-web.eastmoney.com/api/data/v1/get?callback=jQuery112306160003384628727_1650696412661&sortColumns=NOTICE_DATE%2CSECURITY_CODE&sortTypes=-1%2C-1&pageSize=50&pageNumber=2&reportName=RPT_DMSK_FN_INCOME&columns=ALL&filter=(SECURITY_TYPE_CODE+in+(%22058001001%22%2C%22058001008%22))(TRADE_MARKET_CODE!%3D%22069001017%22)(REPORT_DATE%3D%272021-09-30%27)
可以看到代码第几页的是中间的“pageNumber=2”。
3. 获取信息
3.1. 导入需要使用的包
import requests
3.2. 获取数据并解析
先获取数据
headers = {'Content-Type': 'text/plain;charset=UTF-8'}
url = 'https://datacenter-web.eastmoney.com/api/data/v1/get?callback=jQuery112305278712291236005_1650693385897&sortColumns=NOTICE_DATE%2CSECURITY_CODE&sortTypes=-1%2C-1&pageSize=50&pageNumber=1&reportName=RPT_DMSK_FN_INCOME&columns=ALL&filter=(SECURITY_TYPE_CODE+in+(%22058001001%22%2C%22058001008%22))(TRADE_MARKET_CODE!%3D%22069001017%22)(REPORT_DATE%3D%272020-09-30%27)'
response = requests.get(url, headers=headers)
print(response.text)
然后对数据进行解析
import re
r = re.compile('\(.*\)')
result = eval(re.findall(r, response.text)[0][1:-1].replace('null', 'None').replace('true', 'True'))['result']
pages = result['pages']
data = result['data']
profit_data = pd.DataFrame(columns=data[0].keys())
for i in range(len(data)):
profit_data.loc[i, :] = list(data[i].values())
print('pages: ', pages)
print(profit_data)
对照网页对数据进行一些筛选,并跟之前的数据进行一些名称上的统一。
profit_data.rename(columns={'SECUCODE': 'ts_code'}, inplace=True)
profit_data.columns = [s.lower() for s in profit_data.columns]
profit_data = profit_data[['ts_code', 'notice_date', 'report_date', 'parent_netprofit', 'total_operate_income', 'total_operate_cost', 'toe_ratio', 'operate_cost', 'operate_expense', 'operate_expense_ratio', 'sale_expense', 'manage_expense', 'finance_expense', 'operate_profit', 'total_profit', 'income_tax', 'operate_income', 'operate_profit_ratio', 'parent_netprofit_ratio']]
print('pages: ', pages)
print(profit_data.columns)
print(profit_data)
4. 将数据写入数据库
建立数据表
create table profit_statement(id int auto_increment not null primary key, ts_code varchar(10) not null comment "股票代码", notice_date datetime comment '发布日期', report_date datetime comment '报告日期', parent_netprofit double comment '归属母公司净利润', total_operate_income double comment '营业总收入', total_operate_cost double comment '营业总成本', toe_ratio double comment '营业总支出比', operate_cost double comment '营业支出', operate_expense double comment '经营费用', operate_expense_ratio double comment '营业支出同比增长率', sale_expense double comment '销售费用', manage_expense double comment '管理费用', finance_expense double comment '财务费用', operate_profit double comment '经营利润', total_profit double comment '总利润', income_tax double comment '税收', operate_income double comment '经营收入', operate_profit_ratio double comment '营业利润同比增长率', parent_netprofit_ratio double comment '归属母公司净利润同比增长率');
然后将刚刚的数据写入数据库
from sqlalchemy import create_engine
engine=create_engine('mysql+pymysql://remote:password@ip:3306/stock')
profit_data.to_sql('profit_statement', engine, index=False, if_exists='append')
5. 批量写入数据库
首先把刚刚尝试性写入的数据清空。
然后把之前的代码写成函数
def get_data(url, headers):
response = requests.get(url, headers=headers)
s = response.text
r = re.compile('\(.*\)')
result = eval(re.findall(r, s)[0][1:-1].replace('null', 'None').replace('true', 'True'))['result']
pages = result['pages']
data = result['data']
profit_data = pd.DataFrame(columns=data[0].keys())
for i in range(len(data)):
profit_data.loc[i, :] = list(data[i].values())
profit_data.rename(columns={'SECUCODE': 'ts_code'}, inplace=True)
profit_data.columns = [s.lower() for s in profit_data.columns]
profit_data = profit_data[['ts_code', 'notice_date', 'report_date', 'parent_netprofit', 'total_operate_income', 'total_operate_cost', 'toe_ratio', 'operate_cost', 'operate_expense', 'operate_expense_ratio', 'sale_expense', 'manage_expense', 'finance_expense', 'operate_profit', 'total_profit', 'income_tax', 'operate_income', 'operate_profit_ratio', 'parent_netprofit_ratio']]
profit_data.to_sql('profit_statement', engine, index=False, if_exists='append')
return pages
再然后,把这个报告期的利润表数据都获取并写入到数据库。
pages = get_data(url, headers)
for i in range(2, pages+1):
print(i)
url = 'https://datacenter-web.eastmoney.com/api/data/v1/get?callback=jQuery112305278712291236005_1650693385897&sortColumns=NOTICE_DATE%2CSECURITY_CODE&sortTypes=-1%2C-1&pageSize=50&pageNumber=' + str(i) + '&reportName=RPT_DMSK_FN_INCOME&columns=ALL&filter=(SECURITY_TYPE_CODE+in+(%22058001001%22%2C%22058001008%22))(TRADE_MARKET_CODE!%3D%22069001017%22)(REPORT_DATE%3D%272020-09-30%27)'
get_data(url, headers)
最后,把其他报告期的数据也获取并写入到数据库。
参考文献:
-
https://www.jianshu.com/p/cbeca10bf81b -
https://m.php.cn/article/487036.html -
https://blog.51cto.com/u_8697137/3046856
- 点赞
- 收藏
- 关注作者
评论(0)