見出し画像

まずは、RPAから その1

 とりあえず、日々の繰り返し作業を自動化する、つまりRPA(Robotic Process Automation)が初めて取り組むにはいいだろうということで、作ることにしました。
 実は、RPAは、MicrosoftPower Automate Desktopを最初に導入しました。しかしながら、
設定するのが結構手間(なんでも最初はそうですが)
頻繁に更新があり面倒(最近はなぜか毎度)
なぜか、いつも同じところでエラーで止まる(2度目以降で成功するので設定の問題ではない?)
 という切実な問題もあって、UiPathかとも思ったんですが、設定の手間がトラウマで手がつかない、じゃあ、得意なところでプログラミングしてしまおうと。

 しかしながら、PHPではちょっと無理。Webスクレイピングは可能でちこっと作ったこともあるけど、ローカルのパソコンのアプリを実行したりができない(という先入観?)。
 なので、簡単に作れるというPythonをやってみることに。
 とはいえ、Pythonへの取り組みが初めてかと言うと・・・実は、数年前から取り組もうと何冊もハウツー本を購入したし、仕事でも3カ月ほど触れたこともあり、まったく知らないわけではない。自分の意志で触ったことがないだけでした。

 申し訳ありませんが、Windows10環境での話です。

 まずは、Pythonの導入から・・・
 今回のRPAで必要になったのは以下の通り。
・Python
  最新版のpython-3.10.5をダウンロードして実行。
   ※ダウンロードに際して「Add Python3.x to PATH」にチェックを入れるのを忘れないように。あとでPythonパッケージのインストールを行うユーティリティpipを使えなくなるので。

画像1

・webdriver_manager
 ブラウザを操作するためのドライバ。これを入れないと、ブラウザごとに個別の(ブラウザもそうだけど、バージョンも)driverをダウンロードしなくてはならなくなる。
 ここからコマンドプロンプトか、Windows powershellでpipを使う。
  pip install webdriver_manager

・selenium
 
ブラウザー自動化を可能にし、それを支えるツール群とライブラリー群プロジェクトだそうで、Webアプリケーションをテストするためのポータブルフレームワークでもあるとかで、便利そう。
  pip install selenium

・PyAutoGui
 マウスやキーボード操作を自動化してくれる便利ライブラリ。
  pip install PyAutoGui

 ここまでがpipしたいライブラリ等で、Pythonがそもそも持っているライブラリやモジュールで使うのが、以下の通り。
 ・time
  経過時間を測定したり、2つの日時(日付・時刻)の差分(時間差)を算出したりできる。
 ・subprocess
  他プロセス呼び出しライブラリ。
 ・platform
  実行中プラットフォームの固有情報を参照する

 いざプログラミング・・・
 今回は、Python IDLEを使ったプログラミング。次号以降でEditorとかいろいろ使い方を書いていきます(なにせ覚えたてで書いているので)。
 Python IDLEFiley→New File...で適当にモジュールファイルを作成します。untitledという空のモジュールが立ち上がります。

画像2

 初頭にこのRPAで使うライブラリ等を導入宣言します。
 インポートは「,」でまとめることが可能であり、また、as で、そのライブラリ等を短縮化(別名でインポート)することもできます。

import time, subprocess, platform
import pyautogui as pa

 次に、pipしたモジュール類を導入します。

from selenium import webdriver
from selenium.webdriver.common.by import By
from datetime import datetime
from datetime import timedelta

 最初は、seleniumからwebdriverを持ってくる、次は、seleniumwebdrivercommonbyからByを使えるようにする、次はdatetimeからdetetimeを、また、timedeltaを使えるようにする・・・と言ったところですね。
 実際の使い方は、これから書きます。

 次に、使用するブラウザの指定をします。ここで、ドライバが出てきます。Chromeを使います。

# ChromeDriver(WebDriver)を自動更新
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(ChromeDriverManager().install())

 「#」はコメントになります。複数行ある場合は、前後を「"""」で囲めばできます。
 これにより、Chromeのバージョンに合ったドライバを勝手に持ってきてくれるそうです。
 ちなみに、ほかのブラウザを使う場合の例は次の通りです。

