给自己搭一个金融数据库(五)——网页数据爬取

举报
darkpard 发表于 2022/05/04 11:17:31 2022/05/04
【摘要】 在给自己搭一个金融数据库(三)中介绍了数据库的定时更新,但数据来源于tushare数据库。tushare上的净利润时常会有更新,并且没有更新时间,即使定时更新也必须每天去更新一次,而我在策略回溯时,为了保证数据的一致性,必须每个策略每天都重新查询数据库。不知道是不是tushare的次数限制变少了,今天更是一大早就碰到了次数限制。为了攻克这个问题,我决定自己去网站上爬数据。1. 选定数据来源数...

给自己搭一个金融数据库(三)中介绍了数据库的定时更新,但数据来源于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)

图片图片

最后,把其他报告期的数据也获取并写入到数据库。

参考文献:

  1. https://www.jianshu.com/p/cbeca10bf81b
  2. https://m.php.cn/article/487036.html
  3. https://blog.51cto.com/u_8697137/3046856
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。