期末大作业:年报分析

姓名 性别 学号
张佳静 0194966

导入模块

In [7]:
import re
import requests
import pandas as pd
import openpyxl
import time
import os
import matplotlib.pyplot as plt
import numpy as np
import fitz

导入行业年报(以化学原料行业为例)

In [2]:
xlsx = '化学原料行业.xlsx'
df = pd.read_excel(xlsx)
exf = openpyxl.load_workbook(xlsx)  #工作簿
sheet = exf.active  #获取当前正在处理的表格
C2 = sheet['C2']  #excel定位
C = sheet['C']

links = [c.value for c in C]
links_1 = links[1:-1]
links_2 = ''.join(links_1)  #转化成文本 可加‘\n’换行符
p = re.compile('"(.*?)","(.*?)"')
list_of_tuple = p.findall(links_2)

df2 = pd.DataFrame({'link':[t[0] for t in list_of_tuple],
                    'f_name':[t[1] for t in list_of_tuple]})
df2.to_csv('化学原料行业.csv')

读入行业年报

In [3]:
f = open('化学原料行业.csv',encoding='utf-8')
df1 = pd.read_csv(f)
links = df1['link']; f_names = df1['f_name']

# f_names = [re.sub('_','',f) for f in f_names] #删去
# f_names_2 = [re.sub('600\d\d\d','',f) for f in f_names]
def filter_links(words,df,include=True):
    ls = []
    for word in words:
        if include:
            ls.append([word in f for f in df.f_name])
        else:
            ls.append([word not in f for f in df.f_name])
    index = []
    for r in range(len(df)):
        flag = not include
        for c in range(len(words)):
            if include:
                flag = flag or ls[c][r]
            else:
                flag = flag and ls[c][r]
        index.append(flag)
    df2 = df[index]
    return(df2)

df_all = filter_links(['摘要','问询函','社会责任'],df2,include=False)
df_updt = filter_links(['取消'],df_all,include=False)
df_orig = filter_links(['(','('], df_all,include=False)
df_updt = filter_links(['(','('],df_all,include=True)
df_updt = filter_links(['取消'],df_updt,include=False)

更新年报

In [9]:
def sub_with_update(df_updt,df_orig): # 定义函数
    df_newest = df_orig.copy() # 先对年报进行复制
    index_orig = []
    index_updt = []
    for i,f in enumerate(df_orig.f_name):
        for j,fn in enumerate(df_updt.f_name):
            if f in fn:  
                index_orig.append(i)
                index_updt.append(j)        
    #return((index_orig,index_updt))
    for n in range(len(index_orig)):
        i = index_orig[n]
        j = index_updt[n]
        df_newest.iloc[i,-2] = df_updt.iloc[j,-2]
        #df_newest.iloc[i,-1] = df_updt.iloc[j,-1]
    return(df_newest)

df_newest = sub_with_update(df_updt,df_orig)
print(df_newest)
                                                  link  \
