0
0

More than 3 years have passed since last update.

PDF・Word・PowerPoint・Excelファイルのパスを入力すると、ファイルの文字列部分を連結した単一のstrオブジェクトを返すメソッド

Last updated at Posted at 2020-12-03

1. 実行時に走らせるコード

以下を実行すると、引数に渡したファイルパスのファイルが、以下のいずれかである場合、ファイルの中にあるテキスト文字列を文字列連結した、単一のstr型オブジェクトが、返されます。

  1. PDFファイル
  2. Wordファイル
  3. PowerPointファイル
  4. Excelファイル

返り値は、単一のstr)型オブジェクトです。

( 事前にインストールしておくべき資源 )

pip install python-docx
pip install openpyxl

( 実行例 )

Terminal
% ls
000717009.xlsx          JNGI2019_Zentai.pptx        honbun.docx
29zen10kai2.pdf         __pycache__         text_from_string_files.py       get_text_from_arg_filepath.py
% ipython
ipython(Python3.9.0)
In [1]: os.listdir()
Out[1]: 
['text_from_string_files.py',
 'JNGI2019_Zentai.pptx',
 '__pycache__',
 '000717009.xlsx',
 '29zen10kai2.pdf',
 'honbun.docx',
 'get_text_from_arg_filepath.py']

In [2]: from get_text_from_arg_filepath import *

In [3]: get_filename_text_dict('29zen10kai2.pdf')
Out[3]: "['平29.6.190-1総1']['近年の納税実務等を巡る環境変化について「アダム・スミスの4原則」について']['納税実務等を巡る近年の環境変化への対応に向けた海外調査について「アダム・スミスの4原則」について~平成29年1月27日政府税制調査会資料(抜粋)~']['規制改革推進に関する第1次答申(平成29年5月23日規制改革推進会議)(電子申告関係部分)']['e-Tax(国税電子申告・納税システム)']['法人税の電子申告の状況について(未定稿)']['規制改革推進に関する第1次答申(平成29年5月23日規制改革推進会議)(年末調整関係部分)']['日本における給与所得者の年末調整事務の流れ']['個人所得税の納税手続に関する諸外国比較(年末調整がある国)「アダム・スミスの4原則」について']['個人所得税の納税手続に関する諸外国比較(年末調整がない国)「アダム・スミスの4原則」について']['被用者の納税に係る事務負担の在り方(イメージ)']['参考資料']['個人のICT化の状況']['企業活動におけるICT化の状況(1)']['企業活動におけるICT化の状況(2)(日本の電子商取引(EC)市場規模の推移)']['ICT化に伴う経済取引の多様化(例:シェアリングエコノミー、FinTech分野における決済・送金)']['所得税に係る税務手続の流れ(個人事業主を例として)']['(施行開始)']['その他の環境変化に対応した主な施策']['日本の所得税の構造(イメージ)']['税額']['【税額調整目的:控除】']['(2017年1月現在)']['税額']['個人単位課税']['世帯単位課税(N分N乗方式)']['個人単位課税']['税額']['「アダム・スミスの4原則」について「アダム・スミスの4原則」について']['「ワグナーの4大原則・9原則」について「アダム・スミスの4原則」について']"

In [4]: result = get_filename_text_dict('honbun.docx')

In [5]: type(result)
Out[5]: str

In [6]: len(result)
Out[6]: 12505

