質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

メール

メールは、コンピュータネットワークを利用し、 情報等を交換する手段のことです。

Q&A

解決済

1回答

3993閲覧

読み込んだemlファイルの情報をExcelに書き出す方法

UserName

総合スコア3

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

メール

メールは、コンピュータネットワークを利用し、 情報等を交換する手段のことです。

0グッド

1クリップ

投稿2022/06/21 08:23

編集2022/06/22 06:13

Python

1 2import sys 3import email 4from email.header import decode_header 5import datetime 6import glob 7import os 8import openpyxl 9 10class MailParser(object): 11 """ 12 メールファイルのパスを受け取り、それを解析するクラス 13 """ 14 15 def __init__(self, mail_file_path): 16 self.mail_file_path = mail_file_path 17 # emlファイルからemail.message.Messageインスタンスの取得 18 with open(mail_file_path, 'rb') as email_file: 19 self.email_message = email.message_from_bytes(email_file.read()) 20 self.subject = None 21 self.to_address = None 22 self.cc_address = None 23 self.from_address = None 24 self.body = "" 25 self.date = None 26 # 添付ファイル関連の情報 27 # {name: file_name, data: data} 28 self.attach_file_list = [] 29 # emlの解釈 30 self._parse() 31 32 def get_attr_data(self): 33 """ 34 メールデータの取得 35 """ 36 result = """\ 37DATE: {} 38FROM: {} 39TO: {} 40CC: {} 41----------------------- 42BODY: 43{} 44----------------------- 45ATTACH_FILE_NAME: 46{} 47""".format( 48 self.date, 49 self.from_address, 50 self.to_address, 51 self.cc_address, 52 self.body, 53 ",".join([ x["name"] for x in self.attach_file_list]) 54 ) 55 return result 56 57 58 def _parse(self): 59 """ 60 メールファイルの解析 61 __init__内で呼び出している 62 """ 63 self.subject = self._get_decoded_header("Subject") 64 self.to_address = self._get_decoded_header("To") 65 self.cc_address = self._get_decoded_header("Cc") 66 self.from_address = self._get_decoded_header("From") 67 # 変更したところ 68 self.date = datetime.datetime.strptime( 69 self._get_decoded_header("Date"), 70 "%a, %d %b %Y %H:%M:%S %z" 71 ) 72 73 # メッセージ本文部分の処理 74 for part in self.email_message.walk(): 75 # ContentTypeがmultipartの場合は実際のコンテンツはさらに 76 # 中のpartにあるので読み飛ばす 77 if part.get_content_maintype() == 'multipart': 78 continue 79 # ファイル名の取得 80 attach_fname = part.get_filename() 81 # ファイル名がない場合は本文のはず 82 if not attach_fname: 83 charset = str(part.get_content_charset()) 84 if charset: 85 self.body += part.get_payload(decode=True).decode(charset, errors="replace") 86 else: 87 self.body += part.get_payload(decode=True) 88 else: 89 # ファイル名があるならそれは添付ファイルなので 90 # データを取得する 91 self.attach_file_list.append({ 92 "name": attach_fname, 93 "data": part.get_payload(decode=True) 94 }) 95 96 def _get_decoded_header(self, key_name): 97 """ 98 ヘッダーオブジェクトからデコード済の結果を取得する 99 """ 100 ret = "" 101 102 # 該当項目がないkeyは空文字を戻す 103 raw_obj = self.email_message.get(key_name) 104 if raw_obj is None: 105 return "" 106 # デコードした結果をunicodeにする 107 for fragment, encoding in decode_header(raw_obj): 108 if not hasattr(fragment, "decode"): 109 ret += fragment 110 continue 111 # encodeがなければとりあえずUTF-8でデコードする 112 if encoding: 113 ret += fragment.decode(encoding) 114 else: 115 ret += fragment.decode("UTF-8") 116 return ret 117 118if __name__ == "__main__": 119 tifCounter = len(glob.glob1("./mail","*.eml")) 120 print(tifCounter) 121 for mail_file_path in glob.glob('./mail/*'): 122 # ブックを取得 123 book = openpyxl.load_workbook(r'C:\Users\Desktop') 124 # シートを取得 125 sheet = book['Sheet1'] 126 # セルへ書き込む 127 sheet['A1'] = 'ナンバー' 128 sheet['B1'] = 100 129 # 保存する 130 book.save(r'C:\Users\) 131 132 result = MailParser(mail_file_path).get_attr_data() 133 134 print(result) 135

https://qiita.com/pandachan5228/items/186690c4662ed1d8b823

を参考に複数のemlファイルを読み込みができ、最後にExcelに

