如何用python爬取上市公司年报?

我们都知道,很多公司都会在自己的官网中设置专门的栏目(比如投资者关系一栏investor relations)来放置企业的财务报表等相关资料,投资者可以在上面查询下载。通过查找了解......

如何用python爬取上市公司年报

财报分析大家在购买股票的时候,已经不只是凭感觉去买了,基本上都会对一个股票进行深入的分析。毕竟购买股票还是一项风险性较高的投资,需要在较为熟悉以后才能去开展,不能蛮干,钱也都不是天......接下来具体说说

Python代码爬取3000+ 上市公司的信息!能上市的都有这样一个特点

前言

入门爬虫很容易,几行代码就可以,可以说是学习 Python 最简单的途径。

刚开始动手写爬虫,你只需要关注最核心的部分,也就是先成功抓到数据,其他的诸如:下载速度、存储方式、代码条理性等先不管,这样的代码简短易懂、容易上手,能够增强信心。

基本环境配置

版本:Python3

系统:Windows

相关模块:pandas、csv

爬取目标网站

如何用python爬取上市公司年报?

实现代码

import pandas as pdimport csvfor i in range(1,178): # 爬取全部页 tb = pd.read_html('http://s.askci.com/stock/a/?reportTime=2017-12-31&pageNum=%s' % (str(i)))[3] tb.to_csv(r'1.csv', mode='a', encoding='utf_8_sig', header=1, index=0)

3000+ 上市公司的信息,安安静静地躺在 Excel 中:

如何用python爬取上市公司年报?

有了上面的信心后,我开始继续完善代码,因为 5 行代码太单薄,功能也太简单,大致从以下几个方面进行了完善:

增加异常处理

由于爬取上百页的网页,中途很可能由于各种问题导致爬取失败,所以增加了 try except 、if 等语句,来处理可能出现的异常,让代码更健壮。

增加代码灵活性

初版代码由于固定了 URL 参数,所以只能爬取固定的内容,但是人的想法是多变的,一会儿想爬这个一会儿可能又需要那个,所以可以通过修改 URL 请求参数,来增加代码灵活性,从而爬取更灵活的数据。

修改存储方式

初版代码我选择了存储到 Excel 这种最为熟悉简单的方式,人是一种惰性动物,很难离开自己的舒适区。但是为了学习新知识,所以我选择将数据存储到 MySQL 中,以便练习 MySQL 的使用。

加快爬取速度

初版代码使用了最简单的单进程爬取方式,爬取速度比较慢,考虑到网页数量比较大,所以修改为了多进程的爬取方式。

经过以上这几点的完善,代码量从原先的 5 行增加到了下面的几十行:

import requestsimport pandas as pdfrom bs4 import BeautifulSoupfrom lxml import etreeimport timeimport pymysqlfrom sqlalchemy import create_enginefrom urllib.parse import urlencode # 编码 URL 字符串start_time = time.time() #计算程序运行时间def get_one_page(i): try: headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36' } paras = { 'reportTime': '2017-12-31', #可以改报告日期,比如2018-6-30获得的就是该季度的信息 'pageNum': i #页码 } url = 'http://s.askci.com/stock/a/?' + urlencode(paras) response = requests.get(url,headers = headers) if response.status_code == 200: return response.text return None except RequestException: print('爬取失败')def parse_one_page(html): soup = BeautifulSoup(html,'lxml') content = soup.select('#myTable04')[0] #[0]将返回的list改为bs4类型 tbl = pd.read_html(content.prettify(),header = 0)[0] # prettify()优化代码,[0]从pd.read_html返回的list中提取出DataFrame tbl.rename(columns = {'序号':'serial_number', '股票代码':'stock_code', '股票简称':'stock_abbre', '公司名称':'company_name', '省份':'province', '城市':'city', '主营业务收入(201712)':'main_bussiness_income', '净利润(201712)':'net_profit', '员工人数':'employees', '上市日期':'listing_date', '招股书':'zhaogushu', '公司财报':'financial_report', '行业分类':'industry_classification', '产品类型':'industry_type', '主营业务':'main_business'},inplace = True) return tbldef generate_mysql(): conn = pymysql.connect( host='localhost', user='root', password='******', port=3306, charset = 'utf8', db = 'wade') cursor = conn.cursor() sql = 'CREATE TABLE IF NOT EXISTS listed_company (serial_number INT(20) NOT NULL,stock_code INT(20) ,stock_abbre VARCHAR(20) ,company_name VARCHAR(20) ,province VARCHAR(20) ,city VARCHAR(20) ,main_bussiness_income VARCHAR(20) ,net_profit VARCHAR(20) ,employees INT(20) ,listing_date DATETIME(0) ,zhaogushu VARCHAR(20) ,financial_report VARCHAR(20) , industry_classification VARCHAR(20) ,industry_type VARCHAR(100) ,main_business VARCHAR(200) ,PRIMARY KEY (serial_number))' cursor.execute(sql) conn.close()def write_to_sql(tbl, db = 'wade'): engine = create_engine('mysql+pymysql://root:******@localhost:3306/{0}?charset=utf8'.format(db)) try: tbl.to_sql('listed_company2',con = engine,if_exists='append',index=False) # append表示在原有表基础上增加,但该表要有表头 except Exception as e: print(e)def main(page): generate_mysql() for i in range(1,page): html = get_one_page(i) tbl = parse_one_page(html) write_to_sql(tbl)# # 单进程if __name__ == '__main__': main(178) endtime = time.time()-start_time print('程序运行了%.2f秒' %endtime)# 多进程from multiprocessing import Poolif __name__ == '__main__': pool = Pool(4) pool.map(main, [i for i in range(1,178)]) #共有178页 endtime = time.time()-start_time print('程序运行了%.2f秒' %(time.time()-start_time))

