[Python] 353 Gmailの自動送信(ChatGPT編)

巷で話題のChatGPTにプログラミングさせてみました。

パスワードについて補足のネット検索が必要ではありますが、合格点の内容でした。ご丁寧にtry文で例外処理に対応しています。

Google検索を差し置いてプログラミング手法調査のファーストチョイスになりそうです。

ChatGPTは定型的スクリプト作成は得意なようです。何ができて何ができないのかその特性を見極める必要がありますね。

初級プログラマとしては、とりあえずこのAIよりは気の利いたコードを書けるようにしたいものです。

質問:
GmailAPIを使わずにPythonでGmailを自動送信するスクリプトを教えてください

ChatGPT回答:
Gmail APIを使わずにGmailを自動送信するには、SMTP(Simple Mail Transfer Protocol)を使うことができます。
次のようなコードを記述することでGmailを自動送信することができます:
import smtplib
from email.mime.text import MIMEText

def send_email(to, subject, body):
    gmail_user = 'your_gmail_address@gmail.com'
    gmail_password = 'your_gmail_password'

    msg = MIMEText(body)
    msg['Subject'] = subject
    msg['From'] = gmail_user
    msg['To'] = to

    try:
        server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
        server.ehlo()
        server.login(gmail_user, gmail_password)
        server.send_message(msg)
        server.quit()
        print(F'Email was sent to "{to}"')
    except Exception as e:
        print(F'Something went wrong... {e}')
このスクリプトを実行すると、指定された宛先にメールが送信されます。
Gmailアカウントを使用する場合は、Gmailアカウントにアクセスするためのユーザー名とパスワードを設定する必要があります。

[Python] 352 Gmailの自動送信

[M1 Mac, Monterey 12.6.3, Python 3.10.4]

Pythonの汎用性の高さには目を見張るものがありますが、さらに新たな便利機能を見つけました。

Gmailの自動送信はかなり重宝しそうなのでライブラリ化しました。gmail.pyをmy_libraryディレクトリに入れて使います。

このスクリプトで使うパスワードはGoogleが発行する2段階認証非対応デバイス用パスワードになります。

定期実行しているスクリプトでエラーが発生した際に自動メールで知らせることも可能になりますね。

import smtplib
from email.mime.text import MIMEText

def send_gmail(mailto, title, text_msg):
    from_email ='送信元Gmailアドレス' 
    cc_mail = ''
    
    msg = MIMEText(text_msg, 'plain')
    msg['Subject'] = title
    msg['To'] = mailto
    msg['From'] = from_email
    msg['cc'] = cc_mail
    
    smtp_host = 'smtp.gmail.com'
    smtp_port = 587
    smtp_password = '2段階認証非対応デバイス用パスワード'
    
    server = smtplib.SMTP(smtp_host, smtp_port)
    server.starttls()
    server.login(from_email, smtp_password)
    server.send_message(msg)
    server.quit()
from my_library import gmail

mailto = "送信先メールアドレス"
title = "テスト"
msg = "テスト\nメール"

gmail.send_gmail(mailto, title, msg)

参考サイト

[Python] 351 C++ソースコードとJSON要素の照合 その3 スクリプトを統合

[M1 Mac, Monterey 12.6.3, Python 3.10.4]

AdobeXDアイテムデータからJSONファイルを作成するスクリプトとC++ソースコードの内容と比較するスクリプトを統合しました。

これでAdobeXDプラグイン出力のテキストファイルをターミナルにドラッグ&ドロップするだけでC++ソースコードとの比較結果が分かるようになります。

次はVSCodeの拡張機能作成に着手する予定です。

import pandas as pd

print("AdobeXDアイテムデータのパスを入力してください")
items_file = input()

# JSONファイル名作成
items_json_file = "/code/cpp/projects/VideoEditor/plugin/" + (items_file.split("/")[-1]).split(".")[0] + ".json"
print(items_json_file)

# 先頭と末尾のシングルクォートを削除
items_file2 = items_file[1:-1]
print(items_file2)

# データファイルを読み込む
with open(items_file2, "r") as tf:
    items_list = tf.read().replace("\n","").split(';')
    
# print(items_list)
# print(len(items_list))

# listからデータ抽出し、JSON文字列作成
json_str = ""
num = 0
for item in items_list:
    name = item.split("'")[1]
    # print(name + "\n")
    
    xy = (item.split("global X,Y:")[1]).split("parent")[0]
    x = xy.split(",")[0]
    y = xy.split(",")[1]
    # print(x + "\n")
    # print(y + "\n")
    
    wh = (item.split("{")[1]).split("global")[0]
    w = (wh.split("width:")[1]).split(", height")[0]
    h = wh.split("height:")[1]
    # print(w + "\n")
    # print(h + "\n")
    
    if num == 0:
        json_str += "{\"" + name + "\"" + ":[" + x + ", " + y + ", " + w + ", " + h + "],\n"
    elif num < len(items_list) -1:
        json_str += "\"" + name + "\"" + ":[" + x + ", " + y + ", " + w + ", " + h + "],\n"
    else:
        json_str += "\"" + name + "\"" + ":[" + x + ", " + y + ", " + w + ", " + h + "]}"

    # print(json_str + "\n")
    
    num += 1

# JSONファイル作成
with open(items_json_file, mode='w') as f:
    f.write(json_str.replace(" ",""))

# C++ソースファイル    
cpp_file = '/code/cpp/projects/VideoEditor/src/VideoEditor.cpp'
    
# 検索用ファイル文字列(行単位)
with open(cpp_file) as f:
    lines = f.readlines()

# 不一致ファイル名作成
false_json_file = "/code/cpp/projects/VideoEditor/plugin/" + (items_json_file.split("/")[-1]).split("_")[0] + "_false_" +  (items_json_file.split("/")[-1]).split("_")[1]

print(false_json_file)

# JSONファイルをpandasで読込
df = pd.read_json(items_json_file)
print(df)

# 非ウィジェットデータのリスト
notWidget_list = ['convertArea', 'STDOUT', 'IMAGESTOVIDEO', 'VIDEOTOIMAGES']
# 非ウィジェットデータ削除
df2 = df.drop(columns = notWidget_list)

# ウィジェット名リスト化
columns = df2.columns.values
print(columns)
print("columns_len: " + str(len(columns)))

# C++データとAdobeXDデータの照合
false_json = ""
false_count = 0
new_notWidget_list = list()
for col in columns:
    data = df.loc[:, col]
    # print(data.values)
    data2 = str(data.values[0]) + "," + str(data.values[1]) + "," + str(data.values[2]) + "," + str(data.values[3])
    print(data2)
    
    var_str = col + " = new"   
    print(var_str) 
    
    line_str = [line for line in lines if var_str in line]
    
    try:
        line_str2 = line_str[0]
        print(line_str)
        str_exist = data2 in line_str2
        print(str_exist)
        
        if str_exist == False:
            old_xy = (line_str2.split("(")[1]).split(",\"")[0]
            print("col, old_xy: " + col + ", " + str(old_xy))
            
            if false_count == 0:
                false_json += "{\"" + col + "\"" + ":[[" + old_xy + "],[" + data2 + "]],\n"
            else:
                false_json += "\"" + col + "\"" + ":[[" + old_xy + "],[" + data2 + "]],\n"
                
            false_count += 1

    except Exception as e:
        print(e)
        new_notWidget_list.append(col)
        
print("new_notWidget_list: " + str(new_notWidget_list))
print("false_count: " + str(false_count))

false_json2 = false_json[:-2] + "}"

# 不一致WidgetのJSONファイル作成
with open(false_json_file, mode='w') as f:
    f.write(false_json2)

[Python] 350 C++ソースコードとJSON要素の照合 その2 不一致データのJSON化

[M1 Mac, Monterey 12.6.3, Python 3.10.4]

前回の続きです。

C++ソースコードとAdobeXDのデータを照合し、不一致データをJSONファイルにまとめました。

これを見ながら手動でソースコードの修正ができます。C++ソースコードを自動修正するスクリプト作成までやるかどうかは未定です。

JSONの自由度の高さはなかなかのものです。文字列を連結するだけで作成できるので便利ですね。

import pandas as pd

file = 'VideoEditor.cpp'
    
# 照合用ファイル文字列(行単位)
with open(file) as f:
    lines = f.readlines()

# AdobeXDアイテムデータをpandasで読込
df = pd.read_json('items.json')
print(df)

# 非ウィジェットのリスト
notWidget_list = ['convertArea', 'STDOUT', 'IMAGESTOVIDEO', 'VIDEOTOIMAGES']
# 非ウィジェットデータ削除
df2 = df.drop(columns = notWidget_list)

# ウィジェット名リスト化
columns = df2.columns.values
print(columns)
print("columns_len: " + str(len(columns)))

# C++データとAdobeXDデータの照合
false_json = ""
false_count = 0
new_notWidget_list = list()
for col in columns:
    data = df.loc[:, col]
    # print(data.values)
    data2 = str(data.values[0]) + "," + str(data.values[1]) + "," + str(data.values[2]) + "," + str(data.values[3])
    print(data2)
    
    var_str = col + " = new"   
    print(var_str) 
    
    line_str = [line for line in lines if var_str in line]
    
    try:
        line_str2 = line_str[0]
        print(line_str)
        str_exist = data2 in line_str2
        print(str_exist)
        
        if str_exist == False:
            old_xy = (line_str2.split("(")[1]).split(",\"")[0]
            print("col, old_xy: " + col + ", " + str(old_xy))
            
            if false_count == 0:
                false_json += "{\"" + col + "\"" + ":[[" + old_xy + "],[" + data2 + "]],\n"
            else:
                false_json += "\"" + col + "\"" + ":[[" + old_xy + "],[" + data2 + "]],\n"
                
            false_count += 1

    except Exception as e:
        print(e)
        new_notWidget_list.append(col)
        
print("new_notWidget_list: " + str(new_notWidget_list))
print("false_count: " + str(false_count))

false_json2 = false_json[:-2] + "}"

# 不一致WidgetのJSONファイル作成
with open('false.json', mode='w') as f:
    f.write(false_json2)
{"y1Label":[[697,23,21,14],[698,23,21,14]],
"imageSec":[[475,170,80,20],[485,170,60,20]],
"imageNum":[[65,170,100,20],[65,170,50,20]],
"input":[[25,25,35,16],[25,25,16,16]]}

[Python] 349 C++ソースコードとJSON要素の照合 その1

[M1 Mac, Monterey 12.6.3, Python 3.10.4]

C++ソースコードを読み込み、JSON要素との照合を行い、その結果をBool値で返すスクリプトを書きました。

具体的にはFLTKウィジェットの新しいオブジェクトを作成する行の座標、幅、高さがAdobe XDのデータと一致しているかどうか判定します。

一致していなければAdobe XDのデータに書き換えます。この部分については次回以降記事にする予定です。

久々にpandasの出番でした。相変わらずの高機能です。

import pandas as pd

file = '/VideoEditor/src/VideoEditor.cpp'

with open(file) as f:
    lines = f.readlines()

# 改行コードを削除    
lines_strip = [line.strip() for line in lines]

df = pd.read_json('items.json')
print(df)

columns = df.columns.values
print(columns)

for col in columns:
    data = df.loc[:, col]
    # print(data.values)
    data2 = str(data.values[0]) + "," + str(data.values[1]) + "," + str(data.values[2]) + "," + str(data.values[3])
    print(data2)
    
    var_str = col + " = new"   
    print(var_str) 
    
    line_str = [line for line in lines_strip if var_str in line]
    
    try:
        line_str2 = line_str[0]
        print(line_str)
        str_exist = data2 in line_str2
        print(str_exist)
    except Exception as e:
        print(e)
395,70,90,45
convertArea = new
list index out of range
885,180,60,12
STDOUT = new
list index out of range
635,190,310,440
browser = new
['browser = new Fl_Browser(635,190,310,440,"STDOUT");']
True
895,95,50,30
comBtn = new
['comBtn = new Fl_Button(895,95,50,30,"結合");']
True
895,55,50,30
filBtn = new
['filBtn = new Fl_Button(895,55,50,30,"モザイク\\n作成");']
True
895,20,50,30
culcBtn = new
['culcBtn = new Fl_Button(895,20,50,30,"モザイク\\n追加");']
True

[Python] 348 Adobe XDのアイテムデータからJSONファイルを作成

[M1 Mac, Monterey 12.6.3, Python 3.10.4]

Adobe XDの自製プラグインで取得したアイテムデータからJSONファイルを作成しました。

これでアイテムの座標と幅・高さをコピー&ペーストしてC++コードを修正できます。

あとはJSONファイルをキーのアルファベット順でソートする位でしょうか。

時間があればC++コードの自動書き換えを検討します。

import json

with open("items.txt", "r") as tf:
    items_list = tf.read().replace("\n","").split(';')
    
# print(items_list)
# print(len(items_list))

# listからデータ抽出し、JSON文字列作成
json_str = ""
num = 0
for item in items_list:
    name = item.split("'")[1]
    print(name + "\n")
    
    xy = (item.split("global X,Y:")[1]).split("parent")[0]
    x = xy.split(",")[0]
    y = xy.split(",")[1]
    print(x + "\n")
    print(y + "\n")
    
    wh = (item.split("{")[1]).split("global")[0]
    w = (wh.split("width:")[1]).split(", height")[0]
    h = wh.split("height:")[1]
    print(w + "\n")
    print(h + "\n")
    
    if num == 0:
        json_str += "{\"" + name + "\"" + ":[" + x + ", " + y + ", " + w + ", " + h + "],\n"
    elif num < len(items_list) -1:
        json_str += "\"" + name + "\"" + ":[" + x + ", " + y + ", " + w + ", " + h + "],\n"
    else:
        json_str += "\"" + name + "\"" + ":[" + x + ", " + y + ", " + w + ", " + h + "]}"

    print(json_str + "\n")
    
    num += 1

# JSONファイル作成
file = open('items.json', mode='w')
file.write(json_str.replace(" ",""))
file.close()

[JavaScript] 15 Adobe XDのアイテムデータを取得するプラグイン作成 その3 テキスト出力

[M1 Mac, Monterey 12.6.3]

前回の続きです。

Pythonでは区切り文字付きテキストの方がリストのリテラル(機能のないただの文字列)より扱いやすいため、プラグインの内容を修正しました。

これでPythonスクリプトによりアイテムデータをリテラルのリストとして取得できます。あとは各要素から必要な数値を抽出してJSONに変換します。

JavaScriptの方は一応完成になります。

function myCommand(selection) {
    console.log(selection.items.length + " items are selected");

    let items_list = "";
    var num = 1;
    selection.items.forEach(function(value){
        // console.log(value);
        if (num < selection.items.length){
            items_list += value + ";";
        } else {
            items_list += value;
        }
        num += 1;
    });
    console.log(items_list);
}

module.exports = {
    commands: {
        GetItemXY: myCommand
    }
};
with open("items.txt", "r") as tf:
    items_list = tf.read().replace("\n","").split(';')
    
print(items_list)
print(len(items_list))

# ここからlistをJSONに変換する

[Python] 347 MySQLアプリ キャッシュ消去

[M1 Mac, Big Sur 11.7.2, Python 3.10.4, MySQL 8.0.31]

MySQLアプリのキャッシュを消去するスクリプトを書きました。

アプリ起動の都度キャッシュを消すようにすれば、デバッグもはかどります。

いつの間にかMySQLアプリの製作が、Python, PHP, JavaScriptの3言語を使った総力戦と化しています。

#コンソールコマンド実行

import subprocess

proc = subprocess.run("lsof -i:8890", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
result = proc.stdout.decode('UTF-8')

if "PID" in result :
    result_list = result.split(" ")
    
    # リストの空白データをトリミング
    result_list2 = [ele for ele in result_list if ele != '']

    # リスト10番目の要素がプロセスID
    id = result_list2[9]
    print(f'id : {id}')
    
    # プロセスIDをキャンセル
    cmd = f'kill {id}'
    proc2 = subprocess.run(cmd, shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
    
else:
    print('キャッシュはありません')

[Python] 346 MySQLアプリ クエリ中断

[M1 Mac, Big Sur 11.7.2, Python 3.10.4, MySQL 8.0.31]

実行中のクエリを中断するスクリプトを書きました。

Webアプリのボタンを押して中断させたかったのですが、今のところ私のスキルではできないので、このファイルを実行するシェルスクリプトを作成し、とりあえず完了としました。

シェルスクリプトをダブルクリックするとクエリを中断できます。

中断時のChrome
python stop_query.py
import MySQLdb

# MySQLに接続
conn = MySQLdb.connect(user='root')
cur = conn.cursor()

# プロセス確認
proc = f'show processlist;'
cur.execute(proc)
procs = cur.fetchall()

# 実行中クエリを中断
for row in procs:
    print(row)
    
    if 'executing' in row:
        id = row[0]
        print(f'id : {id}')
        kill = f'kill {id};'
        cur.execute(kill)
        
conn.close()

[Python] 345 MySQL自動検索 全テーブル対象 結果CSV化

[M1 Mac, Big Sur 11.7.2, Python 3.10.4, MySQL 8.0.31]

MySQLで自動検索し、ヒットした行の全データをcsvファイルにまとめるスクリプトを書きました。

文字列にリストとしての機能を付与するeval関数を思い出すのに少々時間がかかりました。

久しぶりにリスト内包表記を使いました。相変わらずの優れものです。

import time,datetime,subprocess,os,csv,glob
import MySQLdb

# 今日の日付
today = datetime.date.today()
today_str = str(today)[2:].replace('-','')
print(today_str)

# MySQLの起動確認
proc = subprocess.run("mysqladmin ping", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)
ping_result = proc.stdout.decode('UTF-8')
print(ping_result)

detect = "alive" in ping_result
if detect == False:
    os.system('mysql.server start')
else:
    print("MySQLは起動しています")

# MySQLに接続
conn = MySQLdb.connect(user='root')
cur = conn.cursor()

# 処理時間測定開始
start = time.time()

# データベースdataを選択
select_db = f"use data"
cur.execute(select_db)

# 全テーブルを取得
search_tables = f"show tables"
cur.execute(search_tables)
tables = cur.fetchall()
# print(f"tables : {tables}")

# 検索語と結果ファイル名の設定(同日同検索語の結果ファイルがあれば付番する)
key = 'suzuki'
csv_key = f"{today_str}_{key}"
csv_name = f"/code/Python/MySQL/csv/{today_str}_{key}.csv"
csvfiles = glob.glob(f'/code/Python/MySQL/csv/*.csv')

# リスト内包表記で同日同検索語の結果ファイル数をカウントする
csv_count = sum(csv_key in file for file in csvfiles)
if csv_count > 0:
    print(f'csv_count :{csv_count}')
    csv_num = csv_count + 1
    csv_name = f"/code/Python/MySQL/csv/{today_str}_{key}_{csv_num}.csv"

# 検索
hit = 0
num = 0
for table in tables:
    table2 = str(table).replace('(','').replace(')','').replace(",",'').replace("'",'`')
    print(f"table : {table2}")
    
    search = f"SELECT * FROM {table2} WHERE `Name` LIKE '%{key}%'"
    cur.execute(search)
    rows = cur.fetchall()

    for row in rows:
        print(row)
        row_str = str(row).replace('(','[').replace(')',']')
        print(row_str)
        with open(csv_name, 'a') as f:
            writer = csv.writer(f)
            writer.writerow(eval(row_str))
        hit = hit + 1
 
    # 処理時間算出(秒)
    process_time = time.time() - start
    td = datetime.timedelta(seconds = process_time).total_seconds()

    # 小数点第2位まで表示
    td_2f = f'{td:.2f}'
    print(td_2f)
    
    num = num + 1
    
    # テスト用(1テーブルのみ検索)
    # if num == 1:
    #     break
    
print(f'HIT数 :{hit}')

conn.close()
os.system('mysql.server stop')