日付 差出人名 差出人メールアドレス 内容

の4項目に分けてExcelに書き出すコードを教えてください!

https://teratail.com/questions/09h52spph2wsst
↑↑ここの回答者さんが説明を書いてくれてます〜。

print結果

総メール件数 1 件
日時: 2022-06-21 17:46:21+09:00
FROM: たこ焼きくん aaaaa@aaaa.aaa
TO: cccc@ccccc.cccc
CC:

本文:
はまやらわ


ATTACH_FILE_NAME:

↓完成!!!!🌟

Python

1 2import sys 3import email 4from email.header import decode_header 5import datetime 6import glob 7import openpyxl 8 9class MailParser(object): 10 """ 11 メールファイルのパスを受け取り、それを解析するクラス 12 """ 13 14 def __init__(self, mail_file_path): 15 self.mail_file_path = mail_file_path 16 # emlファイルからemail.message.Messageインスタンスの取得 17 with open(mail_file_path, 'rb') as email_file: 18 self.email_message = email.message_from_bytes(email_file.read()) 19 self.subject = None 20 self.to_address = None 21 self.cc_address = None 22 self.from_address = None 23 self.body = "" 24 self.date = None 25 # 添付ファイル関連の情報 26 # {name: file_name, data: data} 27 self.attach_file_list = [] 28 # emlの解釈 29 self._parse() 30 31 def get_attr_data(self): 32 """ 33 メールデータの取得 34 """ 35 result = """\ 36日時: {} 37FROM: {} 38TO: {} 39CC: {} 40----------------------- 41本文: 42{} 43----------------------- 44ATTACH_FILE_NAME: 45{} 46""".format( 47 self.date, 48 self.from_address, 49 self.to_address, 50 self.cc_address, 51 self.body, 52 ",".join([ x["name"] for x in self.attach_file_list]) 53 ) 54 return result 55 56 57 def _parse(self): 58 """ 59 メールファイルの解析 60 __init__内で呼び出している 61 """ 62 self.subject = self._get_decoded_header("Subject") 63 self.to_address = self._get_decoded_header("To") 64 self.cc_address = self._get_decoded_header("Cc") 65 self.from_address = self._get_decoded_header("From") 66 # 変更したところ 67 self.date = datetime.datetime.strptime( 68 self._get_decoded_header("Date"), 69 "%a, %d %b %Y %H:%M:%S %z" 70 ) 71 72 # メッセージ本文部分の処理 73 for part in self.email_message.walk(): 74 # ContentTypeがmultipartの場合は実際のコンテンツはさらに 75 # 中のpartにあるので読み飛ばす 76 if part.get_content_maintype() == 'multipart': 77 continue 78 # ファイル名の取得 79 attach_fname = part.get_filename() 80 # ファイル名がない場合は本文のはず 81 if not attach_fname: 82 charset = str(part.get_content_charset()) 83 if charset: 84 self.body += part.get_payload(decode=True).decode(charset, errors="replace") 85 else: 86 self.body += part.get_payload(decode=True) 87 else: 88 # ファイル名があるならそれは添付ファイルなので 89 # データを取得する 90 self.attach_file_list.append({ 91 "name": attach_fname, 92 "data": part.get_payload(decode=True) 93 }) 94 95 def _get_decoded_header(self, key_name): 96 """ 97 ヘッダーオブジェクトからデコード済の結果を取得する 98 """ 99 ret = "" 100 101 # 該当項目がないkeyは空文字を戻す 102 raw_obj = self.email_message.get(key_name) 103 if raw_obj is None: 104 return "" 105 # デコードした結果をunicodeにする 106 for fragment, encoding in decode_header(raw_obj): 107 if not hasattr(fragment, "decode"): 108 ret += fragment 109 continue 110 # encodeがなければとりあえずUTF-8でデコードする 111 if encoding: 112 ret += fragment.decode(encoding) 113 else: 114 ret += fragment.decode("UTF-8") 115 return ret 116 117if __name__ == "__main__": 118 # ブックを取得 119 book = openpyxl.load_workbook(r'C:\Users\ああああ\Desktop\あああ\あああああ.xlsx') 120 # シートを取得 121 sheet = book['Sheet1'] 122 123 tifCounter = len(glob.glob1("./mail","*.eml")) 124 print("🙌総メール件数",tifCounter,"件🙌") 125 126 i=2 127 for mail_file_path in glob.glob('./mail/*'): 128 try: 129 result = MailParser(mail_file_path) 130 # セルへ書き込む 131 sheet.cell(row=i, column=1).value = i-1 132 sheet.cell(row=i, column=2).value = result.date.replace(tzinfo=None) 133 sheet.cell(row=i, column=4).value = result.from_address.split("<")[0] 134 sheet.cell(row=i, column=5).value = result.from_address[:-1].split("<")[1] 135 sheet.cell(row=i, column=6).value = result.body 136 137 print(i-1,"件目💕書き込んだよ😘") 138 print(mail_file_path) 139 print() 140 except ValueError: 141 print(i-1,"件目エラーだよ😒") 142 print(mail_file_path) 143 print("👿👿👿👿👿👿👿👿👿👿👿👿👿👿") 144 print() 145 146 i+=1 147 148 # 保存する 149 book.save(r'C:\Users\ああああ\Desktop\あああ\あああああ.xlsx') 150 print("終わったよ😍") 151

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TakaiY

