从年度报告中删除/提取数字

问题描述 投票:0回答:1

简介:

嘿伙计们!

我的愿景是制作一个Python程序,可以深入研究(任何)公司的年度报告,然后提取与“关键字”(等收入、运营成本)相关的特定数字。我希望实现这一目标,因为我花了很多时间研究公司 - 并且希望使这个过程更加高效。提取数字后,我想将其保存在列表中,并在其他年份执行相同的操作。最后我可以比较每年的增长百分比。

在此示例中,我使用 ELKEM 公司及其 2015 年年度报告作为参考。 代码在底部给出!

主要思想是:

1.制作一个函数,可以找到前10页的“财务报表部分”在哪里的信息。这个间隔对于节省时间和优化代码的运行时间至关重要。保存步骤 2 的间隔。

2.制作一个从PDF中提取文本的函数。该函数使用点 1 的间隔作为给定字段,用于开始提取文本。

3.制作一个函数,可以提取正确页面的表格(格式是由单词和数字组成的行表格),然后将表格拆分为行。我感兴趣的数字将始终位于我的关键字的右侧。

  1. 仅返回关键字右侧的数字。

  2. 将号码添加到列表中(此步骤尚不重要,因为步骤 3 必须先工作!)

  3. 对明年的年度报告进行相同的流程

  4. 将所有数字添加到列表/数组后,计算公司每年的增长并将其返回给我。

问题:

在步骤 3 中,我的主要问题出现了:我找不到删除“注释部分列”的方法。注释部分在我想要的数字前面给了我一个额外的(不需要的)数字。返回的是一个不正确的输出。

因此我尝试了不同的方法来克服这个问题。我尝试过使用 CHATGPT 及其推荐 - 但没有任何运气。我尝试将带有关键字的页面转换为表格,然后将其提取。我尝试过使用 python 库将 PDF 页面视为图像。我尝试过单独提取数字等......

我陷入了第 3 步,如果不克服这一步,我就无法取得任何进展。

如果您有更好的策略来解决这个问题,我愿意改变解决方案。

代码:

仅当您将 pdf 文件保存在计算机本地时,该代码才有效。该文件夹的名称必须为 Annual_report,并且该文件夹中的每个 PDF 都必须遵循符号“report_year”,在我们的例子中,pdf 的名称为“report_2015.pdf”。

年报链接:https://www.elkem.com/investor/reports-and-presentations/ 我试图提取的信息/数字位于第 83 页。

import pdfplumber
import re
import glob

def find_table_page_number(pdf_path, target_text):
    with pdfplumber.open(pdf_path) as pdf:
        for page_num, page in enumerate(pdf.pages, start=1):
            text = page.extract_text()
            if re.search(rf"\b{target_text}\b", text, re.IGNORECASE):
                return page_num
    return None

def find_page_number_interval_with_text(pdf_path, target_text):
    with pdfplumber.open(pdf_path) as pdf:
        start_page, end_page = None, None
        for page_num, page in enumerate(pdf.pages, start=1):
            text = page.extract_text()
            match = re.search(rf"(\d+)\s+{target_text}\s+(\d+)", text, re.IGNORECASE)
            if match:
                left_number, right_number = int(match.group(1)), int(match.group(2))
                start_page = min(left_number, right_number)
                end_page = max(left_number, right_number)
                break
        return start_page, end_page

def extract_text_from_pdf(pdf_path, start_page, end_page, table_page_number):
    with pdfplumber.open(pdf_path) as pdf:
        pdf_text = ""
        for page_num in range(start_page, end_page + 1):
            page = pdf.pages[page_num - 1]
            if page_num == table_page_number:
                pdf_text += extract_table_from_page(page)
            else:
                pdf_text += page.extract_text()
    return pdf_text

def extract_table_from_page(page):
    table_data = []

    # Extract text from the page
    page_text = page.extract_text()

    # Split the text into lines
    lines = page_text.split("\n")

    # Flag to determine if we are inside the table area
    inside_table = False

    # Loop through each line and identify the table
    for line in lines:
        if "revenue" in line.lower():
            inside_table = True
        elif "total" in line.lower() and "revenue" in line.lower():
            inside_table = False

        if inside_table:
            # Split the line by spaces to extract the numbers
            numbers = line.split()
            table_data.extend(numbers)

    return "\n".join(table_data)

