2023/10/22
Webページの自動保存・送信システムを作る(2)
前回の続きです。今回はRaspberry Piの中で実施している処理(Pythonプログラム)の詳細をお話しします。Pythonプログラムのキーとなる部分は以下の2点です。
1. Webページをpdfファイルにする技術
2. メールを送受信する技術
1.については、pdfkitライブラリを用いました。このライブラリを利用する上で、同時にwkhtmltopdfライブラリもRaspberry Piにインストールしました。
pip3 install pdfkit2.については、当初Gmailを使う方法を検討していましたが、最終的にoutlook(hotmail)を使うことにしました。以前はGoogleアカウント設定で「安全性の低いアプリ」として設定することでGmailのメールサーバーを外部アプリから利用することができましたが、2022/5/30にこの方法が廃止されたためです。
sudo apt-get install wkhtmltopdf

以下、作成したPythonプログラムです。まとまりがないプログラムですが、エラーなく動作しています。
# ssmail.pyまとまりのないプログラムの中身をChatGPTに解説してもらうと以下の通りです。
# Mail sender of the pdf file converted from the web page
import os
import sys
import pdfkit
import email, imaplib
import base64
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from pathlib import Path
import logging
# Mail registration information
username= os.environ['USERNAME'] # Outlook Mail
password= os.environ['PASSWORD'] # Outlook Mail
to_email= os.environ['TO_EMAIL']
cc_email= os.environ['CC_EMAIL']
# Log file setting
logging.basicConfig(
filename="MailSenderLog.txt",
level=logging.INFO,
format="%(asctime)s:%(levelname)s:%(message)s",
)
# Mail receive
# IMAP4 protocol setting and login
mail= imaplib.IMAP4_SSL("outlook.office365.com")
res = mail.login(username, password)
print(res)
logging.info(res)
# Target folder dxds set
resp_code, mail_count = mail.select(mailbox="dxds", readonly=False)
mail_count_int = int(mail_count[0])
print('Mail: '+ str(mail_count_int))
logging.info('Mail: '+ str(mail_count_int ))
if mail_count_int == 0: # No target mail
mail.logout()
sys.exit()
# Mail check
resp_code, mail_ids = mail.search(None, "ALL")
logging.info("Mail IDs : {}\n".format(mail_ids[0].decode().split()))
mail_id = '1'
logging.info("================== Start of Mail [{}] ====================".format(mail_id))
resp_code, mail_data = mail.fetch(mail_id, '(RFC822)') ## Fetch mail data.
message = email.message_from_bytes(mail_data[0][1]) ## Construct Message from mail data
logging.info("From : {}".format(message.get("From")))
logging.info("To : {}".format(message.get("To")))
logging.info("Bcc : {}".format(message.get("Bcc")))
logging.info("Date : {}".format(message.get("Date")))
logging.info("Subject : {}".format(message.get("Subject")))
logging.info("Body : ")
for part in message.walk():
if part.get_content_type() == "text/plain":
body_lines = part.as_string().split("\n")
logging.info("\n".join(body_lines[:12])) ### Print first 12 lines of message
logging.info("\n")
data_b64_dec = base64.b64decode(''.join(body_lines[3:]))
data_dec = data_b64_dec.decode('utf-8')
logging.info(data_dec.splitlines()[0]) # Target WebPage URL
logging.info("================== End of Mail [{}] ====================\n".format(mail_id))
# WebPage to PDF file
url = data_dec.splitlines()[0]
pdf_file = '/home/pi/prog/output.pdf'
try:
pdfkit.from_url(url, pdf_file)
logging.info(f'PDF file "{pdf_file}" is created.')
except Exception as e:
logging.info(f'Error occurred.: {str(e)}')
# Delete Message
mail.store(mail_id, '+FLAGS', r'\Deleted')
mail.expunge()
# IMAP4 close
mail.logout()
# mail sender
mail_title = 'DX paper'
message = '''
DX paper will be sent.
'''
# Create mail with MIME multipart
msg = MIMEMultipart()
msg['Subject'] = mail_title
msg['To'] = to_email
msg['From'] = username
msg['cc'] = cc_email
msg.attach(MIMEText(message))
# Load attachments
filepath =Path( '/home/pi/prog/output.pdf')
filename = filepath.name #filepath.stem
with open(filepath, 'rb') as f:
attach = MIMEApplication(f.read())
attach.add_header('Content-Disposition', 'attachment', filename=filename)
msg.attach(attach)
# Send a mail
smtp_host = 'smtp.office365.com'
smtp_port = 587
smtp_password = password
server = smtplib.SMTP(smtp_host, smtp_port)
server.starttls()
server.login(username, smtp_password)
server.send_message(msg)
server.quit()
--- ChatGPT Comments From Here ---
このプログラムは、WebページからPDFファイルを生成し、生成されたPDFファイルをメールで送信するPythonスクリプトです。以下はプログラムの主要な部分の説明です。
1. モジュールのインポート:
- `os`, `sys`: システム操作と環境変数へのアクセスを提供するモジュール。
- `pdfkit`: WebページからPDFファイルを生成するためのライブラリ。
- `email`, `imaplib`: 電子メールの操作(受信)に関するライブラリ。
- `base64`: ベース64エンコードとデコードを行うライブラリ。
- `smtplib`: SMTPプロトコルを使用してメールを送信するためのライブラリ。
- `email.mime.text`, `email.mime.multipart`, `email.mime.application`: メールの構築に使用されるMIME(Multipurpose Internet Mail Extensions)関連のモジュール。
- `pathlib`: ファイルパス操作のためのユーティリティ。
2. メールの設定情報:
- `username`, `password`, `to_email`, `cc_email`: メールの認証情報と送信先、CC(カーボンコピー)のアドレスを環境変数から取得します。
3. ログファイル設定:
- `MailSenderLog.txt` ファイルにログ情報を書き込むための設定。
4. メール受信:
- IMAP4プロトコルを使用してOutlookメールに接続し、ログインします。
- 受信対象のメールを`dxds`フォルダから取得し、メールの数を取得します。
5. メールの取得:
- 受信対象のメールが存在する場合、最初のメール(メールID 1)を取得し、その内容を解析します。
- メールの送信元、送信先、日付、件名、本文などの情報をログに記録します。
- メールの本文からWebページのURLを抽出します。
6. WebページからPDFファイル生成:
- 抽出したWebページのURLを使用して、`pdfkit`を使ってPDFファイルを生成します。
- 生成されたPDFファイルは`/home/pi/prog/output.pdf`に保存され、ログに生成の成功またはエラーが記録されます。
7. メッセージの削除:
- メールの処理が完了したら、受信したメールを削除し、IMAP4接続を閉じます。
8. メール送信:
- PDFファイルを添付して、指定された送信先とCCアドレスにメールを送信します。
- SMTPプロトコルを使用してOutlookのSMTPサーバーに接続し、メールを送信します。
このプログラムは、Outlookメールアカウントを使用して特定のフォルダからメールを受信し、WebページをPDFファイルに変換して指定の受信者に送信するためのスクリプトです。プログラム内でログも記録され、エラーが発生した場合に問題のトラッキングが可能です。
--- ChatGPT Comments To Here ---
完璧な解説ですね! 以下、補足です。
2. メールの設定情報: プログラム16〜19行目
前回お話しした通り、Raspberry Piでは、crontabで1日あたり、6:30、6:35、6:40の3回、このPythonプログラム(シェルプログラム)を実行しています。各種ファイルはRaspberry Piの「/home/pi/prog」フォルダに置きました。
DXpapersender.shの中でプログラム16〜19行目の変数を指定しています。中身は以下の通り。
#!bin/bash3. ログファイル設定: プログラム22〜26行目
cd /home/pi/prog/
export USERNAME="my_mail@hotmail.co.jp"
export PASSWORD="my_mail_password"
export TO_EMAIL="to_email@xxx.co.jp"
export CC_EMAIL="my_mail@hotmail.co.jp"
python3 ssmail.py
メールサービスとPythonプログラムとのやりとりのログを記録するためのものです。以下、4. メール受信から6. WebページからPDFファイル生成までのログを取っています。
2023-10-12 06:30:02,671:INFO:('OK', [b'LOGIN completed.'])以後の流れは、ChatGPTの解説通りです。
2023-10-12 06:30:02,715:INFO:Mail: 4
2023-10-12 06:30:02,736:INFO:Mail IDs : ['1', '2', '3', '4']
2023-10-12 06:30:02,737:INFO:================== Start of Mail [1] ====================
2023-10-12 06:30:03,022:INFO:From : xxxx
2023-10-12 06:30:03,024:INFO:To : xxxx
2023-10-12 06:30:03,025:INFO:Bcc : None
2023-10-12 06:30:03,025:INFO:Date : Tue, 10 Oct 2023 20:14:38 +0000
2023-10-12 06:30:03,026:INFO:Subject : dxdx
2023-10-12 06:30:03,026:INFO:Body :
2023-10-12 06:30:03,030:INFO:Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: base64
aHR0cHM6Ly9ub3RlLmNvbS9rb3VzZWluZW5fbm90ZS9uL25kNGRjYWVhOTNjY2Q/bWFnYXppbmVf
(中略)
LmNvbS9hcHAvZ29vZ2xlL2lkMjg0ODE1OTQyPuOBp+WFseacieOBl+OBvuOBl+OBnw0KDQoNCuW4
uOWyoQ0K
2023-10-12 06:30:03,031:INFO:
2023-10-12 06:30:03,032:INFO:https://note.com/xxxxxx
2023-10-12 06:30:03,033:INFO:================== End of Mail [1] ====================
2023-10-12 06:30:20,240:INFO:PDF file "/home/pi/prog/output.pdf" is created.
今回はRaspberry Piの中で実施している処理(Pythonプログラム)の詳細をお話しました。ChatGPTにプログラムの中身を解説してもらいましたが、うまく説明できていて驚きでした。ChatGPTにプログラムを書いてもらうのも良いですが、こういう書かれたプログラムの解説のような使い方も良いですね。