王誉同的实验报告

目录

1.find your assignment点击跳转

2.获取年报点击跳转

3.获取年报各项信息点击跳转

4.绘图点击跳转

5.实验心得点击跳转

代码 PART1

find your assignment


import fitz
import re
import pandas as pd

#判断行业中上市公司个数是否满足大于等于10的要求
def does_match(text):
    if len(re.findall('\n\d{6}\n',text)) < 10:
        return False
    else:
        return True


def find_assignment(No,num): 
    #No为int类型,表示在本次作业中该学生的序号
    #num代表该行业前num家上市公司
        
        #读取所有的内容
    text = ''
    with fitz.open('../1638277734844_11692.pdf') as doc:
        for page in doc:
            text = text + page.get_text('text')
        
    #找到所有行业的两位代码
    locs = re.finditer('\n\d{2}\n',text)
    
    #注意locs里面可能有重复的行业标号,需要筛选一下
    loc_dict = {}
    for loc in locs:
        #loc.span()的结果为左开右闭的区间,去除两端的换行符
        s = loc.span()[0] + 1
        e = loc.span()[1] - 1
        if text[s:e] in loc_dict:
            continue
        else:
            loc_dict[text[s:e]] = [s,e]
    
    #获取有效行业(上市公司>=10),将他们放入列表effective_industries中,

    last_key = '' #保存上一次循环中的key
    last_value = 0 #保存上一次循环中的value[1],即行业代码的索引的后一位置(为换行符)
    effective_industries = []
    for key,value in loc_dict.items():
        
        if key != '01':
            subtext = text[last_value:value[0]]
            if does_match(subtext) == False:
                last_key = key
                last_value = value[1]
                continue
            else:
                effective_industries.append(last_key)   
        #第一个的key必定是01,所以第一次循环直接跳到这一步
        last_key = key
        last_value = value[1]
        
    #注意,最后还剩下一部分没循环到
    subtext = text[last_value:len(text)]
    if does_match(subtext) == True:
        effective_industries.append(key)
    
    #判断No匹配哪个行业
    #可能会出现No超过了有效行业数,故采用模运算
    No = No % len(effective_industries)
    
    my_industry = effective_industries[No-1] 
    
    print('第'+ str(No) + '号的作业是行业 ' + my_industry)
    
    '''
    附加代码,找到自己的行业包含的所有公司代码,以列表返回
    '''

    s = loc_dict.get(my_industry)[1]
    
    #获得下一个键值对,如'01'之后为'02'
    if int(my_industry) < 9:
        nxt = '0' + str(int(my_industry) + 1)
    elif int(my_industry) == 9:
        nxt = '10'
    else:
        nxt = str(int(my_industry) + 1)
    e = loc_dict.get(nxt)[0]
    
    subtext = text[s:e]
    
    code_list = re.findall('\n\d{6}\n',subtext)
    code_list = [code.strip() for code in code_list]
    
    '''
    附加代码,找到自己的行业包含的所有公司名称,以列表返回
    '''
    name_list = []
    
    for code in code_list:
        code_first_loc = subtext.find(code)
        start = code_first_loc + 7
        end = subtext.find('\n', start)
        
        name = subtext[start : end]
        name_list.append(name)
    
    '''
    把公司代码code_list和公司名称name_list合并成dataframe
    '''
    df = {'code_list':code_list[0:num], 'name_list':name_list[0:num]}
    df = pd.DataFrame(df)
    
return df


代码PART2

获取年报


import json
import os
from time import sleep
from urllib import parse
import requests
import time
import random
from fake_useragent import UserAgent
import pdfplumber

ua = UserAgent()
userAgen = ua.random