In [7]: print(result[0:200])
2018年6月25日財務省行政情報化推進委員会財務省デジタルガバメント中長期計画Ⅰ基本事項(1)目的財務省は、「健全な財政の確保適正かつ公平な課税の実現税関業務の適正な運営国庫の適正な管理通貨に対する信頼の維持及び外国為替の安定の確保を図ること」(財務省設置法第3条を任務とし行政事務の効率化及び国民事業者の利便性向上を目的として所掌事務に関連する分野においてシステムを導入しコス

In [8]: 

ファイル渡しは、相対パス絶対パス、どちらでもOK

これまで、テキストファイルは、Pythonスクリプトファイルを実行しているディレクトリ空の相対パスで、自作メソッドに渡していました。

iPython(Python3.9.0)
In [3]: import pathlib

In [4]: tmp = '29zen10kai2.pdf'

In [5]: p = pathlib.Path(tmp)

In [6]: p
Out[6]: PosixPath('29zen10kai2.pdf')

絶対パスに変換

( 参考 )

note.nkmk.me 「Python, pathlibで絶対パスと相対パスを相互変換・判定」
Hbk project 「【Python】絶対パス・相対パスの取得方法(os.pathモジュール)」
Python活用 パスの取り扱い(絶対パスと相対パスを操る)

iPython(Python3.9.0)
In [7]: print(p.resolve())
/Users/ocean/Desktop/files_test/29zen10kai2.pdf

In [10]: abs_path = p.resolve()

In [11]: abs_path
Out[11]: PosixPath('/Users/ocean/Desktop/files_test/29zen10kai2.pdf')

絶対パスで、テキストファイルを自作メソッドの引数に渡す

うまく動いた。

iPython(Python3.9.0)
In [12]: get_filename_text_dict(abs_path)
Out[12]: "['平29.6.190-1総1']['近年の納税実務等を巡る環境変化について「アダム・スミスの4原則」について']['納税実務等を巡る近年の環境変化への対応に向けた海外調査について「アダム・スミスの4原則」について~平成29年1月27日政府税制調査会資料(抜粋)~']['規制改革推進に関する第1次答申(平成29年5月23日規制改革推進会議)(電子申告関係部分)']['e-Tax(国税電子申告・納税システム)']['法人税の電子申告の状況について(未定稿)']['規制改革推進に関する第1次答申(平成29年5月23日規制改革推進会議)(年末調整関係部分)']['日本における給与所得者の年末調整事務の流れ']['個人所得税の納税手続に関する諸外国比較(年末調整がある国)「アダム・スミスの4原則」について']['個人所得税の納税手続に関する諸外国比較(年末調整がない国)「アダム・スミスの4原則」について']['被用者の納税に係る事務負担の在り方(イメージ)']['参考資料']['個人のICT化の状況']['企業活動におけるICT化の状況(1)']['企業活動におけるICT化の状況(2)(日本の電子商取引(EC)市場規模の推移)']['ICT化に伴う経済取引の多様化(例:シェアリングエコノミー、FinTech分野における決済・送金)']['所得税に係る税務手続の流れ(個人事業主を例として)']['(施行開始)']['その他の環境変化に対応した主な施策']['日本の所得税の構造(イメージ)']['税額']['【税額調整目的:控除】']['(2017年1月現在)']['税額']['個人単位課税']['世帯単位課税(N分N乗方式)']['個人単位課税']['税額']['「アダム・スミスの4原則」について「アダム・スミスの4原則」について']['「ワグナーの4大原則・9原則」について「アダム・スミスの4原則」について']"

In [13]:

実装コード

get_text_from_arg_filepath.py
import docx, openpyxl, pptx, os.path
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTContainer, LTTextBox
from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager
from pdfminer.pdfpage import PDFPage

####指定したディレクトリから、テキストファイルを抽出できるファイルを検索するメソッド
def get_text_matching_file_names(ext_pattern_list, search_directory_path) -> list:
    file_names_list = os.listdir(search_directory_path)
    # 上記のいずれかの拡張子を持つファイルのファイル名を格納する配列を用意
    available_filename_list = [] 
    # 上記のいずれかの拡張子を持つファイルのファイル名を配列に格納する
    for file_name in file_names_list:
        ext_check_result = []
        for ext in ext_pattern_list:
            boolean = ext in file_name
            ext_check_result.append(boolean)
        if True in ext_check_result:
            available_filename_list.append(file_name)
    return  available_filename_list

####PDFファイル(拡張子:.pdf)からテキスト抽出するメソッド
def get_text_list_recursively(layout) -> list:
    if isinstance(layout, LTTextBox):
        return [layout.get_text()]
    if isinstance(layout, LTContainer):
        text_list = []
        for child in layout:
            text_list.extend(get_text_list_recursively(child))
            return text_list

def get_text_from_pdf(filepath: str) -> str:
    laparams = LAParams(detect_vertical=True)
    resource_manager = PDFResourceManager()
    device = PDFPageAggregator(resource_manager, laparams=laparams)
    interpreter = PDFPageInterpreter(resource_manager, device)
    results = []
    with open(filepath, "rb") as file:
        for page in PDFPage.get_pages(file):
            interpreter.process_page(page)
            layout = device.get_result()
            text = str(get_text_list_recursively(layout))
            text = text.replace("\\n", "").replace("\n", "").replace(" ", "").replace(" ", "")
            results.append(text)        

    output = "".join(results)
    return output


####PowerPointファイル(拡張子:.pptx)からテキスト抽出するメソッド
def get_text_from_powerpoint(filepath: str) -> str:
    prs = pptx.Presentation(filepath)
    output = ""
    for i, sld in enumerate(prs.slides, start=1):
        for shp in sld.shapes:
            if shp.has_text_frame:
                text = shp.text
                output += text.replace("\n", "").replace("\n", "").replace(" ", "").replace(" ", "")

    return output


####Wordファイル(拡張子:.pptx)からテキスト抽出するメソッド
def get_text_from_word(filepath: str) -> str:
    document = docx.Document(filepath)
    text_list = list(map(lambda par: par.text, document.paragraphs))
    text = "".join(text_list)
    output = text.replace(" ", "").replace(" ", "")
    return output

####Excelファイル(拡張子:.xlsx)からテキスト抽出するメソッド
def get_text_from_excel(filepath: str) -> str:
    output_text = ""
    book = openpyxl.load_workbook(filepath)
    sheet_list = book.sheetnames
    for sheet_name in sheet_list:
        sheet = book[sheet_name]
        for cells in tuple(sheet.rows):
            for cell in cells:
                data = cell.value
                if data is None:
                    continue
                else:
                    output_text += str(data).replace(" ", "").replace(" ", "")
    return output_text


####Key: ファイルの拡張子に応じて、Value: 適切なメソッドを選択する際に用いる辞書
func_dict = {
    'pdf' : get_text_from_pdf,
    'docx'  : get_text_from_word,
    'xlsx'  : get_text_from_excel,
    'pptx' : get_text_from_powerpoint
         }

####mainメソッド
def get_filename_text_dict(file_path):
    # パスからファイルの「ファイル名.拡張子」を取得
    basename = os.path.basename(file_path)
    filename_with_ext = basename
    available_ext_list = list(func_dict.keys())
    # ファイルの拡張子に応じた適切なテキストデータ抽出メソッドを実行
    for ext in available_ext_list:
        if ext in filename_with_ext:
            text = func_dict[ext](filename_with_ext)

    return  text


( リファクタリング版 )

( 修正点1 )

以下のWebページを参考に、引数として受け取ったファイルパスから、ファイルの拡張子を取得する部分を修正。

ファイルの拡張子を取得する

( 修正点2 )

メソッド名から、filenameおよびdictの文字列を削除。

返り値はstr型であり、返り値にはfilenameは含まれない為。このスクリプトファイルは当初、ファイル名とファイル名の中身のテキスト文字列を、keyvalueに収めたdict型オブジェクトを返す仕様であった。その当時の名残が、残ったままになってしまっていた。

def get_text_from_file(file_path):
    # パスからファイルの「ファイル名.拡張子」を取得
    # https://www.gesource.jp/programming/python/code/0010.html
    root, ext = os.path.splitext(file_path)
    available_ext_list = list(func_dict.keys())
    # ファイルの拡張子に応じた適切なテキストデータ抽出メソッドを実行
    for ok_ext in available_ext_list:
        if ext == ok_ext:
            text = func_dict[ext](file_path)

    if not(ext in available_ext_list):
        text = ""

    return text

修正後のスクリプトファイルの使い方

ipython(Python3.9.0)
In [4]: from get_text_from_arg_filepath import *

In [5]: result = get_text_from_file('29zen10kai2.pdf')

In [6]: print(type(result))
<class 'str'>

In [7]: print(len(result))
815

In [8]: print(result[0:200])
['平29..190-1総1']['近年の納税実務等を巡る環境変化についてアダムスミスの4原則について']['納税実務等を巡る近年の環境変化への対応に向けた海外調査についてアダムスミスの4原則について平成29年1月27日政府税制調査会資料抜粋)~']['規制改革推進に関する第1次答申平成29年5月23日規制改革推進会議)(電子申告関係部分']['e-Tax国税電子申告納税

In [9]: result2 = get_text_from_file('honbun.docx')

In [10]: print(type(result2))
<class 'str'>

In [11]: print(len(result2))
12505

In [12]: print(result2[0:200])
2018年6月25日財務省行政情報化推進委員会財務省デジタル・ガバメント中長期計画Ⅰ基本事項(1)目的財務省は、「健全な財政の確保、適正かつ公平な課税の実現、税関業務の適正な運営、国庫の適正な管理、通貨に対する信頼の維持及び外国為替の安定の確保を図ること」(財務省設置法第3条)を任務とし、行政事務の効率化及び国民・事業者の利便性向上を目的として、所掌事務に関連する分野においてシステムを導入し、コス

In [13]: 

修正後のスクリプトファイル

get_text_from_arg_filepath.py
import docx, openpyxl, pptx, os.path
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTContainer, LTTextBox
from pdfminer.pdfinterp import PDFPageInterpreter, PDFResourceManager
from pdfminer.pdfpage import PDFPage

####指定したディレクトリから、テキストファイルを抽出できるファイルを検索するメソッド
def get_text_matching_file_names(ext_pattern_list, search_directory_path) -> list:
    file_names_list = os.listdir(search_directory_path)
    # 上記のいずれかの拡張子を持つファイルのファイル名を格納する配列を用意
    available_filename_list = []
    # 上記のいずれかの拡張子を持つファイルのファイル名を配列に格納する
    for file_name in file_names_list:
        ext_check_result = []
        for ext in ext_pattern_list:
            boolean = ext in file_name
            ext_check_result.append(boolean)
        if True in ext_check_result:
            available_filename_list.append(file_name)
    return  available_filename_list

####PDFファイル(拡張子:.pdf)からテキスト抽出するメソッド
def get_text_list_recursively(layout) -> list:
    if isinstance(layout, LTTextBox):
        return [layout.get_text()]
    if isinstance(layout, LTContainer):
        text_list = []
        for child in layout:
            text_list.extend(get_text_list_recursively(child))
            return text_list

def get_text_from_pdf(filepath: str) -> str:
    laparams = LAParams(detect_vertical=True)
    resource_manager = PDFResourceManager()
    device = PDFPageAggregator(resource_manager, laparams=laparams)
    interpreter = PDFPageInterpreter(resource_manager, device)
    results = []
    with open(filepath, "rb") as file:
        for page in PDFPage.get_pages(file):
            interpreter.process_page(page)
            layout = device.get_result()
            text = str(get_text_list_recursively(layout))
            text = text.replace("\\n", "").replace("\n", "").replace(" ", "").replace(" ", "")
            results.append(text)

    output = "".join(results)
    return output


####PowerPointファイル(拡張子:.pptx)からテキスト抽出するメソッド
def get_text_from_powerpoint(filepath: str) -> str:
    prs = pptx.Presentation(filepath)
    output = ""
    for i, sld in enumerate(prs.slides, start=1):
        for shp in sld.shapes:
            if shp.has_text_frame:
                text = shp.text
                output += text.replace("\n", "").replace("\n", "").replace(" ", "").replace(" ", "")

    return output


####Wordファイル(拡張子:.pptx)からテキスト抽出するメソッド
def get_text_from_word(filepath: str) -> str:
    document = docx.Document(filepath)
    text_list = list(map(lambda par: par.text, document.paragraphs))
    text = "".join(text_list)
    output = text.replace(" ", "").replace(" ", "")
    return output

####Excelファイル(拡張子:.xlsx)からテキスト抽出するメソッド
def get_text_from_excel(filepath: str) -> str:
    output_text = ""
    book = openpyxl.load_workbook(filepath)
    sheet_list = book.sheetnames
    for sheet_name in sheet_list:
        sheet = book[sheet_name]
        for cells in tuple(sheet.rows):
            for cell in cells:
                data = cell.value
                if data is None:
                    continue
                else:
                    output_text += str(data).replace(" ", "").replace(" ", "")
    return output_text

####txtファイル(拡張子:.txt)からテキスト抽出するメソッド
def get_text_from_textfile(filepath: str) -> str:
    output_text = ""
    f = open(filepath, 'r', encoding='UTF-8')
    output_text = f.read()
    f.close()
    return output_text

####Key: ファイルの拡張子に応じて、Value: 適切なメソッドを選択する際に用いる辞書
func_dict = {
    '.pdf' : get_text_from_pdf,
    '.docx'  : get_text_from_word,
    '.xlsx'  : get_text_from_excel,
    '.pptx' : get_text_from_powerpoint,
    '.txt'  : get_text_from_textfile
         }

####mainメソッド
def get_text_from_file(file_path):
    # パスからファイルの「ファイル名.拡張子」を取得
    # https://www.gesource.jp/programming/python/code/0010.html
    root, ext = os.path.splitext(file_path)
    available_ext_list = list(func_dict.keys())
    # ファイルの拡張子に応じた適切なテキストデータ抽出メソッドを実行
    for ok_ext in available_ext_list:
        if ext == ok_ext:
            text = func_dict[ext](file_path)

    if not(ext in available_ext_list):
        text = ""

    return text

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0