Python {Article050}

ようこそ「Python」へ...

PythonでWebサイトの新着ニュースをメールで自動送信するには?【2022年版】

ここでは 「Hacker News」 のサイトから新着ニュースを取得してメール(Gmail)で自動送信する方法を解説します。 「Hacker News」サイトから新着ニュースを取得するにはPythonのWeb Scrapingライブラリ「BeautifulSoup」を使用します。 取得した新着ニュースはGoogleの「Gmail」に送信します。 なお、PythonからGmailにメールを送信するには Googleの 「セキュリティ」 サイトから「安全性の低いアプリのアクセス」を「オン」に設定する必要があります。

click image to zoom!
[Google Security Site]


この仕様は2022年に変更になったので2段階認証を行って新規のパスワード(16桁)を取得する必要があります。 新規のパスワードの取得は以下の手順で行います。
  1. Googleの 「セキュリティ」 サイトに移動したら「2段階認証プロセス」が「オン」になっているか確認します。 「オフ」になっているときは、「オン」にします。 Googleの指示に従って2段階認証の処理を完了させます。
  2. 「2段階認証プロセス」が「オン」になっていることを確認したら「アプリパスワード」をクリックします。 パスワードを入力する画面が表示されたら「パスワード」を入力して「次へ」のボタンをクリックします。 【図A】
  3. 「アプリパスワード」の画面に移動したら「アプリを選択」のドロップダウンリストをクリックして「その他(名前を入力)」を選択します。 「名前」のテキストボックスにはアプリの名前「GMO bot」を入力して[生成]ボタンをクリックします。 【図B】
  4. すると16桁のパスワードが表示されるのでコピペして保存します。 最後に[完了]ボタンをクリックして閉じます。 【図C】
  5. 「アプリパスワード」の一覧に今回追加した「GMO bot」が表示されます。 【図D】


click image to zoom!
図A
click image to zoom!
図B
click image to zoom!
図C
click image to zoom!
図D



ここではVisula Studio Code(VS Code)の「Python Interactive window」 を使用してJupter Notebookのような環境で説明します。 VSCを通常の環境からインタラクティブな環境に切り換えるにはコードを記述するときコメント「# %%」を入力します。 詳しい、操作手順については「ここ」 を参照してください。 インタラクティブな環境では、Pythonの「print(), plt.show()」などを使う必要がないので掲載しているコードでは省略しています。 VSCで通常の環境で使用するときは、必要に応じて「print(), plt.show()」等を追加してください。

この記事では、Pandas、Matplotlibのライブラリを使用しますので 「記事(Article001) | 記事(Article002) | 記事(Article003) | 記事(Article004)」 を参照して事前にインストールしておいてください。 Pythonのコードを入力するときにMicrosoftのVisula Studio Codeを使用します。 まだ、インストールしていないときは「記事(Article001)」を参照してインストールしておいてください。

説明文の左側に図の画像が表示されていますが縮小されています。 画像を拡大するにはマウスを画像上に移動してクリックします。 画像が拡大表示されます。拡大された画像を閉じるには右上の[X]をクリックします。 画像の任意の場所をクリックして閉じることもできます。
click image to zoom!
Gmail[1]
click image to zoom!
Gmail[2]
click image to zoom!
Gmail[3]