def get_adress(bank_name):
    url = "http://www.cninfo.com.cn/new/information/topSearch/detailOfQuery"
    data = {
        'keyWord': bank_name,
        'maxSecNum': 10,
        'maxListNum': 5,
    }
    hd = {
        'Host': 'www.cninfo.com.cn',
        'Origin': 'http://www.cninfo.com.cn',
        'Pragma': 'no-cache',
        'Accept-Encoding': 'gzip,deflate',
        'Connection': 'keep-alive',
        'Content-Length': '70',
        'User-Agent': userAgen,
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Accept': 'application/json,text/plain,*/*',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
    }
    get_json = requests.post(url, headers=hd, data=data)
    data_json = get_json.content
    toStr = str(data_json, encoding="utf-8")
    last_json = json.loads(toStr)
    orgId = last_json["keyBoardList"][0]["orgId"]  # 获取参数
    plate = last_json["keyBoardList"][0]["plate"]
    code = last_json["keyBoardList"][0]["code"]
    return orgId, plate, code

def download_PDF(url, file_name):  # 下载pdf
    url = url
    r = requests.get(url)
    f = open(company + "/" + file_name + ".pdf", "wb")
    f.write(r.content)
    f.close()

def get_PDF(orgId, plate, code):
    url = "http://www.cninfo.com.cn/new/hisAnnouncement/query"
    data = {
        'stock': '{},{}'.format(code, orgId),
        'tabName': 'fulltext',
        'pageSize': 20,
        'pageNum': 1,
        'column': plate,
        'category': 'category_ndbg_szsh;',
        'plate': '',
        'seDate': '',
        'searchkey': '',
        'secid': '',
        'sortName': '',
        'sortType': '',
        'isHLtitle': 'true',
    }

    hd = {
        'Host': 'www.cninfo.com.cn',
        'Origin': 'http://www.cninfo.com.cn',
        'Pragma': 'no-cache',
        'Accept-Encoding': 'gzip,deflate',
        'Connection': 'keep-alive',
        'User-Agent': ua.random,
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Accept': 'application/json,text/plain,*/*',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'X-Requested-With': 'XMLHttpRequest',
    }
    data = parse.urlencode(data)
    data_json = requests.post(url, headers=hd, data=data)
    toStr = str(data_json.content, encoding="utf-8")
    last_json = json.loads(toStr)
    reports_list = last_json['announcements']
    for report in reports_list:
        if '摘要' in report['announcementTitle'] or "20" not in report['announcementTitle']:
            continue
        if 'H' in report['announcementTitle']:
            continue
        else:  # http://static.cninfo.com.cn/finalpage/2019-03-29/1205958883.PDF
            pdf_url = "http://static.cninfo.com.cn/" + report['adjunctUrl']
            file_name = report['announcementTitle']
            print("正在下载:" + pdf_url, "存放在当前目录:/" + company + "/" + file_name)
            download_PDF(pdf_url, file_name)
            time.sleep(random.random()*3)

if __name__ == '__main__':
    company_list = ['000488','000815','001206','002012','002067','002078','002228','002303','002511','002521','002565',
                    '002799','002831','003006','300883','301009','301062','600103','600235','600308','600356','600433',
                    '600567','600793','600963','600966','603022','603165','603607','603687','603733','603863','605007',
                    '605009','605377','605500']
    for company in company_list:
        os.mkdir(company)
        orgId, plate,code = get_adress(company)
        get_PDF(orgId, plate, code)
        print("下载成功")
 


运行结果

年报1 年报2

代码 PART3

获取年报各项信息


import fitz  
import re  
import pandas as pd  
import os  
import matplotlib.pyplot as plt  
import matplotlib  
import numpy as np  



'''董秘信息、营业收入、办公地址'''



def getText(pdf):#定义函数获取文本  
  text = ''  
  doc = fitz.open(pdf)  
  for page in doc:  
      text += page.get_text()
  doc.close()  
  text = text.replace(" "," \n")  
  text = text.replace("\n\n","\n")
# 由于后续subp匹配过程中,有的数字后面没有换行符,无法成功进行非贪婪的匹配,所以通过文本内部符号替换  
  return(text)

path = 'D:\年报'     #年报所处路径  
全部文件 = os.listdir(r'D:\年报')  
#j=0 #用来控制for  
董秘信息 = pd.DataFrame()  
营业收入 = pd.DataFrame()  
收益 = pd.DataFrame()  
地址 = pd.DataFrame()  
网址 = pd.DataFrame()  
邮箱 = pd.DataFrame()  
for 年报 in range(len(全部文件)):  
    #j = j+1  
    # if j >5:  
    #   break  
    路径 = os.path.join(r'D:\年报',全部文件[年报])  
    text = getText(路径)
    # 匹配出董秘信息   