进群获取更多项目源码以及教程:960410445

结语

这个过程觉得很自然,因为每次修改都是针对一个小点,一点点去学,搞懂后添加进来,而如果让你上来就直接写出这几十行的代码,你很可能就放弃了。

怎么批量下载上市公司的财报审计等报告资料?

如何用python爬取上市公司年报?

我们都知道,很多公司都会在自己的官网中设置专门的栏目(比如投资者关系一栏investor relations)来放置企业的财务报表等相关资料,投资者可以在上面查询下载。通过查找了解企业的财务报表,或通过其他公司公告来了解该公司的运营情况。

但是,少量公司的逐个去公司官网或证监会网站(sse.com.cn)查询没有问题,然而遇到大批量财务分析需求,那么这种办法就行不通了!时间成本和精力消耗是主要的考量。

如何用python爬取上市公司年报?

这样一来,对于这类有大批量资料需求的人来讲,掌握Python编程技能、或者短期就急需能够批量下载公司资料的网站渠道就成了必需。

在这里,根据我的研究经历, 推荐两个可行的方法和渠道:

靠前个就是小破站上大灯的Python视频教程,第二个就是财务室网(caiwushi.net)上已处理好的批量公司资料。

利用python+tushare+pandas进行财报分析

一、财报分析

大家在购买股票的时候,已经不只是凭感觉去买了,基本上都会对一个股票进行深入的分析。

毕竟购买股票还是一项风险性较高的投资,需要在较为熟悉以后才能去开展,不能蛮干,钱也都不是天上掉下来的。那么作为散户投资者,如何去分析一家企业的经营状况,基本上都是从从他们的财务报表入手,而且这些资料在上市公司的公告信息里都能查的到,这也是散户比较好的分析一家企业的支撑材料。

财报分析,一般是通过详细的阅读上市公司定期披露的季报、半年报、年报,了解其中各项信息进而进行深度分析,当然最终会利用分析结果去对股票进行较为准确的操作。

财报分析的对象是财务报表,财务报表主要包括三大报表,资产负债表、利润表、现金流量表。这三大报表分析,也会以关注主要项为主,如果能全面分析是较好:

1.获利能力分析:利润的高低、利润额的增长速度等。

2.偿债能力分析:短期偿债能力主要分析其变现能力即流动资产的分布、变动情况,确保投资的安全。具体从两个方面进行分析:长期偿债能力主要分析财务报表中权益项目之间、权益与收益之间、权益与资产之间的关系。

3.经营能力分析: 企业经营能力分析的主要指标是企业营运资产的效率与效益,主要是分析资产的周转率或周转速度,如存货、固定资产、应收账款等。

以上的各项分析,目前在各个股票软件里面都有比较好的数据了,但是也是因为其通用性,造成了按照自己的对比和查看不那么方便,今天我给大家介绍的是如何利用python+tushane+pandas获取三大报表的数据,进行个性化分析,这里我主要还是以介绍获取数据为主,具体的分析还要靠各位自行努力。

步长制药的财报数据(手机端)

如何用python爬取上市公司年报?

步长制药自分析图片

自己用数据进行的分析(只选择了一些项进行对比,有了数据以后,大家可以自行选择分析项)

二、数据获取

