python爬取公司财务报表(Python抓取上市公司财务数据)

本文介绍通过python来抓取上市公司简介和行业,昨天我讲解了上市公司列表的抓取,我们拿到上市公司列表后,就可以实现循环抓取各个上市公司的详情数据。本文将初次涉及到python的scrapy模块使用,将介绍模块中常用的类和方法,还包括xpath介绍和使用。

先回顾一下本主题“Python抓取上市公司财务数据”的内容体系,分成9节来为‬大家讲解,从0到1来详细拆解程序开发流程和编码实现,这套体系内容适合给Python零基础的小白学者学习,同时也对熟悉python但对数据采集不熟练的量化专家提供一套Python抓取的最佳实践。其包含的主要章节如下:

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

2. Win10搭建Python开发环境

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

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

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

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

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

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

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

本文讲解的是其中的第5章节,主要包括:

1)公司简介页面的数据结构分析

2)编写公司信息数据抓取和解析程序

3)公司简介抓取程序的运行

4)所属行业页面数据抓取和解析

本文涉及到的相关基础知识主要有Selector类的使用、xpath表达式的使用,以字符串的处理。其中,Selector类支持xpath和css两种提取元素选择器方式,提取的元素可以使用的方法有:

1. extract方法来获取所选元素的内容,结果为数组;

2. extract_first,它只提取第一个元素的值,如果无符合条件的元素,则返回None。

对于xpath的基本使用语法的表达式含义主要为如下:

1) node_name为选取此节点的所有子节点;

2) 表达式/代表绝对路径匹配,从根节点选取;

3) 表达式//代表相对路径匹配,从所有节点中查找当前选择的节点,包括子节点和后代节点,其第一个/表示根节点;

4) 表达式.代表选取当前节点;

5) 表达式..代表选取当前节点的父节点;

6) 表达式@代表选取属性值,通过属性值选取数据。常用元素属性有@id、@name、@type、@class、@tittle、@href。

xpath提供了100多个内建函数,我们抓取常用的内建函数主要使用了text(),用来文本匹配,表示值取当前节点中的文本内容。

另外,我们对解析结果字符串的处理常用的有:

1. 字符串切割子串,它和数组的切割子数组类似,可以直接使用[x:y]、[x:]或[:y]的方式来取子串。其中x和y为数值,代表下要切割的起始、结束下标值。如果使用负数,则为从字符串结尾开始反向计算下标位置,如'abc'[1:]和'abc'[-2:]的结果均为'bc';

2. 字符串两边的空格去除可以使用strip方法,如'\ta b \r\n'.strip()的结果为'a b'。

一、公司简介页面的数据结构分析

第一步:打开公司简介页面

打开公司简介页面,以新华医疗(600587)为例,如下:

python爬取公司财务报表(Python抓取上市公司财务数据)(1)

第二步:打开页面的浏览器检查工具

我们通过右键-点击“检查”(或快捷键F12),如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(2)

第三步:使用元素选择器选择公司简介表格

点击元素的选择器图标,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(3)

再将鼠标移动到公司简介表格的首行,并点击选中,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(4)

第四步:复制表格首行的xpath信息

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

python爬取公司财务报表(Python抓取上市公司财务数据)(5)

得到的XPath信息为://*[@id="comInfo1"]/tbody/tr[1]

二、编写公司信息数据抓取和解析程序

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

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

python爬取公司财务报表(Python抓取上市公司财务数据)(6)

打开后,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(7)

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

编写scrapy_detail函数抓取页面数据代码,包含参数code股票代码,detail_dir详情存储目录,overwrite是否重写结果文件(若需将抓取结果覆盖)。并先编写根据XPath提取元素部分,如下:

def scrapy_detail(self, code, detail_dir, overwrite): detail_url = "https://vip.stock.finance.sina.com.cn/corp/go.php/vCI_CorpInfo/stockid/%s.phtml" resp = request.urlopen(detail_url%(code), 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) print (sel.xpath('//*[@id="comInfo1"]/tbody/tr[1]')) print (sel.xpath('//*[@id="comInfo1"]/tbody ')) print (sel.xpath('//*[@id="comInfo1"]')) else: print("error return code:%d" % rt_code) return True

