Python抓取上市公司财务数据七历年财务数据抓取

今天给大家介绍“Python抓取上市公司财务数据”主题的第7章节 – 上市公司历年的财务数据抓取。本文将进一步增加python抓取程序的实现难度,实现多个类似数据结构的网页数据的通用抓取。回顾主题,我们分成9节来为讲解Python抓取上市公司财务数据,从0到1来详细拆解程序开发流程和编码实现,是一套从入门到熟练python抓取的课题。其包含的主要章节有:

1. Centos7搭建代码库和Python运行环境

2. Win10搭建Python开发环境

3. Python爬虫应用运行(Docker)镜像准备

4. 编码实现上市公司列表抓取

5. 编码实现上市公司简介和行业板块抓取

6. 编码实现上市公司企业财务摘要抓取

[本节]7. 编码实现上市公司历年财务数据抓取

8. 编码实现上市公司财务数据抓取结果入库(Mysql)

9. Python代码提交及部署运行

在第4节的内容里我们已经对财务指标、资产负债表、利润表、现金流表这四个页面的表格结构和URL进行过分析,并得出其表格结构是类似的。因此,本任务通过编写一个兼容的方法,来对这四个页面的数据进行抓取、解析及存储。本节内容主要分成以下几点:

(1)历年财务数据表格的XPath信息提取

(2)编写样例财务数据抓取和解析程序

(3)编写四类财务数据的历年数据抓取

(4)编写循环调用所有上市公司列表的数据抓取

下面我们就按顺序来讲解,包含非常详细的代码编写和效果截图,建议收藏研究。

一、历年财务数据表格的XPath信息提取

第一步:定位财务指标表格的XPath信息

我们打开财务指标页面的元素选择器,并选择首行的“报告日期”列,如下图:

我们选择首行所在的标签,点击右键-复制-复制XPath,如下图:

得到的XPath信息为://*[@id=”BalanceSheetNewTable0″]/tbody/tr[1]

第二步:定位资产负债表的表格XPath信息

我们打开资产负债表页面的元素选择器,并选择首行的“报表日期”列,如下图:

我们选择首行所在的标签,点击右键-复制-复制XPath,如下图:

得到的XPath信息为://*[@id=”BalanceSheetNewTable0″]/tbody/tr[1]

第三步:定位利润表的表格XPath信息

我们打开利润表页面的元素选择器,并选择首行的“报表日期”列,如下图:

我们选择首行所在的标签,点击右键-复制-复制XPath,如下图:

得到的XPath信息为://*[@id=”ProfitStatementNewTable0″]/tbody/tr[1]

第四步:定位现金流表的表格XPath信息

我们打开现金流表页面的元素选择器,并选择首行的“报表日期”列,如下图:

我们选择首行所在的标签,点击右键-复制-复制XPath,如下图:

得到的XPath信息为://*[@id=”ProfitStatementNewTable0″]/tbody/tr[1]

二、编写样例财务数据抓取和解析程序

第一步:打开Scrapy_detail.py模块文件

打开项目文件夹scrapy-finance,并选中scrapy_detail.py右键-Edit with IDLE-Edit with IDLE 3.10(64-bit),如下图:

打开后,如下图:

第二步:编写代码抓取结果的XPath提取

编写scrapy_finance_indices函数抓取页面数据代码,包含参数code、detail_dir、overwrite之外,还插入了参数如下参数:

1) detail_url为含变量占位符的页面URL,为了生成不同页面的待抓取URL;

2) syear为数据年份范围的开始数,其值意为距离今年的年数;

3) eyear为数据年份范围的截止数,其值意为距离今年的年数(范围不包含截止数);

4) tr_xpath为表格行的XPath;

5) data_sign为数据标识,财务指标用finance,资产负债表用assert,利润表用profit,现金流表用cache来作为数据类型的标识,用来给存储文件命名。

先根据抓取和XPath提取页面元素的逻辑编写提取财务数据页面表格的tr元素选择器代码,如下:

