

csvの日付と内容の列だけを抽出し、昨日の日付だけが含んだ列だけを抽出しメールを送信したいです。  
下記のコードで記載しましたが、エラーが発生します。

ilocではdataframeがemptyだとエラーになるからだと思います。

① csvの 特定の列 だけを抽出した pandasのDataFrame を作成する  
② 昨日の列だけを抽出する  
③ 作成したDataFrameの 1行目と2行目(indexは0と1) に対して④~⑤の処理を行う  
④ 処理対象行の 各列の列名とデータを抽出してそれぞれに改行コードを付加し、連結する  
⑤ 抽出・連結した各列名＋データを、さらに改行コードで連結する  
⑥ 連結したデータをメール本文として挿入し、送信する

CSVのデータ

[code]

    日付                      内容    C     D      
    2021/02/07(日) 11:10:00  test2 test3  test4
    2021/02/06(土) 20:00:00  test5 test6  test7
    2021/02/10(水) 15:59:00  test8 test9  test10
                               
    
[/code]

昨日分だけの列を取得してメールを送信したいです。

[code]

    日付　　　　　　　　　　　　　内容  
    2021/02/10(水) 15:59:00  test8 
    
[/code]

現在のコード

[code]

    Gmail
    from datetime import datetime as dt, date, timedelta
    import csv
    import pandas as pd
    from email.mime.text import MIMEText
    import smtplib
    
    
    today = dt.today()
    (dt.strftime(today, '%Y/%m/%d'))
    
    yesterday = today - timedelta(days=1)
    print(yesterday.strftime("%Y/%m/%d"))
    
    #csvデータをdfに読み込み。 
    filename = "test.csv"
    
    df = pd.read_csv(filename,encoding='shift-jis')
    #### df_i = df.set_index("A","B","C")
    df_i = df[["日付","内容"]] 
    print(df_i)        
    
    df_h = df[df["日付"].str.contains(yesterday)]
    print(df_h)  
    #ここまで昨日のデータ上手く取得できます。      
    
    account = "123@gmail.com"
    password = "123"
    
    to_email = "123"
    from_email = "123@gmail.com"
    
    for j in range(2):
        subject = "【TEST】"
        message = '\n'.join([f"{column}\n{data}\n" for column,data in df_h.iloc[j].iteritems()]) #### !
        print(message)
        msg = MIMEText(message)
        msg["Subject"] = subject
        msg["To"] = to_email
        msg["From"] = from_email
    
        server = smtplib.SMTP("smtp.gmail.com", 587)
        server.starttls()
        server.login(account, password)
        server.send_message(msg)
        server.quit()
    
[/code]

エラーコード

[code]

     File "c:/Users/test/Documents/S3/test.py", line 34, in <module>
        message = '\n'.join([f"{column}\n{data}\n" for column,data in df_h.iloc[j].iteritems()]) 
      File "C:\Users\test\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pandas\core\indexing.py", line 879, in __getitem__
        return self._getitem_axis(maybe_callable, axis=axis)
      File "C:\Users\test\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pandas\core\indexing.py", line 1496, in _getitem_axis
        self._validate_integer(key, axis)
      File "C:\Users\test\AppData\Local\Programs\Python\Python38-32\lib\site-packages\pandas\core\indexing.py", line 1437, in _validate_integer
        raise IndexError("single positional indexer is out-of-bounds")
    IndexError: single positional indexer is out-of-bounds
    
[/code]

お手数おかけしますが、ご回答頂けると幸いです。

宜しくお願いします。


CC BY-SA 4.0
2021-02-11T10:24:29.100
73932
2021-02-11T12:16:26.970
2021-02-11T10:44:24.223
18859
18859
question
python pandas csv gmail
Pythonで特定の列を抽出しメールで送信する


**回答の前に：**  
コメントに書いた「③~⑤の条件が成り立たない」ことに関する確認事項が以下になります。

質問最初の行の「昨日の日付だけが含んだ列だけを抽出しメールを送信したい」は、「昨日の日付だけ **を** 含んだ **行**
だけを抽出しメールを送信したい」の間違いでしょう。

同様に途中の「昨日分だけの列を取得してメールを送信したいです。」は、「昨日分だけの **行** を取得してメールを送信したいです。」でしょうね。

それからメール本文の内容は、質問記事には以下のように書かれていましたが：

[code]

    日付　　　　　　　　　　　　　内容  
    2021/02/10(水) 15:59:00  test8 
    
[/code]

「現在のコード」で示された内容はこの前の別の質問内容に沿ったものですので：

[code]

    message = '\n'.join([f"{column}\n{data}\n" for column,data in df_h.iloc[j].iteritems()]) #### !
    
[/code]

それを当てはめると以下のようになると思われます：

[code]

    日付
    2021/02/10(水) 15:59:00
    
    内容
    test8
    
[/code]

**本当に欲しいメール本文の内容はどちら、あるいはまた別の内容でしょうか？**

* * *

**今の時点で判明している問題点：**

@metropolis
さんがコメントしたように、昨日のデータを抽出するための処理が動きません。「#ここまで昨日のデータ上手く取得できます。」というのは何かの確認ミスか、質問を入力した際の転記ミスでしょう。

この行を：

[code]

    yesterday = today - timedelta(days=1)
    print(yesterday.strftime("%Y/%m/%d"))
    
[/code]

こちらにすることと：

[code]

    yesterday = (today - timedelta(days=1)).strftime("%Y/%m/%d")
    print(yesterday)
    
[/code]

こちらの行は：

[code]

    df_h = df[df["日付"].str.contains(yesterday)]
    
[/code]

こうすべきでしょう：

[code]

    df_h = df_i[df_i["日付"].str.contains(yesterday)]
    
[/code]

同様に @metropolis
さんがコメントしたように、「ilocではdataframeがemptyだとエラーになるからだと思います。」自身はその通りですが、その原因は「昨日の日付だけを含んだ行だけを抽出」しているので、必ずしも2行のデータがあるとは限らないのに、固定的に2行分のデータがあるものとした前回質問の回答のままループしているからです。

@metropolis さんコメントのように、こちらの行は：

[code]

    for j in range(2):
    
[/code]

こうすべきでしょう：

[code]

    for j in range(len(df_h)):
    
[/code]

それから以下の行は、今回出力しようとするメール本文の内容に合わせて変更する必要があるかもしれません：

[code]

    message = '\n'.join([f"{column}\n{data}\n" for column,data in df_h.iloc[j].iteritems()]) #### !
    
[/code]

それから、そもそも「昨日の日付を含んだ行が無い」場合を検出して、メール処理を行う前に終了するとかの対処も必要でしょう。


CC BY-SA 4.0
2021-02-11T12:11:03.623
73934
2021-02-11T12:16:26.970
2021-02-11T12:16:26.970
26370
26370
73932
answer