# FirefoxのGeckoDriverを自動更新
from webdriver_manager.firefox import GeckoDriverManager
driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())

# Internet ExplorerのIEDriverを自動更新
from webdriver_manager.microsoft import IEDriverManager
driver = webdriver.Ie(IEDriverManager().install())

# EdgeのMicrosoftWebDriver/EdgeChromiumDriverを自動更新
from webdriver_manager.microsoft import EdgeChromiumDriverManager
driver = webdriver.Edge(EdgeChromiumDriverManager().install())

 safariMacのことなので、機会があれば。
 driverという名前(インスタンス)は、予約語(機会があれば)以外であればなんでもいい。browserとか。
 いくつもブラウザを開くときは、draiver_1とかで個々に設定します。
 これで、この場合、Chromeブラウザを自在に使うことができるようになります。
 このChromeブラウザを使って、あるサイトを開き、IDとパスワードを自動で入力し、必要な日付を自動で入力し、得られたデータをテキストファイルに書き込みます。
 defを使って関数を作りますが、別にそうする必要はなく、ベタに書いても動作します。ちょっとプロっぽく関数にします。

def site_open():
    # Chromeドライバを使ってサイトを開く
    driver = webdriver.Chrome(ChromeDriverManager().install())
    driver.get('https://chat.kimochi-tengoku.online/master')

 defは、ここから関数が始まるという宣言(PHPJavaだとpublic functionに当たる)で、関数名を置く。関数は()で完結するし、その()内にこの関数に渡す引数を指定することもできます。
 関数を宣言して「:」を書いたあと、関数内の処理が始まり、ここがPythonらしい(Rubyも・・・?)ところで、インデントを入れたところがすべて処理内容になります。つまり、インデントがなくなるところが処理の終わりということになります。通常4スペースですが、決まりはないそう。
 関数内にさらに関数を作る場合も、その関数の部分はさらにインデントを置くことになります。

    # IDであるメールアドレスとパスワードを自動で入力
    e_name = driver.find_element(By.NAME, 'inputEmail')
    e_pwd = driver.find_element(By.NAME, 'inputPassword')
    e_btn = driver.find_element(By.CLASS_NAME, 'btn')

 行の最初が変数になります。PHPのように「$」を付けることはない。変数は予約語でなければよく、半角英字で始まること。
 Python3かららしいですが、サイトのタグにアクセスする場合の構文。ここで、seleniumwebdrivercommonbyからByを使えるようにしているわけです。タグの要素はほぼ使えるようです。上の例では、nameclassに指定した名称を使っています。

   e_name.send_keys('fortuner@kimochi-tengoku.online')
   e_pwd.send_keys('xxxxxxx')  # 隠してます
   e_btn.click()
   time.sleep(2)

 インスタンスにした変数に入力するのがsend_keysとなります。
 そして、ボタンを自動でクリックします。
 sleepは待ち時間=秒です。ボタンを押して結果がでるまで、つまり、サーバーにIDとパスワードを送り、その結果としてサイトが開く、その通信時間をみています。2秒じゃ長いのか短いのか、なんとも言えません。適当です。

   e_birthday = driver.find_element(By.ID, 'birthday')
   e_btn2 = driver.find_element(By.CLASS_NAME, 'birth-btn')
   e_doom = driver.find_element(By.ID, 'birthday_doom')
   e_kabbala = driver.find_element(By.ID, 'kabbala')
   e_close = driver.find_element(By.ID, 'logoutBtn')   

 サイトが開いてから、改めて、インスタンスを作ります。
 あたりまえですが、サイトが開くまで、そのサイト内のタグ要素は利用できません。ここではID要素も使ってます。

   dt1 = datetime.now() + timedelta(days=1)
   print(dt1)
   dt2 = "{0:%Y%m%d}".format(dt1)
   e_birthday.send_keys(dt2)
   time.sleep(1)
   e_btn2.click()
   time.sleep(2)

 timedeltaがここに出てきました。datetimeで取得した日付に対して足したり引いたりします。
 ここでは、1日足して、明日の日付を設定しています。
 printは、PythonIDLEに出力するコマンドになります。どんな結果が得られたか見たい時に使うので、なくても問題ありません。
 明日の日付を入力の形式に合うようにフォーマットしています。このサイトでは年月日を西暦年月日8桁を要求しています。最初の「0:」はformat対象の0番目、つまりここではdt1についてフォーマットしますよ、ということらしい。ふぅーん。

   print(e_doom.text)
   print(e_kabbala.text)
   e_text = e_doom.text + "\n" + e_kabbala.text

 最後の行の「+」は、ここでは文字列の結合です。変数がそのままだったり、変数に特にデータ型を必要としなかったり、Javascriptみたいなところがありますね。

   e_close.click()
   driver.close()

   return e_text

 サイトを閉じ、ブラウザも閉じて、得た文字列を返します。