4    http://news.windin.com/ns/bulletin.php?code=B5...   
6    http://news.windin.com/ns/bulletin.php?code=A1...   
8    http://news.windin.com/ns/bulletin.php?code=B1...   
10   http://news.windin.com/ns/bulletin.php?code=B9...   
12   http://news.windin.com/ns/bulletin.php?code=B3...   
15   http://news.windin.com/ns/bulletin.php?code=BA...   
16   http://news.windin.com/ns/bulletin.php?code=DF...   
18   http://news.windin.com/ns/bulletin.php?code=56...   
20   http://news.windin.com/ns/bulletin.php?code=D6...   
22   http://news.windin.com/ns/bulletin.php?code=B8...   
23   http://news.windin.com/ns/bulletin.php?code=B1...   
25   http://news.windin.com/ns/bulletin.php?code=CD...   
27   http://news.windin.com/ns/bulletin.php?code=49...   
29   http://news.windin.com/ns/bulletin.php?code=A4...   
31   http://news.windin.com/ns/bulletin.php?code=EC...   
35   http://news.windin.com/ns/bulletin.php?code=77...   
37   http://news.windin.com/ns/bulletin.php?code=24...   
39   http://news.windin.com/ns/bulletin.php?code=1B...   
41   http://news.windin.com/ns/bulletin.php?code=61...   
43   http://news.windin.com/ns/bulletin.php?code=EA...   
45   http://news.windin.com/ns/bulletin.php?code=3D...   
47   http://news.windin.com/ns/bulletin.php?code=D5...   
49   http://news.windin.com/ns/bulletin.php?code=28...   
52   http://news.windin.com/ns/bulletin.php?code=4A...   
54   http://news.windin.com/ns/bulletin.php?code=8A...   
55   http://news.windin.com/ns/bulletin.php?code=BC...   
57   http://news.windin.com/ns/bulletin.php?code=C1...   
59   http://news.windin.com/ns/bulletin.php?code=DE...   
62   http://news.windin.com/ns/bulletin.php?code=44...   
64   http://news.windin.com/ns/bulletin.php?code=12...   
..                                                 ...   
437  http://news.windin.com/ns/bulletin.php?code=BD...   
440  http://news.windin.com/ns/bulletin.php?code=AD...   
441  http://news.windin.com/ns/bulletin.php?code=AD...   
443  http://news.windin.com/ns/bulletin.php?code=BD...   
445  http://news.windin.com/ns/bulletin.php?code=B7...   
447  http://news.windin.com/ns/bulletin.php?code=97...   
449  http://news.windin.com/ns/bulletin.php?code=91...   
451  http://news.windin.com/ns/bulletin.php?code=60...   
453  http://news.windin.com/ns/bulletin.php?code=FE...   
456  http://news.windin.com/ns/bulletin.php?code=9F...   
457  http://news.windin.com/ns/bulletin.php?code=A5...   
459  http://news.windin.com/ns/bulletin.php?code=58...   
461  http://news.windin.com/ns/bulletin.php?code=A6...   
463  http://news.windin.com/ns/bulletin.php?code=D7...   
465  http://news.windin.com/ns/bulletin.php?code=9E...   
467  http://news.windin.com/ns/bulletin.php?code=78...   
470  http://news.windin.com/ns/bulletin.php?code=67...   
471  http://news.windin.com/ns/bulletin.php?code=55...   
473  http://news.windin.com/ns/bulletin.php?code=05...   
475  http://news.windin.com/ns/bulletin.php?code=15...   
477  http://news.windin.com/ns/bulletin.php?code=C9...   
481  http://news.windin.com/ns/bulletin.php?code=0C...   
483  http://news.windin.com/ns/bulletin.php?code=68...   
485  http://news.windin.com/ns/bulletin.php?code=E8...   
487  http://news.windin.com/ns/bulletin.php?code=9B...   
489  http://news.windin.com/ns/bulletin.php?code=5A...   
492  http://news.windin.com/ns/bulletin.php?code=AF...   
493  http://news.windin.com/ns/bulletin.php?code=B0...   
494  http://news.windin.com/ns/bulletin.php?code=92...   
495  http://news.windin.com/ns/bulletin.php?code=BB...   

                             f_name  
4                    延安必康:2020年年度报告  
6                  太化股份:2020年年度报告全文  
8                    金浦钛业:2020年年度报告  
10                   ST亚星:2020年年度报告  
12                   ST明科:2020年年度报告  
15                   苏盐井神:2020年年度报告  
16                   世龙实业:2020年年度报告  
18                   天原股份:2020年年度报告  
20                   金牛化工:2020年年度报告  
22                    新金路:2020年年度报告  
23                       新金路:年报财务报表  
25                   凯美特气:2020年年度报告  
27                   华软科技:2020年年度报告  
29                   科隆股份:2020年年度报告  
31                   远兴能源:2020年年度报告  
35                   洪汇新材:2020年年度报告  
37                   百川股份:2020年年度报告  
39                   君正集团:2020年年度报告  
41                   中核钛白:2020年年度报告  
43                   和邦生物:2020年年度报告  
45                   大洋生物:2020年年度报告  
47                   江苏索普:2020年年度报告  
49                    新疆天业:2020年度报告  
52                   屹通新材:2020年年度报告  
54                   怡达股份:2020年年度报告  
55           中盐化工:600328_2020年_年度报告  
57                   航锦科技:2020年年度报告  
59                   联瑞新材:2020年年度报告  
62                   奥克股份:2020年年度报告  
64                   江天化学:2020年年度报告  
..                              ...  
437                  宏达新材:2017年年度报告  
440                  雅克科技:2017年年度报告  
441              雅克科技:2017年年度年报审计报告  
443                  嘉化能源:2017年年度报告  
445  嘉化能源:绿色公司债券绿色项目进展及环境效益2017年度报告  
447                  井神股份:2017年年度报告  
449                  振华股份:2017年年度报告  
451                  晶瑞股份:2017年年度报告  
453                   新宙邦:2017年年度报告  
456                  亚星化学:2017年年度报告  
457                   云天化:2017年年度报告  
459                  兰太实业:2017年年度报告  
461                  氯碱化工:2017年年度报告  
463                  湘潭电化:2017年年度报告  
465                  红星发展:2017年年度报告  
467                  万华化学:2017年年度报告  
470                  滨化股份:2017年年度报告  
471                  山东海化:2017年年度报告  
473                  回天新材:2017年年度报告  
475                  中泰化学:2017年年度报告  
477                  永太科技:2017年年度报告  
481                  金禾实业:2017年年度报告  
483                  远兴能源:2017年年度报告  
485                  方大化工:2017年年度报告  
487                  和邦生物:2017年年度报告  
489                  金牛化工:2017年年度报告  
492                  ST南化:2017年年度报告  
493                *ST三维:2016年报审计报告  
494                *ST三维:2014年报审计报告  
495                *ST三维:2015年报审计报告  