def extract_lines_containing_keywords(text, keywords):
    lines = text.split('\n')
    lines_with_keywords = [line for line in lines if any(keyword in line.lower() for keyword in keywords)]
    return lines_with_keywords

######## add the correct folderpath for you
folder_path = r"C:\Users........................\annual_reports"
pdf_files = glob.glob(folder_path + "/report_*.pdf")

target_text = r"Financial Statement Elkem AS"
keywords_to_extract = ["revenue"]

for pdf_file in pdf_files:
    print(f"Processing {pdf_file}...")
    start_page, end_page = find_page_number_interval_with_text(pdf_file, target_text)
    
    if start_page and end_page:
        table_page_number = find_table_page_number(pdf_file, "revenue")
        if table_page_number:
            pdf_text = extract_text_from_pdf(pdf_file, start_page, end_page, table_page_number)
            lines_with_keywords = extract_lines_containing_keywords(pdf_text, keywords_to_extract)
            if lines_with_keywords:
                print(f"Financial Statement found in the interval of pages {start_page} - {end_page}")
                for line in lines_with_keywords:
                    print(line)
            else:
                print(f"Keywords not found in {pdf_file}")
        else:
            print(f"Table page not found in {pdf_file}")
    else:
        print(f"Financial Statement not found in {pdf_file}")
    print("=" * 50)

并返回输出:

Financial Statement found in the interval of pages 82 - 115
Revenue 4 7 155 256 6 450 525
Revenue recognition
Sales revenues are presented net of VAT and discounts. Revenues from goods sold are recognised when the significant risk and
reward of the ownership of the goods are transferred to the buyer, according to the actual delivery term for each sale. Revenues and
Revenue from sale of goods 5 817 613 5 212 892
Revenue from sale of goods - group 1 050 606 1 021 537
Other operating revenue 176 392 119 876
Other operating revenue - group 110 645 96 220
Total revenue 7 155 256 6 450 525
Total revenue 1 426 3 348 4 774
Total revenue 1 426 3 348 4 774
==================================================

在第二行的输出中,您可以看到数字 4 在数字 7 前面。数字 4 已从注释部分列中错误地提取出来。 2015 年收入的正确数字是 7 155 256,而不是 4 7 155 256。后面的其他七位数字来自 2014 年列(它们始终将上一年作为年度报告的标准)。

提前感谢您提供的任何帮助或提示,如果有任何不清楚的地方请通知我! 祝你有美好的一天:)

python web-scraping finance stock pdfplumber
1个回答
0
投票

您的代码正在使用

.extract_text()

您可以进行的第一个更改是使用表函数:https://github.com/jsvine/pdfplumber#extracting-tables

在最基本的层面上,您可以垂直标记左侧和右侧:

explicit_vertical_lines = [ 
   min(page.chars, key=itemgetter("x0"))["x0"],
   max(page.chars, key=itemgetter("x1"))["x1"] 
]

# im = page.to_image()
# im.draw_vlines(explicit_vertical_lines).save('lines.png')

“行”都是单行,因此您可以使用

"text"
水平策略:

page.extract_table(dict(
   explicit_vertical_lines = explicit_vertical_lines,
   horizontal_strategy = "text"
))

它合并了“名称”和“注释”列,但确实正确隔离了您想要的数字。

[['Income statement – Elkem AS', None, None],
 ['', None, None],
 ['1 January - 31 December Note', '2015', '2014'],
 ['', '', ''],
 ['Amounts in NOK 1000', '', ''],
 ['', '', ''],
 ['Revenue 4', '7 155 256', '6 450 525'],
 ['', '', ''],
 ['Other operating income 4', '123 166', '72 496'],
 ['', '', ''],
 ['Total operating income', '7 278 422', '6 523 021'],
 ['', '', ''],
 ['Raw materials and energy for smelting', '(3 970 252)', '(3 864 619)'],
 ['', '', ''],
 ['Employee benefit expenses 5,6', '(902 483)', '(835 590)'],
 ['', '', ''],
 ['Amortisations and depreciations 12', '(309 465)', '(286 275)'],
 ['', '', ''],
 ['Impairment losses 12', '(1 814)', '550 846'],
 ['', '', ''],
 ['Currency gains/losses related to operating activities 9', '(442 276)', '(84 443)'],
 ...

使事情变得更准确将取决于您可以使用哪些信息(如果有),例如“我想要的列名始终是年份或日期”。

© www.soinside.com 2019 - 2024. All rights reserved.