PDF・Word・PowerPoint・Excelファイルからテキスト部分を一括抽出するメソッド


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

以下を実行すると、__カレントディレクトリに格納されているすべてのPDF・Word・PowerPoint・Excelファイルについて、以下の辞書*dict*型オブジェクトを返します。__

__返り値__は、__以下を要素に持つ辞書（*dict*）型オブジェクト__です。

```text:返り値の辞書の要素
{ファイル名 : そのファイルのテキスト部分を文字列結合した文}
```

####__実行コード__

```Python3:
from text_from_string_files import *
from pprint import pprint

pprint(func_dict)
# 実行結果
{'docx': <function get_text_from_word at 0x11783ff70>,
 'pdf': <function get_text_from_pdf at 0x11783fe50>,
 'pptx': <function get_text_from_powerpoint at 0x11783fee0>,
 'xlsx': <function get_text_from_excel at 0x11783d040>}

result = get_filename_text_dict(func_dict)
print(result.keys())
pprint(result['あるKeyの文字列'])
pprint(result)
```

####（ 事前にインストールしておくべき資源 ）

```bash:
pip install python-docx
pip install openpyxl
```

####（ 実行例 ）


```bash:Terminal
% ls
000717009.xlsx			JNGI2019_Zentai.pptx		honbun.docx
29zen10kai2.pdf			__pycache__			text_from_string_files.py
%  ipython
```

```Python3:ipython（Python３.9.0）

In [1]: from text_from_string_files import *

In [2]: result = get_filename_text_dict(func_dict)

In [3]: print(result.keys())
dict_keys(['JNGI2019_Zentai.pptx', '000717009.xlsx', '29zen10kai2.pdf', 'honbun.docx'])

In [4]: file_content_list = result.values()

In [5]: len(file_content_list)
Out[6]: 4

In [6]: type(result["000717009.xlsx"])
Out[6]: str

In [7]: len(result["000717009.xlsx"])
Out[7]: 158657

In [8]: print(result["000717009.xlsx"][0:200])
団体名12345678910111213141516171819導入状況単独利用・共同利用具体的な導入事務について簡潔に記入導入分野その他の内容
※「その他」を選択した場合のみ記入具体的な導入機能導入の動機
※複数回答可AI導入・開発の状況その他の内容を簡潔に記入
※「その他」を選択した場合のみ記入導入に当たってのＢＰＲ実施の有無導入効果の有無導入効果
※導入効果有の場合のみ記入※複数回答可導入効

In [9]: len(result["JNGI2019_Zentai.pptx"])
Out[9]: 72100

In [10]: type(result["JNGI2019_Zentai.pptx"])
Out[10]: str

In [11]: print(result["JNGI2019_Zentai.pptx"][0:200])
2017年度（平成29年度）温室効果ガス排出量（確報値）について環境省1１．概況と増減要因233我が国の温室効果ガス排出量の推移<出典>温室効果ガス排出・吸収目録(2005年度比)《2013年度比》[前年度比]【前年度からの増減量】総排出量12億9,200万トン（CO2換算）(▲6.5%)《▲8.4%》[▲1.2%]【▲1,610万トン】○総排出量は2010年度から4年連続で増加していたが、201

In [12]: len(result["29zen10kai2.pdf"])
Out[12]: 815

In [13]: type(result["29zen10kai2.pdf"])
Out[13]: str

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

In [15]: len(result["honbun.docx"])
Out[15]: 12505

In [16]: type(result["honbun.docx"])
Out[16]: str

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

In [18]: 
```

##２. スクリプトファイル

__以下、PowerPointファイルとExcelファイルからテキストデータを読み込むメソッド以外は、以下のWebページ所収のコードを踏襲させていただきました（一部改変）。__

・ [[Python] Word/Excel/PowerPoint/PDFからテキスト抽出するライブラリ・サンプルコード」](https://deecode.net/?p=852)

なお、上記のサイトのコードは、*List[str]*オブジェクトを返します。
今回は、配列の中身の*str*オブジェクトを文字列結合して、単一の*str*オブジェクトを返すように、手を加えました。

元のメソッドの*layout = device.get_result()*の次の行に、以下を追記。

```Python:Python
 	text = str(get_text_list_recursively(layout))
	text = text.replace("\\n", "").replace("\n", "")
	results.append(text)
	output = "".join(results)
```

Excelファイルからテキスト部分を取得するメソッドは、以下を参考に作成しました。

・ [「Python Excelのシート名をすべて取得するsheetnames」](https://pg-chain.com/python-excel-sheetnames)
・ [「Python Excelのデータをすべて取得する方法」](https://pg-chain.com/python-excel-data)

また、PowerPointファイルからテキストを取得するコードは、以下を参考にしました（一部改変）。

・ [「python-pptxで文字列を抽出する」](https://www.relief.jp/docs/python-pptx-extract-text.html)

__「[Python] Word/Excel/PowerPoint/PDFからテキスト抽出するライブラリ・サンプルコード」__所収のコードは、PowerPointファイルのうち、表紙スライドに含まれるテキストしか、取得できなかったためです。

###実装コード


```Python3:text_from_string_files.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(func_dict):
    func_dict = func_dict
    # カレントディレクトリの絶対パスを取得
    current_directory_path = os.getcwd()
    available_ext_list = list(func_dict.keys())
    # カレントディレクトリにあるテキストデータを抽出可能なファイルのファイル名を全件取得
    file_list = get_text_matching_file_names(available_ext_list, current_directory_path)
    # ファイルの拡張子に応じた適切なテキストデータ抽出メソッドを実行
    output_dict = {}
    for filename in file_list:
        for ext in available_ext_list:
            if ext in filename:
                text = func_dict[ext](filename)
                output_dict[filename] = text
    return  output_dict

#if __name__ == '__main__':
#	main()
```