[228 rows x 2 columns]

将年报按数目进行排序

In [10]:
df_newest.sort_values(by=['f_name'],inplace=True)
df_newest['公司简称'] = [f[:4] for f in df_newest.f_name]

counts = df_newest['公司简称'].value_counts()

ten_company = []
for cn in counts.index[:10]:
    ten_company.append(filter_links([cn], df_newest))
    
if not os.path.exists('10companies'): # 创建文件夹
    os.makedirs('10companies')
    
for df_com in ten_company:
    cn = df_com['公司简称'].iloc[0]
    df_com.to_csv('10companies/%s.csv' % cn)
ten_csv = os.listdir('10companies')

print(ten_csv)
['ST南化.csv', '三孚股份.csv', '中泰化学.csv', '丰元股份.csv', '凯美特气.csv', '延安必康.csv', '振华股份.csv', '新疆天业.csv', '洪汇新材.csv', '红星发展.csv']

下载年报PDF

In [11]:
def extract_links(t):
    f = open(t,encoding='utf-8')
    df_final_links = pd.read_csv(f)
    links = df_final_links['link']
    return(links)
links_company = []
for i in range(len(ten_csv)): #提取年报数目前10的公司的年报链接
    links_single = extract_links(ten_csv[i])
    links_single = list(links_single)
    links_company.append(links_single)

def get_PDF_url(url):
    r=requests.get(url);r.encoding='utf=8';html=r.text
    r.close()
    p=re.compile('<a href=(.*?)\s.*?>(.*?)</a>',re.DOTALL)
    a=p.search(html) #因第一个<a>即是目标标签,故用search
    if a is None:
        Warning('没有找到下载链接。请手动检查链接:%s'%url)
        return()
    else:
        href=a.group(1); fname=a.group(2).strip()
    href=r.url[:26]+href #形成完整链接
    return((href,fname))

for i in range(len(links_company)):
    for link in links_company[i]:
        href,fname = get_PDF_url(link)
        r = requests.get(href,allow_redirects=True)
        open('%s' %fname,'wb').write(r.content) #'wb'二进制
        r.close()

提取营业收入

In [13]:
filenames = os.listdir() #把代码所在文件夹的所有文件和文件名查找出来
pdf_list = [f for f in filenames if f.endswith('.pdf')]  #将年报查找出来

def extract_data(pdf): #定义抓取营业收入数据函数
    idx = pdf.find('20')
    company_name = pdf[0:idx]
    year = pdf[idx:idx+4]
    #
    doc = fitz.open(pdf)
    text = [page.get_text() for page in doc]
    text = ''.join(text)
    #
    p_s = re.compile(r'(?<=\n)\w{1,2}、.*?会计数据和财务指标\s*?(?=\n)')
    section_match = p_s.search(text)
    s_idx = section_match.start()
    #
    p = re.compile('营业收入(.*?)归属于',re.DOTALL)
    data_line = p.search(text[s_idx:]).group()
    data_line = data_line.replace('\n', '')
    p_digit = re.compile(r'(-)?\d[,0-9]*?\.\d{1,2}')
    revenue = p_digit.search(data_line).group()
    return((company_name,year,revenue))

#创建新DataFrame进行组合
companies, years, revenues = [],[],[]
for pdf in pdf_list:
    company, year, revenue = extract_data(pdf)
    companies.append(company)
    years.append(year)
    revenues.append(revenue)

df = pd.DataFrame({'company': companies,
                  'year': years,
                  'revenue': revenues})
df.sort_values(by=['year'],inplace=True) #将各年年报按年份排序

#统一年报公司名称
df['company'] = [re.sub('股份有限公司','',f) for f in df['company']]
df['company'] = [re.sub('60\d\d\d\d','',f) for f in df['company']]
df['company'] = [re.sub(':','',f) for f in df['company']]