def scrapy_finance_indices(self, code, detail_url, syear, eyear, tr_xpath, data_sign, detail_dir, overwrite): res_file = “%s/%s_%s.data” % (detail_dir, data_sign, code) if not overwrite and os.path.isfile(res_file): print (“skip scrapy, result exist in:” res_file) return False if syear >= eyear: print (“skip scrapy, no vaild year range (%d, %d)”%(syear, eyear)) return False # year parameters pdate_list = [] nyear = int(time.strftime(‘%Y’,time.localtime())) for i in range(syear, eyear): pdate_list.append(str(nyear-i)) for year_parameter in pdate_list: resp = request.urlopen(detail_url%(code, year_parameter), timeout=30) print(“request url:” resp.geturl()) rt_code = resp.getcode() if rt_code==200: content = resp.read() response = HtmlResponse(url=detail_url, body=content) sel = Selector(response=response) tr_list_sel = sel.xpath(tr_xpath) print (tr_list_sel) else: print (“error return code: %s” % rt_code) return True

将方法scrapy_finance_summary放在ScrapyDetail类中,编写效果如下图:

需要注意的是,我们在生成年份时,使用time模块来格式化生成的年份。

第三步:调用并运行测试XPath解析结果

为了测试scrapy_finance_indices函数,我们在run方法中增加调用,参数code、detail_dir、overwrite均和前面简介页抓取的调用一致,其他参数赋值先使用财务指标表的url和XPath来测试,年份范围使用1到2,数据类型用finance。并先在模块顶部增加time模块的加载后。相关代码如下图:

保存后运行该模块,结果如下:

通过运行结果可得,使用生成的2021年财务指标数据页URL抓取结果,使用对应的XPath信息解析得到了128行数据。

第四步:编写将数据解析到字典的处理逻辑

我们在循环处理之外定义date_dict字典,并在循环处理中将字段提取保存到字典中。并且将日期作为字典的第一级,下一级为指标的名称,若指标存在父标题,则使用二三级作为指标名称,最后一级存储指标的值。另外,第一行的日期值用变量first_val数组存储起来,用于后面的对应报告期财务数据字典的查询存储。而将变量header_title作为指标名称的父标题,若无父标题,则为None。最后在循环结束后打印data_dict字典,实现代码如下:

header_title = None first_val = None for tr_sel in tr_list_sel: td_sel = tr_sel.xpath(‘td//text()’).extract() if not td_sel: continue title_key = td_sel[0] # one column means parent level title if len(td_sel) == 1: header_title = title_key continue # parse columns to val_list val_list = [] for i in range(1, len(td_sel)): val_list.append(td_sel[i]) # first row is report date row and finance data rows following if not first_val: first_val = val_list else: for i in range(0, len(val_list)): info_dict = date_dict.get(first_val[i], {}) date_dict[first_val[i]] = info_dict if header_title: header_dict = info_dict.get(header_title, {}) info_dict[header_title] = header_dict else: header_dict = info_dict header_dict[title_key] = val_list[i].strip() print (date_dict)

上述处理代码中,需要注意几点:

1. 使用td//text()子路径提取出表格一行数据的文本数组,如果该数组为空则跳过;

2. 解析出的行数组td_sel,如果只有第一列则作为后续指标的父级标题;

3. 行数据的第二列开始为值数据,即值数组val_list,并且首行值(first_val)为日期值;

4. 解析结果赋值到date_dict字典时,会先取出该数据列对应的日期值(存储在相同下标的first_val数组中),并初始化该日期对应的数据字典info_dict;

5. 如果指标存在父标题,则先初始化该父标题的值字典header_dict,如果指标不存在父标题,则info_dict就是header_dict。指标数据的键值对将存储在header_dict中。

增加的数据解析代码添加后,如下图:

字典date_dict的初始化将放到所有循环之前,如下图:

第五步:运行测试数据解析逻辑

保存并运行模块代码,结果如下图:

双击展开合并的json打印输出,如下图:

代码成功解析出了测试公司的2021年财务指标数据。

第六步:编写将解析结果存储到文件

在scrapy_detail函数中,将解析结束后的打印字典换成写文件,如下图:

保存并运行后,效果如下图:

第七步:查看测试样例的财务指标数据抓取结果

打开detail_data文件夹,查看结果文件,如下图:

运行结果成功保存到了finance_600587.data数据文件中。

三、编写四类财务数据的历年数据抓取

第一步:在run中调用抓取四类财务数据

在ScrapyDetail类的run方法中,修改scrapy_finance_indices的样例调用,改为依次调用抓取四类财务数据的抓取,类型分别为:

1) 财务指标用finance;

2) 资产负债表用assert;

3) 利润表用profit;

4) 现金流表用cache。