try:  
  p_site = re.compile('(?<=\n)\w*董事会秘书?\s?\n证券事务代表\s\n姓名?\s?\n?(.*?)\s?(?=\n)', re.DOTALL)  # 匹配出董事会秘书姓名  
  site1 = p_site.search(text).group(0)  
  p_site2 = re.compile(  
  '(?<=\n)\w*董事会秘书?\s?\n证券事务代表\s\n姓名?\s?\n?(.*?)\s?(?=电话)\s?\电话?\s\n?(.*?)(?=\n)', re.DOTALL)  
  site2 = p_site2.search(text).group(0)  
  len(site2)  
  董秘姓名 = site1[19:]  
  董秘电话 = site2[-13:]  
# print(pd.DataFrame(data = [董秘姓名,董秘电话],index = ['董秘姓名','董秘电话'],columns = [年报[7:11]]))  
  df = (pd.DataFrame(data = [董秘姓名,董秘电话],index = ['{年报}董秘姓名'.format(年报=全部文件[年报][:6]),'{年报}董秘电话'.format(年报=全部文件[年报][:6])],columns = [全部文件[年报][7:11]]))  
  董秘信息 = pd.concat([董秘信息,df],axis=1)  
  #print(董秘信息) 
  if 年报 != len(全部文件)-1:  
      if 全部文件[年报][:6] != 全部文件[年报+1][:6]:  
        董秘信息.to_excel(r'C:\Users\HI\Desktop\董秘信息汇总\{年报}董秘信息.xlsx'.format(年报=全部文件[年报][:6]))        #d  
        董秘信息 = pd.DataFrame()  
  else:  
     董秘信息.to_excel(r'C:\Users\HI\Desktop\董秘信息汇总\{年报}董秘信息.xlsx'.format(年报=全部文件[年报][:6]))  # d  
     董秘信息 = pd.DataFrame()  
except:  
  print(全部文件[年报],'董秘信息出错了')  
  pass  
    # 匹配出营业收入  
try:  
    # p_site = re.compile('(?<=\n)\w*营业收入?\s?\n?(.*?)\s?(?=\n)', re.DOTALL)  
    # site1 = p_site.search(text).group(0)  
    # 收入 = site1[5:]  
    #text = getText(r'F:\许晶作业\年报\601225-2014年度报告.pdf')  
    p_s = re.compile('(?<=\\n)[\D、]?\D*?主要\D*?数据和\D*?(?=\\n)(.*?)净利润', re.DOTALL)  
    txt = p_s.search(text).group(0)  
    p_site = re.compile('(?<=\n)\w*营业收入?\s?\n?(.*?)\s?(?=\n)', re.DOTALL)  
    site1 = p_site.search(txt).group(0)  
    收入 = site1[6:]  
    a = re.findall(r"\d+\.?\d*", site1)  
    收入 = ''.join(a)  
    收入 = 收入.replace(',','')  
    收入 = pd.to_numeric(收入)  
    if '单位:亿元' in txt:  
         收入 = 收入 * 1000000  
    elif '单位:万元' in txt:  
         收入 = 收入 * 10000  
    elif '单位:百万元' in txt:  
         收入 = 收入 * 1000000  
    elif '单位:千元' in txt:  
         收入 = 收入 * 1000  
    df = pd.DataFrame(data = [收入],index = ['{年报}收入'.format(年报 = 全部文件[年报][:6])],columns = [全部文件[年报][7:11]])  
     #print(df)  
    营业收入 = pd.concat([营业收入,df],axis=1)  
     #print(营业收入)  
    if 年报 != len(全部文件)-1:  
        if 全部文件[年报][:6] != 全部文件[年报+1][:6]:
           营业收入.to_excel(r'C:\Users\HI\Desktop\营业收入汇总\{年报}营业收入.xlsx'.format(年报=全部文件[年报][:6]))        #d  
           营业收入 = pd.DataFrame()  
    else:  
       营业收入.to_excel(r'C:\Users\HI\Desktop\营业收入汇总\{年报}营业收入.xlsx'.format(年报=全部文件[年报][:6]))  # d  
       营业收入 = pd.DataFrame()  
except:  
  print(全部文件[年报], '营业收入出错了')  
  营业收入 = pd.DataFrame()  
  pass 
    # 匹配出办公地址  