上述代码对xpath路径及其父级路径的提取结果都进行了打印。该方法定义在ScrapyDetail类中,格式需注意增加一层缩进。

另外,在模块顶部增加依赖模块的加载,引入代码如下:

from urllib import request import ssl ssl._create_default_https_context = ssl._create_unverified_context from scrapy.selector import Selector from scrapy.http import HtmlResponse

以上代码说明如下:

1. from urllib import request为从urllib模块中加载request子模块,http请求我们使用request模块的urlopen方法;

2. import ssl和ssl._create_default_https_context = ssl._create_unverified_context是在https安全请求时,设置为做不认证的模式。不做此设置会导致https类型的请求会失败。

3. Selector为选择器类,提供xpath、css的路径提取方法;

4. HtmlResponse为Response的子类,用于下载http请求的返回信息;

为了测试scrapy_detail函数,我们在run方法中增加调用,参数赋值为:

(1) code参数局部赋值,使用样例企业新华医疗(600587)作为测试;

(2) detail_dir作为ScrapyDetail类的成员变量进行赋值;

(3) overwrite设置成true,以方便后续重跑测试。

代码编写好后,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(8)

第三步:运行测试XPath提取结果

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

python爬取公司财务报表(Python抓取上市公司财务数据)(9)

根据运行结果可知,通过请求拿到的表格格式略有不同,表格里面没有tbody标签,因此只有最顶级的xpath能取到元素。

第四步:修改调试XPath提取结果

我们将xpath路径换成//*[@id="comInfo1"]/tr[1],并增加打印第一行的所有列的xpath为//*[@id="comInfo1"]/tr[1]/td,以及表格的所有行后的xpath为//*[@id="comInfo1"]/tr,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(10)

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

python爬取公司财务报表(Python抓取上市公司财务数据)(11)

根据结果输出,我们成功获取到了表格中的行和列元素数据。

第五步:编写公司简介表格数据的循环解析

编写xpath循环解析表格行,并每两列作为一个键值对,存储在info_dict字典中,代码如下:

tr_list_sel = sel.xpath('//*[@id="comInfo1"]/tr') for tr_sel in tr_list_sel: one_row = tr_sel.xpath('td//text()').extract() key = None val = "" for one_sel in one_row: if one_sel.endswith(':'): val = "" key = one_sel[:len(one_sel)-1] else: val = val ("\t" if val else "") one_sel if key: info_dict[key] = val.strip() print (info_dict)

其中:

1) 先用//*[@id="comInfo1"]/tr解析出每行的元素选择器;

2) 设置xpath为td//text()来循环提取出每列中的文本;

3) 对多列文本的数组进行循环处理,将':'结尾的作为键,随后的列作为对应的值,存储在info_dict中;

4) 循环全部结束后,打印输出解析结果字典info_dict。

在scrapy_detail函数中增加以上解析逻辑后,如下图所示:

python爬取公司财务报表(Python抓取上市公司财务数据)(12)

第六步:测试运行简介表格解析结果

运行scrapy_detail.py模块,运行效果如下图所示:

python爬取公司财务报表(Python抓取上市公司财务数据)(13)

代码成功解析出了上市公司的公司简介。

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

增加文件存在判断,代码如下:

res_file = "%s/detail_%s.data"%(detail_dir, code) if not overwrite and os.path.isfile(res_file): print ("skip scrapy, result exist in:" res_file) return False

将该代码逻辑放在函数scrapy_detail的开头,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(14)

解析结果字典info_dict需要写入文件,我们将写文件逻辑放在函数write_file中,代码如下:

def write_file(self, info_dict, res_file): if info_dict: try: fb = open(res_file, 'w') fb.write(json.dumps(info_dict) '\n') except IOError as err: print ('IO Error:', err) else: fb.close()

由于用到了json模块,我们需要在模块顶部增加import json来加载,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(15)

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

python爬取公司财务报表(Python抓取上市公司财务数据)(16)