并且设置抓取时间范围为近5年(可以改成其他范围),即syear=0,eyear=6,代码如下:

syear, eyear = 0, 6 overwrite = True # finance indices detail_url = “https://money.finance.sina.com.cn/corp/go.php/vFD_FinancialGuideLine/stockid/%s/ctrl/%s/displaytype/4.phtml” tr_xpath = ‘//*[@id=”BalanceSheetNewTable0″]/tbody/tr’ data_sign = ‘finance’ self.scrapy_finance_indices(code, detail_url, syear, eyear, tr_xpath, “finance”, self.detail_dir, overwrite) # assert owe data detail_url = “https://money.finance.sina.com.cn/corp/go.php/vFD_BalanceSheet/stockid/%s/ctrl/%s/displaytype/4.phtml” tr_xpath = ‘//*[@id=”BalanceSheetNewTable0″]/tbody/tr’ data_sign = ‘assert’ self.scrapy_finance_indices(code, detail_url, syear, eyear, tr_xpath, “assert”, self.detail_dir, overwrite) # profit detail_url = “http://money.finance.sina.com.cn/corp/go.php/vFD_ProfitStatement/stockid/%s/ctrl/%s/displaytype/4.phtml” tr_xpath = ‘//*[@id=”ProfitStatementNewTable0″]/tbody/tr’ data_sign = ‘profit’ self.scrapy_finance_indices(code, detail_url, syear, eyear, tr_xpath, “profit”, self.detail_dir, overwrite) # cache stream detail_url = “http://money.finance.sina.com.cn/corp/go.php/vFD_CashFlow/stockid/%s/ctrl/%s/displaytype/4.phtml” tr_xpath = ‘//*[@id=”ProfitStatementNewTable0″]/tbody/tr’ data_sign = ‘cache’ self.scrapy_finance_indices(code, detail_url, syear, eyear, tr_xpath, “cache”, self.detail_dir, overwrite)

更新的模块代码保存后,如下图:

第二步:测试运行历年财务数据的抓取程序

使用快捷键Ctrl F5运行模块后,结果如下图:

第三步:查看历年财务数据的测试抓取结果

打开detail_data文件夹,查看结果文件,如下图:

运行结果成功保存到了finance_600587.data、assert_600587.data、profit_600587.data、cache_600587.data四个数据文件中。

四、编写循环调用所有上市公司列表的数据抓取

第一步:编写读取上市公司列表数据文件方法

编写加载json数据文件方法load_json_file,代码如下:

def load_json_file(self, list_file): code_list = [] try: fb = open(list_file, ‘r’) while True: line = fb.readline() if line: one_json = json.loads(line) code_list.append(one_json) else: break except IOError as err: print (‘IO Error:’, err) else: fb.close() return code_list

在ScrapyDetail类中编写load_json_file函数,如下图:

第二步:在run中加载上市公司列表并实现循环抓取其财务数据

在__init__方法中指定self.list_file的值为列表json文件的存储路径,并在run方法中将测试样例code赋值修改为循环加载的上市公司列表json数据,并取出每行json数据中的键’code’的值赋值给code,代码如下:

code_list = self.load_json_file(self.list_file)for code_json in code_list: code = code_json[‘code’]

最后注释了overwrite = True,避免重复抓取,更新好模块代码后,如下图:

至此,我们就完成了上市公司列表的财务数据抓取程序编写。

五、结语

本节先从历年财务数据表格的XPath信息获取开始,获取到四类财务数据的数据表格XPath路径,并编写解析表格数据的通用方法,通过样例测试完成历年财务数据的抓取,以及结果存储到文件。最后,通过加载上市公司企业列表,以及循环列表来实现各类财务数据的循环调用,实现了用一套流程完成了四类上市公司财务数据的抓取、解析和持久化存储。

随着本节的结束,我们财务数据抓取的相关内容就讲完了,关于爬虫的高阶用法的详解(如验证码识别、代理抓取、模拟js执行、模拟动态数据渲染等),就不在该主题讲了,感兴趣的点赞告诉我~~我好考虑后续做些相关主题的实战分享。

下一节我将介绍抓取结果数据入库(Mysql),对python处理json文件数据以及读写关系型数据库进行实战讲解,感兴趣的朋友关注下我的头条号,不要错过。

未经允许不得转载:股市行情网 » Python抓取上市公司财务数据七历年财务数据抓取

相关文章

评论 (0)