try:  
  p_site = re.compile('(?<=\n)\w*办公地址?\s?\n?(.*?)\s?(?=\n)', re.DOTALL)  
  site1 = p_site.search(text).group(0)  
  办公地址 = site1[8:]  
  df = pd.DataFrame(data = [办公地址],index = ['{年报}办公地址'.format(年报 = 全部文件[年报][:6])],columns = [全部文件[年报][7:11]])  
 # print(df)  
  地址 = pd.concat([地址,df],axis=1)  
 #print(地址)  
  if 年报 != len(全部文件)-1:  
      if 全部文件[年报][:6] != 全部文件[年报+1][:6]:  
          地址.to_excel(r'C:\Users\HI\Desktop\办公地址汇总\{年报}办公地址.xlsx'.format(年报=全部文件[年报][:6]))        #d  
          地址 = pd.DataFrame()  
  else:  
      地址.to_excel(r'C:\Users\HI\Desktop\办公地址汇总\{年报}办公地址.xlsx'.format(年报=全部文件[年报][:6]))  # d  
      地址 = pd.DataFrame()  
except:  
  print(全部文件[年报], '办公地址出错了')  
  pass  




'''电子邮箱、公司网址、每股收益'''



try:  
   p_site = re.compile('(?<=\n)\w*电子信箱?\s?\n?(.*?)\s?(?=\n)', re.DOTALL)  
   site1 = p_site.search(text).group(0)  
   电子信箱 = site1[6:]  
   df = pd.DataFrame(data = [电子信箱],index =  ['{年报}邮箱'.format(年报 = 全部文件[年报][:6])],columns = [全部文件[年报][7:11]])  
 #  print(df)  
   邮箱 = pd.concat([邮箱,df],axis=1)
         # print(邮箱)  
   if 年报 != len(全部文件)-1:  
       if 全部文件[年报][:6] != 全部文件[年报+1][:6]:  
          邮箱.to_excel(r'C:\Users\HI\Desktop\邮箱汇总\{年报}邮箱.xlsx'.format(年报=全部文件[年报][:6]))    #d  
          邮箱 = pd.DataFrame()  
   else:  
       邮箱.to_excel(r'C:\Users\HI\Desktop\邮箱汇总\{年报}邮箱.xlsx'.format(年报=全部文件[年报][:6]))  # d  
       邮箱 = pd.DataFrame()  
except:  
   print(全部文件[年报], '邮箱出错了')  
   pass  
  # 匹配出公司网址 
try:  
   p_site = re.compile('(?<=\n)\w*公司?网址\s?\n?(.*?)\s?(?=\n)', re.DOTALL)  
   p_site =  re.compile('(?<=\n)公司\w*网\s?址:?\s?\n?(.*?)\s?(?=\n)', re.DOTALL)  
   site1 = p_site.search(text).group(0)  
   公司网址 = site1[6:]  
   df = pd.DataFrame(data = [公司网址],index =  ['{年报}网址'.format(年报 = 全部文件[年报][:6])],columns = [全部文件[年报][7:11]])  
  # print(df)  
   网址 = pd.concat([网址,df],axis=1)  
  #print(网址)  
   if 年报 != len(全部文件)-1:  
       if 全部文件[年报][:6] != 全部文件[年报+1][:6]:  
          网址.to_excel(r'C:\Users\HI\Desktop\网址汇总\{年报}网址.xlsx'.format(年报=全部文件[年报][:6]))        #d  
          网址 = pd.DataFrame()  
   else:  
       网址.to_excel(r'C:\Users\HI\Desktop\网址汇总\{年报}网址.xlsx'.format(年报=全部文件[年报][:6]))  # d  
       网址 = pd.DataFrame()  
except:  
   print(全部文件[年报], '网址出错了')  
   pass  
 # 匹配出每股收益  
