用于将使用循环提取的文本附加到 Python 中的列表的多重处理

Multiprocessing for appending text extracted with a loop to a list in Python

作为一个 Python(和编程)新手,我正在尝试将数千个 PDF 的文本提取到一个文件(或列表,如果更好的话)中。数据将在稍后阶段用于内容分析。我创建了一个工作函数,它遍历目录中的所有 PDF,使用 pdfplumber 提取文本并将其附加到列表中。

我现在想使用多处理来加速否则会非常冗长的过程。但是,我似乎无法弄清楚如何最好地实现使用并行进程附加到列表的循环。下面是尝试使用一些教程中的代码,使用 concurrent.futures 和我的函数:

import pdfplumber
import os
import concurrent.futures

def pdfextractor(file):
    text = []
    for file in os.listdir("./processing/"):
        filename = os.fsdecode(file)
        if filename.endswith('.pdf'):
            with pdfplumber.open("./processing/" + file) as pdf:
                pdf_page = pdf.pages[0]
                single_page_text = pdf_page.extract_text()
                text.append(str(single_page_text))

if __name__ == "__main__":
    executor = concurrent.futures.ProcessPoolExecutor(4)
    futures = [executor.submit(pdfextractor, 'file')]
    concurrent.futures.wait(futures)

这导致启动多个进程,将相同的 PDF 文本附加到 text 列表。将 ProcessPoolExecutor 更改为 ThreadPoolExecutor 会产生所需的函数输出,但不会增加速度。

经过大量修改,我设法解决了这个问题。这是将 运行 函数所需时间减少一半以上的代码。我将函数一分为二以更好地适应 concurrent.futuresextract_pdf 遍历 PDF 的所有页面,提取文本并将其附加到列表中。 extract_all 然后在整个目录上重复此过程。结果是一个嵌套列表。

def extract_pdf(filename, directory):
    filename = os.fsdecode(filename)
    allpages_text = []
    if filename.endswith('.pdf'):
        with pdfplumber.open(directory + filename) as pdf:
            for page in pdf.pages:
                text = page.extract_text()
                allpages_text.append(text)
            allpages_text = '-'.join(allpages_text)
            return allpages_text


def extract_all(directory):
    data = []

    with concurrent.futures.ProcessPoolExecutor(max_workers=8) as executor:

        futures = {executor.submit(extract_pdf, filename, directory): filename for filename in os.listdir(directory)}

        for future in concurrent.futures.as_completed(futures):
            try:
                result = future.result()
                data.append(result)
            except Exception as exc:
                print("There was an error. {}".format(exc))
    return data



if __name__ == '__main__':
    directory = './test/'

    results = extract_all(directory)

这个网站对我更好地了解 concurrent.futures 模块的情况很有帮助:https://rednafi.github.io/digressions/python/2020/04/21/python-concurrent-futures.html