2022/06/21 08:37

print(result) で出てきた結果を 1つか2つ、メアドなど差し障りのある内容は伏せ字にして質問に追加してください。
guest

回答1

0

ベストアンサー

いろいろ変えなくてはなりませんが、ちょっとずつ。

まず、エクセルファイルをループの中で毎回開くようになっているので、ループの外に出します。
書き出し処理もループの外に出します。
ループの中で やるのはセルへの書き込みだけです。

  • Excelファイルを開いて、シートオブジェツコを取得する
  • ループでデータを取得してセルに書き込む
  • Excelファイルを書き出す

セルのの参照は「A1」形式を使っていますが、これだと処理しにくいので,cellメソッドでセルを取ります。 こんな形になります。

python

1 sheet.cell(raw=i, col=0).value = "日付"

先の書き方の行(raw)は、メール毎に増やさなければなりませんが、ループの前に変数「i」を0で初期化して、ループごとに1増やして使いましょう。

メールから抽出したデータはオブジェクトの変数に入っています。

python

1result.date #日付 2result.from_address # 差出人名 差出人メールアドレス 3result.body # 内容

差出人名は差出人メールアドレスの前についているようなので、スペースで分割(split)してそれぞれ取り出せばいいかと思います。ただし、差出人名が無いものがあったりした場合どうするかは悩ましいところですね。

で、これらを必要なカラムに設定すればいいでしょう。

とりあえず、アドバイスしてみました。


追記

こんな感じですかね?!?!

まだまだですね。

最初のコードからいきましょう。

python

1 for mail_file_path in glob.glob('./mail/*'): 2 # ブックを取得 3 book = openpyxl.load_workbook(r'C:\Users\') 4 # シートを取得 5 sheet = book['Sheet1'] 6 # セルへ書き込む 7 sheet['A1'] = 'ナンバー' 8 sheet['B1'] = 100 9 # 保存する 10 book.save(r'C:\Users\') 11 result = MailParser(mail_file_path).get_attr_data() 12 print(result)

まずは、Excelの処理をループの外に出します。

python

1 # ブックを取得 2 book = openpyxl.load_workbook(r'C:\Users\') 3 # シートを取得 4 sheet = book['Sheet1'] 5 6 for mail_file_path in glob.glob('./mail/*'): 7 # セルへ書き込む 8 sheet['A1'] = 'ナンバー' 9 sheet['B1'] = 100 10 result = MailParser(mail_file_path).get_attr_data() 11 print(result) 12 13 # 保存する 14 book.save(r'C:\Users\')

ループの中では sheet 変数が見えますが、これはエクセルのSheet1を保持しています。
このシートの列にメールファイルごとに情報を書き込むわけですから、基本的な処理はこれでだいたいできているのです。
あとは、どこからどこへデータを移すかということだす。

python

1 sheet.cell(raw=i, col=0).value = <日付> 2 sheet.cell(raw=i, col=1).value = <名前> 3 sheet.cell(raw=i, col=2).value = <メアド> 4 sheet.cell(raw=i, col=2).value = <内容>

日付などを取得するには、前に書いたように resultが必要だから、まずはresult取得して、この処理ですね。

python

1 # ブックを取得 2 book = openpyxl.load_workbook(r'C:\Users\') 3 # シートを取得 4 sheet = book['Sheet1'] 5 6 for mail_file_path in glob.glob('./mail/*'): 7 result = MailParser(mail_file_path).get_attr_data() 8 # セルへ書き込む 9 sheet.cell(raw=i, col=0).value = <日付> 10 sheet.cell(raw=i, col=1).value = <名前> 11 sheet.cell(raw=i, col=2).value = <メアド> 12 sheet.cell(raw=i, col=2).value = <内容> 13 14 book.save(r'C:\Users\')