这些数据如何获取,当然有很多地方,可以下载财报,也可以自己输入,但是这些都比较慢,我利用python+tushare+pandas只需要几行代码就可以快速的获取,而且一旦写好一次后,后续想获取任意股票的数据,就非常方便了,而且我是把四张报表合并了分析(增加了软件里常用的财务主要指标表),大家也可以简单的,先分析一张报表。

以下是具体的代码,我做了说明,实际用到的代码非常少,真正有用的代码不超过20行.

'''

Author:唐朝品鉴

Date:2020年5月24日

获取指定公司的利润表、资产负债表、现金流量表

'''

import pandas as pd

import tushare as ts

from time import sleep

'''

下面是参数说明:

ts_code 股票代码

end_date 报告期

report_type 报表类型,1合并报表 2单季合并 3调整单季合并表 4调整合并报表 5调整前合并报表 6母公司报表 7母公司单季报 8 母公司调整单季表 9母公司调整表 10母公司调整前报表 11调整前合并报表 12母公司调整前报表

basic_eps 基本每股收益

diluted_eps 稀释每股收益

total_revenue 营业总收入

sell_exp 销售费用

admin_exp 管理费用

fin_exp 财务费用

total_profit 利润总额

income_tax 所得税费用

n_income 净利润(含少数股东损益)

'''

#这里是获取数据前的定义,方便修改,重复利用

#注册地址 https://tushare.pro/register?reg=365370

token='**这个需要大家去注册一个tushare,免费的,然后从后台获取**'

pro = ts.pro_api(token)

my_code='603858.SH'

fbegdate='20150101'

fenddate='20201231'

lrb_files='ts_code,end_date,report_type,basic_eps,diluted_eps,total_revenue,' \

'sell_exp,admin_exp,fin_exp,total_profit,income_tax,n_income'

zcfzb_files='ts_code,end_date,report_type,money_cap,notes_receiv,accounts_receiv,oth_receiv,inventories,total_cur_assets,' \

'cip,r_and_d,total_assets,total_cur_liab,total_liab,minority_int'

xjllb_files='ts_code,end_date,report_type,net_profit,finan_exp,c_fr_sale_sg,c_inf_fr_operate_a,c_paid_to_for_empl,' \

'st_cash_out_act,n_cashflow_act,n_cashflow_inv_act,n_cash_flows_fnc_act'

cwzb_files='ts_code,end_date,' \

'profit_dedt,gross_margin,inv_turn,ar_turn,ca_turn,fa_turn,assets_turn,fcff,' \

'ocfps,netprofit_margin,grossprofit_margin,cogs_of_sales,expense_of_sales,roe,' \

'roe_yearly,debt_to_assets,fixed_assets,rd_exp'

#下面是利用代码,获取网上数据

while True:

try:

#利润表

lr_df = pro.income(ts_code=my_code, start_date=fbegdate, end_date=fenddate,fields=lrb_files)

sleep(2)

#资产负债表

zcfz_df = pro.balancesheet(ts_code=my_code, start_date=fbegdate, end_date=fenddate,fields=zcfzb_files)

sleep(2)

#现金流量表

xjll_df = pro.cashflow(ts_code=my_code, start_date=fbegdate, end_date=fenddate, fields=xjllb_files)

sleep(2)

#财务主要指标表

cwzb_df = pro.fina_indicator(ts_code=my_code, start_date=fbegdate, end_date=fenddate,fields=cwzb_files)

sleep(2)

break

except Exception as e:

print(e)

continue

# 这里是利用年月日的时间生成,年、季度列;**指定列,0表示靠前列,即生成年度列和季度列

lr_df.insert(2, 'fyear',lr_df['end_date'].str[0:4])

lr_df.insert(3,'fperiod',lr_df['end_date'].str[4:6])

#利用drop_duplicates删除重复行

nlr_df=lr_df.drop_duplicates(subset=['ts_code','end_date','report_type'], keep='first')

nzcfz_df=zcfz_df.drop_duplicates(subset=['ts_code','end_date','report_type'], keep='first')

nxjll_df=xjll_df.drop_duplicates(subset=['ts_code','end_date','report_type'], keep='first')

ncwzb_df=cwzb_df.drop_duplicates(subset=['ts_code','end_date'], keep='first')

hz_df1=pd.merge(nlr_df,nzcfz_df,on=['ts_code','end_date'])

hz_df2=pd.merge(hz_df1,nxjll_df,on=['ts_code','end_date'])

hz_df3=pd.merge(hz_df2,ncwzb_df,on=['ts_code','end_date'])

