金融数据获取:获取上市公司财务报表

本文介绍了如何使用Python模拟爬虫技术,通过Selenium和requests库处理JavaScript动态加载的网页,从新浪财经获取上证指数成分股的公司列表和近3年的财务数据。首先,提取所有公司代码,然后针对每个公司爬取其历史财务报表数据,并将数据保存为CSV文件。整个过程涉及到网页URL分析、循环遍历、正则表达式以及数据清洗和存储。
摘要由CSDN通过智能技术生成

        前段时间介绍了selenium模拟爬虫,应对很多需要动态加载或鼠标点击的网页都非常有效,本期介绍一个js动态加载的网页爬虫。正好笔者也很久没有写爬虫了,当是练练手。目标定为新浪财经,获取上证指数成分股近3年的利润表数据,爬取完成后保存到本地csv中。


目录

1. 获取所有公司列表

2. 爬取单个公司历史财务数据

3. 批量爬取历史数据


        先导入一些必要模块:

import pandas as pd
import requests
import re

1. 获取所有公司列表

        打开新浪的行情中心,选择相关指数即可以查看所有成分股:行情中心_新浪财经。如图,每页如果显示80条,一共有25页,利用循环遍历爬取是没跑了。

         新浪的难点在于翻页是通过js请求完成的,也就是说无论点击哪一页,浏览器上显示的网址都是一样的。笔者通过Telerik fiddler工具抓取到翻页时的网址如下:

url = "https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeDataSimple?page=1&num=80&sort=symbol&asc=1&node=zhishu_000001&_s_r_a=page"

        当然,键盘F12在网络里一条条找访问记录也是可以找到这个网址的:

         观察该网址不难发现,"page="的字段就是翻页的参数。"num="的字段就是每页显示多少条记录的参数。

        下面改写一下,加入翻页循环。利用正则表达式匹配公司代码最后存进表格:

stock_list = []
for i in range(1, 26):
    url = "https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeDataSimple?page="+str(i)+"&num=80&sort=symbol&asc=1&node=zhishu_000001&_s_r_a=page"
    response = requests.get(url).text
    symbol = re.findall('"symbol":"(.*?)","name"',response,re.S)
    stock_list.extend(symbol)

print(stock_list[:5])
print("共获取:", len(stock_list))

# ['sh600000', 'sh600004', 'sh600006', 'sh600007', 'sh600008']
# 共获取: 2000

        共获取到2000家公司代码。

2. 爬取单个公司历史财务数据

        一样先观察网址,笔者找到一个较为容易的网址结构:http://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/600585/ctrl/2022/displaytype/4.phtml

        新浪这个网址不是通过js请求的,可以直接在浏览器上复制粘贴,只要改改公司代码和年份即可,内容属于可见即可爬的表格:

url = "http://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/600000/" \
    "ctrl/2022/displaytype/4.phtml"
df = pd.read_html(url, attrs = {"id": "ProfitStatementNewTable0"}, header=[1], index_col=0)[0]
df.dropna(axis=1, how="all", inplace=True)

print(df)

                2022-09-30	2022-06-30	2022-03-31
报表日期			
    NaN	            NaN	        NaN	        NaN
一、营业收入	14368000.00	9864400.00	5000200.00
利息净收入	10159200.00	6868100.00	3450200.00
其中:利息收入	22503100.00	15027800.00	7533200.00
减:利息支出	12343900.00	8159700.00	4083000.00
...

        但这样只能请求到三期的财报,如果要更多期就需要循环遍历了,不过也很简单:

url = "http://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/600000/ctrl/2022/displaytype/4.phtml"
df = pd.read_html(url, attrs = {"id": "ProfitStatementNewTable0"}, header=[1], index_col=0)[0]
df.dropna(axis=1, how="all", inplace=True)

for i in range(1, 4):
    url = "http://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/600000/ctrl/"+str(2022-i)+"/displaytype/4.phtml"
    df_1 = pd.read_html(url, attrs = {"id": "ProfitStatementNewTable0"}, header=[1], index_col=0)[0]
    df_1.dropna(axis=1, how="all", inplace=True)
    df = pd.concat([df, df_1], axis=1) 

df = df.dropna(how="all")
print(df)

报表日期         2022-09-30	2022-06-30	2022-03-31	2021-12-31	2021-09-30	2021-06-30	2021-03-31	2020-12-31	2020-09-30	2020-06-30	2020-03-31	2019-12-31	2019-09-30	2019-06-30	2019-03-31														
一、营业收入	14368000.00	9864400.00	5000200.00	19098200.00	14348400.00	9736500.00	4952200.00	19638400.00	14873100.00	10140700.00	5542400.00	19068800.00	14638600.00	9759900.00	5008400.00
利息净收入	10159200.00	6868100.00	3450200.00	13595800.00	10138900.00	6766200.00	3367200.00	13858100.00	9145600.00	6187500.00	3209600.00	12885000.00	9782200.00	6426400.00	3144600.00

3. 批量爬取历史数据

        将上面的代码改写成函数传参,遍历所有的公司代码即可。封装好后加入一些进度显示,时间计算的代码,一个精致的利润表数据获取程序就完成了:

def craw_list():
    stock_list = []
    for i in range(1, 26):
        url = "https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeDataSimple?page="+str(i)+"&num=80&sort=symbol&asc=1&node=zhishu_000001&_s_r_a=page"
        response = requests.get(url).text
        symbol = re.findall('"symbol":"(.*?)","name"',response,re.S)
        stock_list.extend(symbol)
    return stock_list


def craw_mod(code, year):
    url = "http://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/"+code+"/ctrl/2022/displaytype/4.phtml"
    df = pd.read_html(url, attrs = {"id": "ProfitStatementNewTable0"}, header=[1], index_col=0)[0]
    df.dropna(axis=1, how="all", inplace=True)

    for i in range(1, year):
        url = "http://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/"+code+"/ctrl/"+str(2022-i)+"/displaytype/4.phtml"
        df_1 = pd.read_html(url, attrs = {"id": "ProfitStatementNewTable0"}, header=[1], index_col=0)[0]
        df_1.dropna(axis=1, how="all", inplace=True)
        df = pd.concat([df, df_1], axis=1) 
        df.dropna(how="all")
        
    df.to_csv(code + ".csv") # 存储路径
    

def main():
    stock_list = craw_list()
    for code in stock_list:
        craw_mod(code[2:], 3) # code前两个字符为"sh",要去掉
        print("爬取进度{}%\r".format('%.2f'% (100*(stock_list.index(code) + 1)/len(stock_list))), end = "")


if __name__=="__main__":
    import datetime
    start = datetime.datetime.now()
    main()
    end = datetime.datetime.now()
    print("程序耗时:", end - start)

        当然,用多线程或者多进程辅助加速也是可以的,这里就不进行展示了。

        在刚刚的网址中找到资产负债表、现金流量表的网址链接就可以进一步把其它两张表也爬下来,都是一样的操作,换换网址而已,笔者也不进行更多展示了。

        最后都保存到了本地:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Simon Cao

创作不易,您的鼓励将是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值