赞
踩
A股上市公司年报,是我们分析上市公司财务状况和经营状况,并进行股票估值和行情预测的重要依据。那么,我们应该如何爬取这些上市公司的财报数据,并用于数据分析和可视化呢?今天我们以东方财富网为例,来介绍一下基本的步骤。
1. 浏览器:Safari浏览器(版本:17.31)
2. Python版本:Python3.12
3. 开发环境:Pycharm 2023.3(Community Edition)
4. 操作系统:MacOS 14.3(Sonoma)
1. 点击如下网址,进入数据页面
2. 页面空白处“点击右键”——“检查元素”,进入开发者工具。
选择”网络“标签页,然后刷新网页,获取所有网页加载项。
3. 对列表中的所有加载项依次进行预览,寻找数据源地址。
以本次操作为例,数据源的网址为(数据源网址是动态生成的):
4. 分析数据源网址,找出真正的数据源接口
一般网址的基本结构为:
协议://域名(IP:端口)/资源路径?查询条件(结构:key1=value1&key2=value2)
据此分析上面的数据源网址,可以发现,真正的数据接口,其实是:
https://datacenter-web.eastmoney.com/api/data/v1/get
但是,要想获取到指定数据,“查询条件”部分也是必不可少的。这个我们后面再讲。
5. 分析数据源网址的代码结构,确定爬取方案
通过“预览”,我们可以发现,数据源网址对应的,其实是一个JSON格式的数据。但这并不是标准的JSON格式数据,还多了一个“jQuery112307880322881038256_1709033016691()”。这个多出来的部分是回调函数,对应数据源网址中的"callback"部分,我们可直接在网址中删除。
1. 导入工具包
- # coding:utf-8
- import requests
- import pandas as pd
- import json
2. 创建DataFrame表格。注意:变量名要与数据对应
list=pd.DataFrame(columns=['股票代码','股票名称','所在行业','股市类型','交易市场','每股收益','每股净收益','营业总收入','营业收入同比增长','净利润','净利润同比增长','每股净资产','净资产收益率','每股经营现金流量','销售毛利率','利润分配','股息率'])
3. 建立循环,以爬取所有页面的数据。循环范围根据数据的页面数量决定。
4. 使用requests爬取数据
(1)确定爬取数据的url网址,如下:
url='https://datacenter-web.eastmoney.com/api/data/v1/get?sortColumns=UPDATE_DATE%2CSECURITY_CODE&sortTypes=-1%2C-1&pageSize=50&pageNumber='+str(i)+'&reportName=RPT_LICO_FN_CPD&columns=ALL&filter=(REPORTDATE%3D%272022-12-31%27)'
其中”?"之后的”查询条件“部分,分别设为:
sortColumns=UPDATE_DATE%2CSECURITY_CODE #排序变量#
sortTypes=-1%2C-1 #排序格式#
pageSize=50 #每页的数据量,此处默认为50#
pageNumber=str(i) # "i"对应循环数,循环爬取各页数据#
reportName=RPT_LICO_FN_CPD #报告名#
columns=ALL #查询所有变量#
filter=(REPORTDATE%3D%272021-12-31%27) #筛选报告时间,此处默认2022-12-31#
(2)创建表头headers,如下:
- header={'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3.1 Safari/605.1.15',
- 'Cookie': 'st_asi=delete; st_inirUrl=https%3A%2F%2Fbaidu.com%2F; st_psi=20240227192236777-113300301066-4864084221; st_pvi=11934193275781; st_sn=13; st_sp=2024-02-26%2015%3A19%3A30; JSESSIONID=37A0895F7D4E1F2005EF79C5B041FC90; st_si=63431626210633; HAList=ty-1-000001-%u4E0A%u8BC1%u6307%u6570; qgqp_b_id=b06ad5d3eaab94f81f12355ecebb1842'}
cookie可以随意复制一个,不影响最终结果。
(3)爬取网页
- money=requests.get(url=url,headers=header)
- money.encoding='utf8'
5. 解析爬取的JSON数据
- data=json.loads(money.text)
- chart=data["result"]['data']
6. 将爬取到的数据依次写入DataFrame表格中
- k=0
- for j in range(50):
- try:
- chartj=chart[j]
- print(chartj)
- code=chartj['SECURITY_CODE']
- abbr=chartj['SECURITY_NAME_ABBR']
- market=chartj['TRADE_MARKET']
- type=chartj['SECURITY_TYPE']
- eps=chartj['BASIC_EPS']
- epsde=chartj['DEDUCT_BASIC_EPS']
- income=chartj['TOTAL_OPERATE_INCOME']
- try:
- incomegrtht=float(chartj['YSTZ'])/100
- except:
- incomegrtht = chartj['YSTZ']
- profit=chartj['PARENT_NETPROFIT']
- try:
- profitgrtht=float(chartj['SJLTZ'])/100
- except:
- profitgrtht = chartj['SJLTZ']
- bps=chartj['BPS']
- try:
- roe=float(chartj['WEIGHTAVG_ROE'])/100
- except:
- roe=chartj['WEIGHTAVG_ROE']
- mgjy=chartj['MGJYXJJE']
- try:
- xsml=float(chartj['XSMLL'])/100
- except:
- xsml=chartj['XSMLL']
- lrfp=chartj['ASSIGNDSCRPT']
- hy=chartj['PUBLISHNAME']
- try:
- gxl=float(chartj['ZXGXL'])/100
- except:
- gxl=chartj['ZXGXL']
- list.loc[k]=[code,abbr,hy,type,market,eps,epsde,income,incomegrtht,profit,profitgrtht,bps,roe,mgjy,xsml,lrfp,gxl]
- k=k+1
- except:
- continue
其中,k=0需要在整个爬虫代码最前端进行声明。
同时,导入变量数据时,要与开头设定的DataFrame表格的变量顺序一致。
7. 把DataFrame表格保存为excel文件
list.to_excel('list.xlsx',index=False)
运行代码后,在项目所在目录中会生成表格“list.xlsx”。
代码运行时,一般可见如下警告。它并不会影响最终结果,因此可以不予理会:
FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.
打开该文件,可以看到爬取的数据如下:
最后,附上完整代码
- # coding:utf-8
- import requests
- import pandas as pd
- import json
- k=0
- list=pd.DataFrame(columns=['股票代码','股票名称','所在行业','股市类型','交易市场','每股收益','每股净收益','营业总收入','营业收入同比增长','净利润','净利润同比增长','每股净资产','净资产收益率','每股经营现金流量','销售毛利率','利润分配','股息率'])
- for i in range(1,237):
- url='https://datacenter-web.eastmoney.com/api/data/v1/get?sortColumns=UPDATE_DATE%2CSECURITY_CODE&sortTypes=-1%2C-1&pageSize=50&pageNumber='+str(i)+'&reportName=RPT_LICO_FN_CPD&columns=ALL&filter=(REPORTDATE%3D%272022-12-31%27)'
- header={'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3.1 Safari/605.1.15',
- 'Cookie': 'st_asi=delete; st_inirUrl=https%3A%2F%2Fbaidu.com%2F; st_psi=20240227192236777-113300301066-4864084221; st_pvi=11934193275781; st_sn=13; st_sp=2024-02-26%2015%3A19%3A30; JSESSIONID=37A0895F7D4E1F2005EF79C5B041FC90; st_si=63431626210633; HAList=ty-1-000001-%u4E0A%u8BC1%u6307%u6570; qgqp_b_id=b06ad5d3eaab94f81f12355ecebb1842'}
- money=requests.get(url=url,headers=header)
- money.encoding='utf8'
- data=json.loads(money.text)
- chart=data["result"]['data']
- for j in range(50):
- try:
- chartj=chart[j]
- print(chartj)
- code=chartj['SECURITY_CODE']
- abbr=chartj['SECURITY_NAME_ABBR']
- market=chartj['TRADE_MARKET']
- type=chartj['SECURITY_TYPE']
- eps=chartj['BASIC_EPS']
- epsde=chartj['DEDUCT_BASIC_EPS']
- income=chartj['TOTAL_OPERATE_INCOME']
- try:
- incomegrtht=float(chartj['YSTZ'])/100
- except:
- incomegrtht = chartj['YSTZ']
- profit=chartj['PARENT_NETPROFIT']
- try:
- profitgrtht=float(chartj['SJLTZ'])/100
- except:
- profitgrtht = chartj['SJLTZ']
- bps=chartj['BPS']
- try:
- roe=float(chartj['WEIGHTAVG_ROE'])/100
- except:
- roe=chartj['WEIGHTAVG_ROE']
- mgjy=chartj['MGJYXJJE']
- try:
- xsml=float(chartj['XSMLL'])/100
- except:
- xsml=chartj['XSMLL']
- lrfp=chartj['ASSIGNDSCRPT']
- hy=chartj['PUBLISHNAME']
- try:
- gxl=float(chartj['ZXGXL'])/100
- except:
- gxl=chartj['ZXGXL']
- list.loc[k]=[code,abbr,hy,type,market,eps,epsde,income,incomegrtht,profit,profitgrtht,bps,roe,mgjy,xsml,lrfp,gxl]
- k=k+1
- except:
- continue
- list.to_excel('list.xlsx',index=False)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。