これで書き込めるのですが、このままだと「i」 が無い状態です。 iは行番号で、行はメールファイルごとに1つですから、ループが回るごとに1つ増やします。

python

1 # ブックを取得 2 book = openpyxl.load_workbook(r'C:\Users\') 3 # シートを取得 4 sheet = book['Sheet1'] 5 6 i = 0 7 for mail_file_path in glob.glob('./mail/*'): 8 result = MailParser(mail_file_path).get_attr_data() 9 # セルへ書き込む 10 sheet.cell(raw=i, col=0).value = <日付> 11 sheet.cell(raw=i, col=1).value = <名前> 12 sheet.cell(raw=i, col=2).value = <メアド> 13 sheet.cell(raw=i, col=2).value = <内容> 14 i += 1 15 book.save(r'C:\Users\')

これで、ループが回るごとに違う行にデータを書き込むことができます。

あとは、 <日付> などですね。 <日付> は result.date に入ってますよね。 本文は、 body です。
名前とメアドは from_address にまとめて入っているので自分で分解して入れてみてください。

python

1 # ブックを取得 2 book = openpyxl.load_workbook(r'C:\Users\') 3 # シートを取得 4 sheet = book['Sheet1'] 5 6 i = 0 7 for mail_file_path in glob.glob('./mail/*'): 8 result = MailParser(mail_file_path).get_attr_data() 9 # セルへ書き込む 10 sheet.cell(raw=i, col=0).value = result.date 11 sheet.cell(raw=i, col=1).value = <名前> 12 sheet.cell(raw=i, col=2).value = <メアド> 13 sheet.cell(raw=i, col=2).value = result.body 14 i += 1 15 book.save(r'C:\Users\')

ちなみに、
質問に出ていたコードは
``python
i = 1
for row in ws.iter_rows():
for cell in row:
sheet.cell(row=i, column=1).value = "日付"
i = i + 1

これでrowがぐるぐる回って、カラムもぐるぐる回っていますが、これにあわせて、メールを 読んだり、そのなかのデータを適切に取得したりしなければなりません。 もともと、複数あるファイルをループ回していて、1ファイル1行なのだから、エクセルの行やカラムで回す必要はないのです。

投稿2022/06/21 09:02

編集2022/06/22 01:55
TakaiY

総合スコア12801

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

UserName

2022/06/21 09:03

うわーー!!またまたありがとうございます! やってみます!!!!!!!
TakaiY

2022/06/21 09:09

ああ、あと、セルに書き込むタイミングは、resultに結果を取得した後ですよ。
UserName

2022/06/21 09:39

print(result) のあとに for i in なんたらを入れればいいんですか、、、?😭
UserName

2022/06/21 09:56

あ! i = 1 for row in ws.iter_rows(): for cell in row: sheet.cell(row=i, column=1).value = "日付" i = i + 1 こんな感じですかね?!?!
UserName

2022/06/22 01:32

--> 131 sheet.cell(raw=i, col=0).value = result.date で AttributeError: 'str' object has no attribute 'date' というエラーが出るのですが何故ですか(><) あと、回答のフォルダ名消しといてもらってもいいですか(><)本当すみません…………。
UserName

2022/06/22 01:32

Excel入ってるフォルダ名全部消しといて欲しいです(><)
TakaiY

2022/06/22 01:59

直しておきました。 >AttributeError: 'str' object has no attribute 'date' というエラーが出るのですが何故ですか(><) result = MailParser(mail_file_path).get_attr_data() これを result = MailParser(mail_file_path) こうしてみていただけますか?
UserName

2022/06/22 02:16

# セルへ書き込む sheet.cell(row=i, column=1).value = result.body だと問題なくExcelに書き出されるんですけど、 sheet.cell(row=i, column=1).value = result.date だと TypeError: Excel does not support timezones in datetimes. The tzinfo in the datetime/time object must be set to None. が出るのですが(><)たくさん質問してすみません(><)
UserName

2022/06/22 02:35

sheet.cell(row=i, column=1).value = result.from_address.split("<")[0] sheet.cell(row=i, column=2).value = result.from_address[:-1].split("<")[1] sheet.cell(row=i, column=3).value = result.body 差出人名とアドレス分けれました!!!!! わーい!!!!🥳
TakaiY

2022/06/22 02:39

おや、Excelはタイムゾーンを入れられないんですね。 sheet.cell(row=i, column=1).value = result.date.replace(tzinfo=None) こうするとどうでしょう(ぼくも今調べた)
UserName

2022/06/22 05:56

出来ました!!!!!! 完成ですぅ!!!! 本当にありがとうございました! Python王子!!!🦄✨
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問