1 目录解析

虽然许多年报具有书签,不过一些页码并不准确。每一份年报,内容里都包含目录页,但还是有一些页码不准。所以,有必要写一些代码,来识别出正确的包含页码的目录信息。

1.2 代码

import re
import fitz

# pdf = '下载的年报.pdf'
pdf = '2021-03-18-002352.SZ-顺丰控股_2020年年度报告.pdf' # 须和代码文件在同一文件夹
doc = fitz.open(pdf)
toc_bookmarks = doc.get_toc()

def getText(pdf):
    text = ''
    doc = fitz.open(pdf)
    for page in doc:
        text += page.get_text()
    doc.close()
    return(text)

def getTOC_level1(headings,pdf):
    doc = fitz.open(pdf)
    toc = []
    for page in doc:
        text = page.get_text()
        pageNo = page.number
        if len(text) > 100:
            continue
        text = re.sub('\s', '', text)
        for heading in headings:
            title = re.sub('\s', '', heading[1])
            if re.search(title, text):
                toc.append([1,heading[0],title,pageNo])
                break
    return(toc)

def getTOC(pdf,level=2):
    # text = getText(pdf)
    if level not in [1,2,3]:
        raise ValueError("level 应该为 1、2、3")
    toc = []
    doc = fitz.open(pdf)
    # 需要排除目录页的干扰。
    p_tocpage = re.compile('(?<=\\n)\s*目录\s*(?=\\n)')
    for page in doc:
        text = page.get_text()
        if p_tocpage.search(text):
            pageNo_toc = page.number        
            break
    # 需要剔除审计报告影响
    # 三级目录
    p_level_1 = re.compile('(第\w{1,2}节)\s+([\w、,]*)')
    p_level_2 = re.compile('([一二三四五六七八九十]{1,2})、\s*(.*)')
    p_level_3 = re.compile('(\d{1,2})、\s*(.*)')
    for page in doc:
        text = page.get_text()
        pageNo = page.number # 注意从0开始
        if pageNo == pageNo_toc:
            # 解析目录页
            headings = p_level_1.findall(text)
            continue
        lines = text.splitlines()
        lines = [l.strip() for l in lines if l.strip() != '']
        for line in lines:
            match1 = p_level_1.match(line)
            if match1:
                toc.append([1,match1.group(1),match1.group(2),pageNo])
            if level >= 2:
                match2 = p_level_2.match(line)
                if match2:
                    toc.append([2,match2.group(1),match2.group(2),pageNo])
            if level == 3:
                match3 = p_level_3.match(line)
                if match3:
                    toc.append([3,match3.group(1),match3.group(2),pageNo])
    # 以上对顺丰控股2020年报不适用
    toc_1 = [c for c in toc if c[0] == 1]
    if len(toc_1) < 10:
        # above is failed
        toc = getTOC_level1(headings, pdf)
    return((toc,headings))

toc,headings = getTOC(pdf,level=2)
text = getText(pdf)

1.3 结果分析

年报准备的再仔细都可能有错!

顺丰控股的年报,已经是制作的非常精美了,不过并没有书签信息,而且也出了一个错误,即第一节节标题错用了“及”,而不是正确的“和”

  • 正文页截图