「Hacker News」サイトの新着ニュースをメールで自動送信する

  1. Pythonの「gmail_config.py」ファイルを作成してGoogleのGmailのアカウント情報を定義する

    Visual Studio Code(VSC)を起動したら新規ファイル「gmail_config.py」を作成して行1-6をコピペします。 行4-6を自分のメールアドレスとパスワードに置換したら保存ください。 行2-3は固定ですから置換する必要はありません。

    PythonからGmailにメールを送信するには「安全性の低いアプリのアクセス」を「オン」に設定する必要があります。 手順は図1の説明を参照してください。
    # gmail_config.py
    GMAIL_SERVER = 'smtp.gmail.com'         # your smtp server
    GMAIL_PORT = 587                        # your port number
    GMAIL_FROM = '****@gmail.com'           # your from email id
    GMAIL_TO = '****@gmail.com'             # your to email ids  # can be a list
    GMAIL_PASS = '**********'               # your email id's password
    click image to zoom!
    図1
    図1はGoogle Accountの「Security」画面です。 この画面から「セキュリティ」を選択して「安全性の低いアプリのアクセス」を「オン」に設定してください。
  2. 新規ファイルを作成してPythonのライブラリを取り込む

    新規ファイルを作成したら行1-7をコピペします。 行1-6ではPythonのライブラリを取り込んでいます。 行7では前出で作成した「gmail_config.py」を取り込んでいます。
    import requests
    from bs4 import BeautifulSoup 
    import smtplib
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    import datetime
    import gmail_config
    click image to zoom!
    図2
    図2はVisual Studio Code(VSC)の画面です。 右側のインタラクティブ・ウィンドウからgmail_config.pyで定義した 「GMAIL_SERVER」と「GMAIL_PORT」の内容を表示しています。
  3. Hacker Newsサイトから新着ニュースを取得する

    行3では現在の日時を取得しています。 行10-20では関数「extract_news()」を定義しています。 引数urlには「Hacker News」サイトのURLを指定します。 戻り値としてHacker Newsサイトの新着ニュースのコンテンツを返します。 行22では関数extract_news()を呼び出してHacker Newsサイトから新着ニュースを取得しています。 行23-25ではメールで送信する本文を生成しています。 なお、メールはHTML形式で送信します。
    ### send email using gmail
    # get current date/time
    now = datetime.datetime.now()
    
    # email content placeholder
    content = ''
    
    # extracting Hacker News Stories
    
    def extract_news(url):
        print('Extracting Hacker News Stories...')
        cnt = ''
        cnt += ('<b>Hacker News Top Stories:</b>\n' + '<br />' + '-'*50 + '<br />')
        response = requests.get(url)
        content = response.content
        soup = BeautifulSoup(content,'html.parser')
        for i,tag in enumerate(soup.find_all('td',attrs={'class':'title','valign':''})):
            cnt += ((str(i+1) + ' :: ' + tag.text + '\n' + '<br />') if tag.text != 'More' else '')
            #print(tag.prettify) #find_all('span',attrs={'class':'sitestr'}))
        return(cnt)
        
    cnt = extract_news('https://news.ycombinator.com/')
    content += cnt
    content += ('<br />------<br />')
    content +=('<br /><br />End of Message')
    click image to zoom!
    図3
    図3では関数「extract_news()」からの戻り値を表示しています。 画面にはHacker Newsの新着ニュースが表示されています。
  4. 取得した新着ニュースをメールで送信する

    行8-12ではgmail_config.pyファイルに定義したGmailのアカウント情報を取得して変数に保存しています。 行14ではMIMEMultipart(Multipurpose Internet Mail Extensions)のインスタントを生成しています。 行16-18ではMIMEにメールの「Subject(件名)」「FROM (Gmail address」「TO (eMail address)」を設定しています。 行20ではMIMEにメールの本文を設定しています。

    行24ではSMTP(Simple Mail Transfer Protocol) Serverのインスタントを生成しています。 行26ではSMTP ServerのDebug情報を表示するように設定しています。 「0」を設定するとDebug情報の表示を抑止します。 行27-31ではSMTP Serverに接続&ログインしてメールを送信しています。 行27ではSMTP Serverのグリーティングに対して挨拶を返しています。 行28ではSMTP Serverに対して安全でない接続からTLSを使用して安全な接続にアップグレードすることを通知しています。 行29ではSMTP Serverにログインしています。 行31ではメールを送信しています。 行35ではSMTP Serverを切断しています。
    ### send the email
    
    print('Composing Email...')
    
    # update your email details
    # make sure to update the Google Low App Access settings before
    
    SERVER = gmail_config.GMAIL_SERVER  # your smtp server
    PORT = gmail_config.GMAIL_PORT      # your port number
    FROM = gmail_config.GMAIL_FROM      # your from email id
    TO = gmail_config.GMAIL_TO          # your to email ids  # can be a list
    PASS = gmail_config.GMAIL_PASS      # your email id's password
    
    msg = MIMEMultipart()
    
    msg['Subject'] = 'Top News Stories HN [Automated Email] ' + now.strftime('%Y/%m/%d') 
    msg['From'] = FROM
    msg['To'] = TO
    
    msg.attach(MIMEText(content, 'html'))
    
    print('Initiating Server...')
    
    server = smtplib.SMTP(SERVER, PORT)
    
    server.set_debuglevel(1)    # 0-suppress debug info, 1-display debug info
    server.ehlo()
    server.starttls()
    server.login(FROM, PASS)
    # We could not login successfully.  Return result of last attempt.
    server.sendmail(FROM, TO, msg.as_string())
    
    print('Email Sent...')
    
    server.quit()
    click image to zoom!
    図4-1
    図4-1はGmailにメールを送信したときの画像です。 Hacker Newsのサイトから取得した新着ニュースが表示されています。
    click image to zoom!
    図4-2
    図4-2はGoogleのGmailの画像です。 Hacker Newsのサイトから取得した新着ニュースが送信されています。
  5. ここで解説したコードをまとめて掲載

    最後にここで解説したすべてのコードをまとめて掲載しましたので参考にしてください。
    
    import requests # http requests
    from bs4 import BeautifulSoup # web scraping
    # Send the mail
    import smtplib
    # email body
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText
    # system date and time manipulation
    import datetime
    import gmail_config
    
    # %%
    
    ### send email using gmail
    # get current date/time
    now = datetime.datetime.now()
    
    # email content placeholder
    content = ''
    
    ### extracting Hacker News Stories
    
    def extract_news(url):
        print('Extracting Hacker News Stories...')
        cnt = ''
        cnt +=('<b>Hacker News Top Stories:</b>\n'+'<br />'+'-'*50+'<br />')
        response = requests.get(url)
        content = response.content
        soup = BeautifulSoup(content,'html.parser')
        for i,tag in enumerate(soup.find_all('td',attrs={'class':'title','valign':''})):
            cnt += ((str(i+1)+' :: '+tag.text + "\n" + '<br />') if tag.text!='More' else '')
            #print(tag.prettify) #find_all('span',attrs={'class':'sitestr'}))
        return(cnt)
        
    cnt = extract_news('https://news.ycombinator.com/')
    content += cnt
    content += ('<br />------<br />')
    content +=('<br /><br />End of Message')
    
    # %%
    
    ### lets send the email
    
    print('Composing Email...')
    
    # update your email details
    # make sure to update the Google Low App Access settings before
    
    SERVER = gmail_config.GMAIL_SERVER  # "your smtp server"
    PORT = gmail_config.GMAIL_PORT      # your port number
    FROM = gmail_config.GMAIL_FROM      # "your from email id"
    TO = gmail_config.GMAIL_TO          # "your to email ids"  # can be a list
    PASS = gmail_config.GMAIL_PASS      # "your email id's password"
    
    msg = MIMEMultipart()
    
    # msg.add_header('Content-Disposition', 'attachment', filename='empty.txt')
    msg['Subject'] = 'Top News Stories HN [Automated Email] ' + now.strftime('%Y/%m/%d') 
    msg['From'] = FROM
    msg['To'] = TO
    
    msg.attach(MIMEText(content, 'html'))
    
    print('Initiating Server...')
    
    server = smtplib.SMTP(SERVER, PORT)
    #server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
    server.set_debuglevel(1)    # 0-suppress error, 1-display error
    server.ehlo()
    server.starttls()
    server.login(FROM, PASS)
    # We could not login successfully.  Return result of last attempt.
    server.sendmail(FROM, TO, msg.as_string())
    
    print('Email Sent...')
    
    server.quit()