def text_writing(e_text):
    with open(r'C:\Users\ich_j\OneDrive\Documents\占い\誕生日\占い.txt', mode='w') as f:
         f.write(e_text)

    subprocess.Popen(['start', r'C:\Users\ich_j\OneDrive\Documents\占い\誕生日\占い.txt'], shell=True)

 text_writingという関数は、e_textという引数(site_openで返された文字列の入った変数)を受け取り、それをテキストファイルに書き込み、書き込んだテキストファイルを編集可能なように開きっぱなしにします。
 このシステムでは、テキストファイルに書き込まれてデータをさらに利用する予定だからです。それもいずれは自動化するかもしれません。
 with openは、指定のファイルを開き、処理後自動的に締まるコマンドです。mode="w"は、書き込み用だということです。ただの"w"でもできるようです。ファイルの前の「r」は、''内の文字列をそのまま、つまり、エスケープを無効化します。ない場合、C:\\といった書き方をすることになります。
 テキストファイルも開きっぱなし(ブラウザに出力)にするにはアプリケーションとして開かないとなりません。それが、subprocess.Popenとなります。
 ファイルの場合はstart、フォルダの場合はexplorerを指定します。ファイルを開く(実行する)場合、Windowsの場合は、shellTrueに指定する必要があるとのこと。これにより指定のコマンドはシェルつまりコマンドプロンプトによって実行されるとのことです。

 いよいよ締めです。
 今まで関数としてご案内してきました。なので、その関数を呼んで実行させる部分が必要となります。
 なぜか、文末に置くようです。

if __name__ == "__main__":
   e_text = site_open()
   text_writing(e_text)

 わざわざmainにする必要はなく、
  e_text = site_open()
  text_writing(e_text)

という書き方でも動作します。site_openで返されたデータe_texttext_writingに渡してテキストファイルに書き込み、そのファイルを開きっぱなしにする。
 ぼくも、初めてif __name__ == "__main__":はどんなおまじないかと不審でならなかったのですが、文字通りおまじないでしかないようです。まあ、明示的に、ここから始まりますよ、ということにする、のが、プロっぽいということでしょう。
 こうして作り込んだモジュールを保存します。untitledモジュールをFile→Save As...でモジュール名と場所を決めて保存します。
 編集する場合は、IDLEFile→Open...で既存モジュールを開けます。
 保存すると、モジュールの実行ができます。RunRun Module。若干遅まきに実行されますし、subprocess.Popenのためにコマンドプロンプトが開きっぱなしになります。

 以上が、ぼくが今回初めて意識してPythonを作った経緯です。
 ここで、実際の実行を動画に・・・

 今後、さらにPythonのプログラミングについて研鑽していくつもりです。
 予定としては、
わざわざモジュールをIDLEで開いてRunしなくても、いわゆる実行ファイルにして即時実行できるようにする
・subprocess.Popenのために開いたコマンドプロンプトが自動的に閉じるようにする
実行ファイルを指定しなくても画面のアイコンを使ってアプリケーションが実行できるようにする
といったところを考えています。
 ぼちぼち作っていきますので、それなりにご期待ください。

 ながながと記述しましたが、超初心者のお役に立てれば、と思います。
 初心者でない方がここまでお読みいただいたのであれば、不適切な部分をご指摘いただければとも願っています。

 ありがとうございました。

この記事が気に入ったらサポートをしてみませんか?