df['revenue'] = [re.sub(',','',f) for f in df['revenue']] #除去revenue的逗号
df['revenue'] = pd.to_numeric(df['revenue']) #将revenue的object格式转化为float格式

print(df)
   company  year       revenue
0     新疆天业  2017  4.977163e+09
16    三孚股份  2017  1.074166e+09
12    振华股份  2017  1.185480e+09
24    丰元股份  2017  3.209092e+08
8     红星发展  2017  1.335084e+09
35    洪汇新材  2017  3.885001e+08
20    中泰化学  2017  4.105903e+10
4     ST南化  2017  2.141563e+08
28    凯美特气  2017  4.282858e+08
5     ST南化  2018  2.754416e+08
9     红星发展  2018  1.593039e+09
21    中泰化学  2018  7.022263e+10
36    洪汇新材  2018  5.183070e+08
13    振华股份  2018  1.404864e+09
32    延安必康  2018  8.446807e+09
29    凯美特气  2018  5.045597e+08
1     新疆天业  2018  4.827760e+09
17    三孚股份  2018  1.103852e+09
25    丰元股份  2018  2.648109e+08
22    中泰化学  2019  8.311989e+10
26    丰元股份  2019  4.579660e+08
33    延安必康  2019  9.328179e+09
18    三孚股份  2019  1.156606e+09
14    振华股份  2019  1.395222e+09
10    红星发展  2019  1.523390e+09
6     ST南化  2019  6.685268e+08
2     新疆天业  2019  4.503738e+09
37    洪汇新材  2019  5.379710e+08
30    凯美特气  2019  5.145274e+08
34    延安必康  2020  6.953408e+09
31    凯美特气  2020  5.187532e+08
19    三孚股份  2020  1.006252e+09
23    中泰化学  2020  8.419702e+10
15    振华股份  2020  1.278418e+09
11    红星发展  2020  1.377647e+09
7     ST南化  2020  7.284210e+08
3     新疆天业  2020  8.992580e+09
27    丰元股份  2020  3.572639e+08
38    洪汇新材  2020  5.447160e+08

绘图分析

In [16]:
def image(d): #定义函数
    d1=df[df['company']==d] #定位公司名称
    fig=plt.figure()
    revenue=d1['revenue'] #以营业收入为纵坐标
    df['revenue'] = pd.to_numeric(df['revenue'])
    year = d1['year'] #以年份为横坐标
    ax1=plt.subplot(211)
    ax1.plot(year,revenue,color='g')
    ax1.set_ylabel('revenue')
    ax1.set_title('revenue')
    ax1.grid(True,axis='both')

ST南化

In [17]:
image('ST南化')

据图分析,ST南化的营业收入在近四年呈增长型,平均收入规模为5亿左右

三孚股份

In [18]:
image('三孚股份')

据图分析,三孚股份近四年营业收入状况为:2019年达到四年最高点,为11.5亿;但其后一年的营业收入为四年最低(10亿)

新疆天业

In [19]:
image('新疆天业')

据图分析,新疆天业近四年营业收入状况为:2020年达到四年最高点,超过80亿

红星发展

In [20]:
image('红星发展')

据图分析,红星发展的营业收入状况为:2018年达到四年最高点,为16亿;其后两年一直下下跌,最近一年(2020年)跌落14亿,但仍未低于四年最低点

振华股份

In [21]:
image('振华股份')

据图分析,最近一年(2020年)振兴股份的营业收入大致位于四年平均线处,规模为13亿左右

丰元股份

In [22]:
image('丰元股份')

据图分析,四年内丰元股份的营业收入呈现出上下波动趋势,2018年为四年最低,2019年则增为最高

洪汇新材

In [23]:
image('洪汇新材')

洪汇新材近四年营业收入持续增长,但增长率呈现出下跌趋势,最近一年(2020年)的收入规模为5.5亿

凯美特气

In [24]:
image('凯美特气')

凯美特气近四年营业收入持续增长,但增长率呈现出下跌趋势,最近一年(2020年)的收入规模为5亿

延安必康

In [25]:
image('延安必康')

延安必康近三年的营业收入规模最高超过90亿,最低则达到70亿

中泰化学

In [26]:
image('中泰化学')

中泰化学近四年营业收入持续增长,但增长率呈现出下跌趋势,最近一年(2020年)的收入规模为800亿

实验中出现的错误

  • 没有正确选择处理文件夹
  • 下载年报链接时link选择错误,将该行业所有年报均下载下来了,处理措施是定义extract_links函数
In [ ]: