自分の環境
- OS: Windows10 Pro 64ビット (Version 20H2)
- CPU: Intel Core i7-6700
- メモリ: 16GB
使用したアプリ
- Anaconda3-2020.10
- Visual Studio Code
- Google Chrome 87.0.4280.66(Official Build)
使用するライブラリ
- selenium 3.141.0
- chromedriver-binary 87.0.4280.20.0
- opencv-python 4.4.0.46
- pillow 8.0.1
Anaconda Prompt (管理者)を起動する
pipのアップデートがあるか確認
pip install --upgrade pip
ブラウザの操作を自動化するseleniumをインストールします。
pip install selenium
chromeバージョン更新と確認
なるべく更新してほしいのですが、chrome://settings/help で確認してください。
更新したくない場合chrome://versionで確認できます。
今回の私の環境でのバージョンは「87.0.4280.66」でした。
なのでこの「87.0.4280.66」を使ってインストールしていきます。
#バージョンによってこの数字を変える
pip install chromedriver-binary==87.0.4280.66
するとこんなエラーが出ました。
そんなバージョンなんてないぞ と怒られてしまいました。
なのでこの赤文字の中から青線で囲った一番最新のバージョンを指定します。
更新していない方はそのバージョンに一番近いものを選んでください。
##Seleniumを使ってフォームを送信させる
Google Formはフォームに各質問を識別させる番号ありURLの最後にパラメータを付加させることで質問の値を入力した状態でURLを開くことができます。
このフォームではメールアドレスを取得しない設定なのでこのフォームでスクリプトを試す場合は 下欄のログイン処理の箇所をコメントアウト してください。
上記リンクを開くとわかるように、entry.366340186=36.
を付け足すことで、最初から入力できていると思います。
黒枠で囲ったところが識別番号です。F12キーを押し検証画面で質問のdivを探し、以下のような番号を探します。
番号が探せたらentry.識別番号=値
の形でパラメータを付加させます。これを応用させて、seleniumを使って毎日ランダムで温度を送信できるようにします。
コードの意味
# 体温を36.1~36.7の中からランダムで選ばせる
bodytemp = str(36 + random.randint(0, 7) / 10)
# 送信したいフォームのURLを指定
url = 'https://docs.google.com/forms/d/e/1FAIpQLSf82M_QmbdzwphCwID2WyTwQAXbTlep89z5Lj-uB0NDX3ZFVQ/viewform?entry.366340186=' + bodytemp
URLが完成したら、あとはSeleniumでURLを開いて送信ボタンを押してもらうだけですね。
なお、ログインが必要なフォームな場合は毎回ログインが必要なので自動でログインする機能も実装しています。
ログインする必要がないフォームの場合は、これらをコメントアウトしてください
# メールアドレス指定
login_id = "メールアドレス" #ここに入力する
email_form = driver.find_element_by_name("identifier")
email_form.send_keys(login_id)
email_form.send_keys(Keys.ENTER)
time.sleep(1)
# パスワード指定
login_pw = "パスワード" #ここに入力する
passwd_form = driver.find_element_by_name("password")
passwd_form.send_keys(login_pw)
passwd_form.send_keys(Keys.ENTER)
time.sleep(1)
送信した時刻と体温を画像に出力させる
ちゃんと動作して送信できていても、毎日送信できているか心配ですよね...
なので送れているのかを確認するために、送信完了画面のキャプチャを撮ってもらい、OpenCVとPILを使って時刻と送信時の体温を入力する機能を実装しました。画像がなければ何かしらのエラーが起きていて、送れていないことがわかります。
# スクショ
driver.save_screenshot("temp.png")
# 画像に文字を入れる関数
def img_add_msg(img, message):
font_path = "C:\Windows\Fonts\meiryo.ttc" # Windowsのフォントファイルへのパス
font_size = 24 # フォントサイズ
font = ImageFont.truetype(font_path, font_size) # PILでフォントを定義
img = Image.fromarray(img) # cv2(NumPy)型の画像をPIL型に変換
draw = ImageDraw.Draw(img) # 描画用のDraw関数を用意
# テキストを描画(位置、文章、フォント、文字色(BGR+α)を指定)
draw.text((50, 500), message, font=font, fill=(0, 0, 0, 0))
img = np.array(img) # PIL型の画像をcv2(NumPy)型に変換
return img # 文字入りの画像をリターン
img2 = cv2.imread("temp.png", 1) # 画像読み込み
cr = "\n"
mail = "メール: "
dt_now = datetime.datetime.now() # 時刻取得
char1 = "送信時間: "
char2 = " ℃で送信しました。"
message = (char1 + dt_now.strftime("%Y年%m月%d日 %H:%M:%S\n") + (body_temp) + char2) # 画像に入れる文章
img = img_add_msg(img2, message) # img_add_msgを実行
cv2.imwrite(("./a.png"), img) # 画像書き込み
cv2.waitKey(0)
cv2.destroyAllWindows()
os.rename("./a.png", "{0:%Y%m%d_%H%M%S}.png".format(dt_now)) # 時刻にリネーム
os.remove("temp.png") # 一時ファイルを削除
タイムスケジューラで7時~8時までにランダムで起動
プログラムも正常に動いたら、いよいよタイムスケジューラで自動的に起動して送信してもらいます。
[Win]+[R]を押して「control schedtasks」と入力を押して、[OK]を押します。
起動できたら左側の「タスクスケジューラライブラリ」に移動して、右の「基本タスク作成」をクリックします。
これは、PATHが通っていれば[python.exe]です。通っていない方は、pythonの場所を指定してください。
今回私は Desktop に体温というフォルダーを作り、その中に実行プログラムが置いてあります。
なので、引数と開始は
#プログラムファイルを指定
C:\Users\ユーザ名\Desktop\体温\auto_bodytemp.py
#そのプログラムがあるフォルダを指定
C:\Users\ユーザ名\Desktop\体温
になります。
まだ設定することがあるので、
[完了]をクリックしたときに、このタスクの[プロパティ]ダイアログを開く
をクリックしてから完了をクリックしてください。
設定項目ですが、
- タスクの開始は [スケジュールに従う]
- 設定が [毎日]、開始が今日にして、7時に起動するので [7:00:00] にする
- 間隔は [1日] にする
- 詳細設定の [遅延時間を指定する(ランダム)] にチェックを入れて、[1時間] に設定する
- [有効] にチェックを入れないと詳細設定が動きません。
次は、[設定] タブに移動して、これらを設定してください。
- タスク要求時に実行する
- スケジュールっされた時刻にタスクを開始できなかった場合、すぐにタスクを実行する
- タスクが失敗した場合の再起動の間隔 は1分間で再起動試行の最大数は5回
- タスクを停止するまでの時間は1時間
- 要求時に実行中のタスクが終了しない場合、タスクを強制的に停止する
これらが設定が出来たら終了です! [完了]をクリックしてください。
いよいよタスクを実行します!
新しく出来たタスクを右クリックして[実行する]をクリックしたら動作することを確認してください。
コード
以下は私が作成したコードです。
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import random
from PIL import Image, ImageFont, ImageDraw
import cv2
import numpy as np
import datetime
import chromedriver_binary
import time
import os
# 体温を36.1~36.7の中からランダムで選ぶ
bodytemp = str(36 + random.randint(0, 7) / 10)
# 送信したいフォームのURLを指定
url = 'https://docs.google.com/forms/d/e/1FAIpQLSf82M_QmbdzwphCwID2WyTwQAXbTlep89z5Lj-uB0NDX3ZFVQ/viewform?entry.366340186=' + bodytemp
# ログをCriticalまで表示させない
options = webdriver.ChromeOptions()
options.add_experimental_option("excludeSwitches", ["enable-logging"])
options.add_argument("log-level=3")
options.add_argument("--no-sandbox")
options.add_argument("--disable-gpu")
# Chromeで自動動作
driver = webdriver.Chrome(options=options)
driver.implicitly_wait(5)
# URLに遷移
driver.get(url)
# メールアドレス指定
login_id = "メールアドレス" #ここにメールアドレスを入力する
email_form = driver.find_element_by_name("identifier")
email_form.send_keys(login_id)
email_form.send_keys(Keys.ENTER)
time.sleep(1)
# パスワード指定
login_pw = "パスワード" #ここにパスワードを入力する
passwd_form = driver.find_element_by_name("password")
passwd_form.send_keys(login_pw)
passwd_form.send_keys(Keys.ENTER)
time.sleep(1)
# GoogleFromの送信ボタンを押す
submit_button = driver.find_element_by_class_name("exportButtonContent")
submit = driver.find_element_by_class_name("appsMaterialWizButtonPaperbuttonLabel")
time.sleep(1)
submit.click()
# スクショ
driver.save_screenshot("temp.png")
# 画像に文字を入れる関数
def img_add_msg(img, message):
font_path = "C:\Windows\Fonts\meiryo.ttc" # Windowsのフォントファイルへのパス
font_size = 24 # フォントサイズ
font = ImageFont.truetype(font_path, font_size) # PILでフォントを定義
img = Image.fromarray(img) # cv2(NumPy)型の画像をPIL型に変換
draw = ImageDraw.Draw(img) # 描画用のDraw関数を用意
draw.text((50, 500), message, font=font, fill=(0, 0, 0, 0)) # テキストを描画(位置、文章、フォント、文字色(BGR+α)を指定)
img = np.array(img) # PIL型の画像をcv2(NumPy)型に変換
return img # 文字入りの画像をリターン
img2 = cv2.imread("temp.png", 1) # 画像読み込み
cr = "\n"
mail = "メール: "
dt_now = datetime.datetime.now() # 時刻取得
char1 = "送信時間: "
char2 = " ℃で送信しました。"
message = (mail + login_id + cr + char1 + dt_now.strftime("%Y年%m月%d日 %H:%M:%S\n") + (bodytemp) + char2) # 画像に入れる文章
img = img_add_msg(img2, message) # img_add_msgを実行
cv2.imwrite(("./a.png"), img) # 画像書き込み
cv2.waitKey(0)
cv2.destroyAllWindows()
os.rename("./a.png", "{0:%Y%m%d_%H%M%S}.png".format(dt_now)) # 時刻にリネーム
os.remove("temp.png") # 一時ファイルを削除
driver.close()
driver.quit()