try:  
  # text = getText(r'F:\许晶作业\年报\601088-2020年度报告.pdf')  
   p_s = re.compile('(?<=\\n)[\D、]?\D*?主要\D*?数据和\D*?(?=\\n)(.*?)收益率', re.DOTALL)
   txt = p_s.search(text).group(0)  
   p_site = re.compile('(?<=\n)\w*基本每股(.*?)亏?损?\s?\n?(.*?)\s?(?=\n)\s?\n?(.*?)\s?(?=\n)', re.DOTALL)  
   site1 = p_site.search(txt).group(0)  
   if site1[:11] == '基本每股收益(元/股)' or site1[:11] == '基本每股收益(元/股)' or site1[:11] == '基本每股收益(元/股)':  
       每股收益 = site1[13:]  
   else:  
       每股收益 = site1[16:]  
  
   df = pd.DataFrame(data = [每股收益],index =  ['{年报}每股收益'.format(年报 = 全部文件[年报][:6])],columns = [全部文件[年报][7:11]])  
   #print(df)  
   收益 = pd.concat([收益,df],axis=1)  
   #print(收益)  
   if 年报 != len(全部文件)-1:  
      if 全部文件[年报][:6] != 全部文件[年报+1][:6]:  
         收益.to_excel(r'C:\Users\HI\Desktop\收益汇总\{年报}收益.xlsx'.format(年报=全部文件[年报][:6]))        #d  
         收益 = pd.DataFrame()  
   else:  
       收益.to_excel(r'C:\Users\HI\Desktop\收益汇总\{年报}收益.xlsx'.format(年报=全部文件[年报][:6]))  # d  
       收益 = pd.DataFrame()  
except:  
   print(全部文件[年报], '每股收益出错了')  
   收益 = pd.DataFrame()  
   pass  


年报数据(部分)

代码PART4

绘图


import matplotlib.pyplot as plt
import numpy as np
import tool

def draw_pics_twinx(df):
    
    plt.rcParams['figure.dpi'] = 200
    plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
    plt.rcParams['font.sans-serif'] = ['SimHei'] # 使图片显示中文
    
    
    x = df['year']
    tool.to_year_list(x)
    y_rt = df['营业收入']
    tool.to_num_list(y_rt)
    y_ni = df['净利润']
    tool.to_num_list(y_ni)
    
    fig = plt.figure()
    
    
    ax1 = fig.subplots()
    ax1.plot(x, y_rt,'steelblue',label="营业收入",linestyle='-',linewidth=2,
             marker='o',markeredgecolor='pink',markersize='2',markeredgewidth=2)
    
    ax1.set_xlabel('年份')
    ax1.set_ylabel('营业收入(单位:亿元)')
    for i in range(len(x)):
        plt.text(x[i],y_rt[i],(y_rt[i]),fontsize = '10')
    ax1.legend(loc = 6) 

    ax2 = ax1.twinx()
    ax2.plot(x, y_ni, 'orange',label = "归属于股东的净利润",linestyle='-',linewidth=2,
             marker='o',markeredgecolor='teal',markersize='2',markeredgewidth=2)
    
    ax2.set_ylabel('归属于股东的净利润(单位:亿元)')
    for i in range(len(x)):
        plt.text(x[i],y_ni[i],(y_ni[i]),fontsize = '10')
    ax2.legend(loc = 2)
    
    '''
    title部分必须放最后,否则会出现左边的y轴有重复刻度的问题
    '''
    title = df['name'][0] + '历年' + '财务数据'
    plt.title(title)
    
    plt.savefig('../pics/' + title + '.png')
    plt.show()


运行结果

晨鸣纸业历年财务数据 合兴包装历年财务数据 景兴纸业历年财务数据 凯恩股份历年财务数据 美利云历年财务数据 美盈森历年财务数据 齐峰新材历年财务数据 太阳纸业历年财务数据 依依股份历年财务数据 中顺洁柔历年财务数据

实验心得

当使用Python进行文本处理时,正则表达式是一个非常有用的工具。Python提供了re模块,该模块可以让我们使用正则表达式来快速地处理文本。 在实验中,我学习了如何使用re模块编写正则表达式。re模块提供了很多函数来处理正则表达式,例如match、search、findall等。我们可以使用这些函数来匹配文本,找到我们需要的内容。 其次,我学习了正则表达式的语法。正则表达式是一种强大的工具,但其语法比较复杂。例如,使用特殊字符来匹配文本、使用字符集和范围、使用量词和分组等。在实验中,我通过不断的尝试和调试,对正则表达式的语法有了更深入的认识。 最后,我也学习了如何在Python中使用正则表达式来完成实际的文本处理任务。例如,我用正则表达式来提取邮件地址、公司网址、每股收益等。这些任务都可以使用正则表达式来完成。 总的来说,通过这个实验,我对Python正则表达式有了更深入的认识。我学习了使用re模块、正则表达式的语法以及如何在Python中使用正则表达式来处理文本。这些知识对我今后的学习和工作都非常有用。 我也意识到了自己实力的不足,学艺不精,在以后的学习中我会不断深入去理解这门课所学到的知识

回到目录