#以下是我用来重命名,改成中文的主要为了方便,所以有点长,其实可以省略的

def renname(df):

i = 0 # 用i的目的是区别,列名重复的问题,确保重命名后不重复,为删除列做好准备

# 获取列名

for column in df.iloc[:,:]:

# 用i的目的是区别,列名重复的问题,确保重命名后不重复,为删除列做好准备

print(column)

i = i + 1

if column == 'ts_code':

newname = '股票代码'

elif column == 'end_date':

newname='时间'

elif column== 'fyear':

newname='年度'

elif column == 'fperiod':

newname='月份'

elif column == 'report_type_x':

newname='利润表类型'

elif column == 'basic_eps':

newname='基本每股收益'

elif column == 'diluted_eps':

newname='稀释每股收益'

elif column == 'total_revenue':

newname='营业总收入'

elif column == 'sell_exp':

newname='销售费用'

elif column == 'admin_exp':

newname='管理费用'

elif column == 'fin_exp':

newname='财务费用'

elif column == 'total_profit':

newname='利润总额'

elif column == 'income_tax':

newname='所得税费用'

elif column == 'n_income':

newname='净利润(含少数股东损益)'

elif column == 'report_type_y':

newname='资产负债表类型'

elif column == 'money_cap':

newname = '货币资金'

elif column == 'notes_receiv':

newname='应收票据'

elif column == 'accounts_receiv':

newname='应收账款'

elif column == 'oth_receiv':

newname='其他应收款'

elif column == 'inventories':

newname='存货'

elif column == 'total_cur_assets':

newname='流动资产合计'

elif column == 'cip':

newname='在建工程'

elif column == 'r_and_d':

newname='研发支出'

elif column == 'total_assets':

newname='资产总计'

elif column == 'total_cur_liab':

newname='流动负债合计'

elif column == 'total_liab':

newname='负债合计'

elif column == 'minority_int':

newname='少数股东权益'

elif column == 'report_type':

newname='现金流量表类型'

elif column == 'net_profit':

newname='净利润'

elif column == 'finan_exp':

newname='(现)财务费用'

elif column == 'c_fr_sale_sg':

newname='销售商品、提供劳务收到的现金'

elif column == 'c_inf_fr_operate_a':

newname='经营活动现金流入小计'

elif column == 'c_paid_to_for_empl':

newname='支付给职工以及为职工支付的现金'

elif column == 'st_cash_out_act':

newname='经营活动现金流出小计'

elif column == 'n_cashflow_act':

newname='经营活动产生的现金流量净额'

elif column == 'n_cashflow_inv_act':

newname='投资活动产生的现金流量净额'

elif column == 'n_cash_flows_fnc_act':

newname='筹资活动产生的现金流量净额'

elif column == 'profit_dedt':

newname='扣除非经常性损益后的净利润'

elif column == 'gross_margin':

newname='毛利'

elif column == 'inv_turn':

newname='存货周转率'

elif column == 'ar_turn':

newname='应收账款周转率'

elif column == 'ca_turn':

newname='流动资产周转率'

elif column == 'fa_turn':

newname='固定资产周转率'

elif column == 'assets_turn':

newname='总资产周转率'

elif column == 'fcff':

newname='企业自由现金流量'

elif column == 'ocfps':

newname='每股经营活动产生的现金流量净额'

elif column == 'netprofit_margin':

newname='销售净利率'

elif column == 'grossprofit_margin':

newname='销售毛利率'

elif column == 'cogs_of_sales':

newname='销售成本率'

elif column == 'expense_of_sales':

newname='销售期间费用率'

elif column == 'roe':

newname='净资产收益率'

elif column == 'roe_yearly':

newname='年化净资产收益率'

elif column == 'debt_to_assets':

newname='资产负债率'

elif column == 'fixed_assets':

newname='固定资产合计'

elif column == 'rd_exp':

newname='研发费用'

else:

newname=column

# df=df.drop([column],axis=1, inplace=True) #根据列名删除该列

df.rename(columns={column: str(newname)}, inplace=True)

return df

#这里是调用了重命名函数,也可以不用的

renname(hz_df3)

#把结果保存的excel,备用

hz_df3.to_excel('F:/python_analyze/%s_cbhz.xlsx'%my_code)

以上就是如何用python爬取上市公司年报?的详细内容,希望通过阅读小编的文章之后能够有所收获!

版权:本文由用户自行上传,观点仅代表作者本人,本站仅供存储服务。如有侵权,请联系管理员删除,了解详情>>

发布
问题