其中参数info_dict为解析结果字典,res_file为将写入的文件路径。最后,使用快捷键Ctrl S保存更新后的模块代码。

三、公司简介抓取程序的运行

第一步:创建结果数据存储的文件夹detail_data

打开项目文件夹scrapy_finance,右键-新建-新建文件夹,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(17)

新建的文件夹命名成detail_data,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(18)

第二步:测试运行scrapy_detail模块

切换回scrapy_detail.py的编辑窗口,使用快捷键ctrl F5运行模块,结果如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(19)

第三步:查看简介数据抓取结果

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

python爬取公司财务报表(Python抓取上市公司财务数据)(20)

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

四、所属行业页面数据抓取和解析

第一步:打开所属行业页面

打开公司所属行业页面,以新华医疗(600587)为例,如下:

python爬取公司财务报表(Python抓取上市公司财务数据)(21)

第二步:使用元素选择器选择所属行业板块的值

我们通过右键-点击“检查”(或快捷键F12),点击左下角的元素的选择器图标,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(22)

再将鼠标移动到所属行业板块的值(本示例的值为“医疗器械”),并点击选中,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(23)

第三步:复制所属行业板块的值的xpath信息

选中<tr>标签,点击右键-复制-复制XPath,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(24)

得到表格该值的字段xpath信息为://*[@id="con02-0"]/table[1]/tbody/tr[3]/td[1]

第四步:编写代码抓取并提取所属行业板块的值

在ScrpayDetail类中增加函数scrapy_industry,并编写代码如下:

def scrapy_industry(self, code, detail_dir, overwrite): res_file = "%s/industry_%s.data"%(detail_dir, code) if not overwrite and os.path.isfile(res_file): print ("skip scrapy, result exist in:" res_file) return False detail_url = "https://vip.stock.finance.sina.com.cn/corp/go.php/vCI_CorpOtherInfo/stockid/%s/menu_num/2.phtml" resp = request.urlopen(detail_url%(code)) 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) one_sel = sel.xpath('//*[@id="con02-0"]/table[1]/tr[3]/td[1]/text()').extract_first() self.write_file({"industry" : one_sel}, res_file) else: print("error return code: %d" % rt_code) return True

该方法实现中,将请求响应的内容直接使用刚刚获取到的xpath信息,再拼接上/text()来获取其元素下一级文本内容。解析结果直接以字典的形式写入文件中,write_file在前面已经定义实现了。相关依赖的模块在前面步骤中已经增加过加载代码,就不用重复添加了。代码编写完成后,效果如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(25)

在run方法中,增加scrapy_industry方法的调用,并将overwrite设置为False,以避免重复抓取前面的公司简介页,并增加os模块的加载,如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(26)

使用Ctrl S快捷键保存所编写的模块代码。

第五步:所属行业板块抓取程序的运行

使用快捷键ctrl F5运行scrapy_detail.py模块,结果如下图:

python爬取公司财务报表(Python抓取上市公司财务数据)(27)

第六步:查看所属行业板块抓取结果

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

python爬取公司财务报表(Python抓取上市公司财务数据)(28)

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

五、结语

本文讲解了如何对新浪财经的上市公司简介页的数据结构进行分析,通过元素选择器找到xpath信息,并通过编写python程序来实现数据的抓取和表格数据解析成键值对字典,最后将字典数据存储到结果文件中。最后使用同样的流程对所属行业页面进行了抓取、解析和存储。中间还遇到了浏览器和urllib请求到的网页数据不一致的坑,希望大家能及时发现这种坑,以程序响应的数据为准,同时能掌握其调试和分析的思路。

下一节将介绍“上市公司的财务摘要数据的抓取”,详细拆解实现过程,以逐步深入的方式让小白学者也能完全掌握python抓取上市公司财务数据的编码实操过程。学到现在,你应该对网页数据的结构和解析基本掌握了,后续将逐步侧重加强数据处理和存储分析方面的讲解。看到这里请点赞支持下,对该主题感兴趣的朋友可以关注下我的后续动态~

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页