Seleniumを使ってGoogle ChromeからCSVファイルをアップロードしてみました-Pythonを学ぶ(4)

(4)プログラム初心者がPythonを勉強してみる39日目

つぶ式ではコンテンツ連動型広告やアフィリエイト広告を利用しています。

情報収集の為のPython

Seleniumから勉強してみようということで書いてみましたw

前回記事はこちら

毎日の作業を自動化してみよう

前回記事に書いた

「スクレイピングのライブラリをどれから勉強したらいいかわからない」状態になっていました。

「とりあえず何か書かないと……」

仕事で毎日”あるサイト”に複数のcsvファイルを手作業でアップロードしています。

それを自動化してみよう!と試行錯誤( ・`д・´)

Python初心者の初コードなので、汚いコードで間違いだらけだと思うのですがその点はご了承ください……w

初めてのPythonコード

目的 : ブラウザからの”csvファイルをアップロード”自動化

言語 : Python

使用ライブラリ : Selenium

使用ブラウザ : Google Chrome

Python初心者が書いたプログラムです!

このコードを使用してもらえるのはスーパーミラクル光栄ですが、

何が起きても自己責任でお願いします!ごめんなさい!!

プログラミング初心者が書いたPythonコードです!

このコードを使用してもらえるのはスーパーミラクル光栄ですが、
何が起きても自己責任でお願いします!ごめんなさい!!

【注意点・仕様・備考】

  • Windowsで実行
  • サイトにはログインが必要
  • アップロードするcsvファイルは複数
  • アップロード完了時にダイアログが表示される
  • 稀にアップロード失敗するので2回繰り返し(ループになるとだめなので2回まで)
  • アップロード完了csvファイルの記録をとりたい
  • アップロード後に表示されるページに表示されたテキストの記録をとりたい
  • 完了メッセージを表示したい

フォルダ・ファイル構成

pythonstudy/
├ sample.py
├ chromedriver.exe
├ csvlist.txt
├ finmassege.txt
└ csv/
   └[アップロードしたい.csv]

コード

コードの後に処理ごとの説明を記載しています。

説明から読みたい方はコチラからどうぞ

from selenium import webdriver 
from selenium.webdriver.common.alert import Alert
import time
import os
import wx
import sys

#サイトログインページ情報とログイン情報をまとめる
TOP_URL = "example.com"
UPLOAD_URL = "http://hogehoge.example/"
ID = "id"
PASSWORD = "password"

#ディレクトリを取得
dir_name = (os.path.dirname(__file__))
dir_name = dir_name.replace('\\', '/') #Windows用?に\を/に置換

#完了メッセージ表示用のwxPython
wx_app = wx.App()

#ブラウザ読み込み
driver = webdriver.Chrome("./chromedriver.exe") #chromedriver.exe読み込み
driver.set_page_load_timeout(600) #ページロード最大600秒
driver.get(TOP_URL) #chrome起動→ログインページに移動

time.sleep(1)

#ログイン
id = driver.find_element_by_name("loginid")
id.send_keys(ID)
password = driver.find_element_by_name("password")
password.send_keys(PASSWORD)

time.sleep(1)

#ログインボタンをクリック
login_button = driver.find_element_by_name("login")
login_button.click()

time.sleep(1)

#csv一覧のテキストファイルを読み込みで開いてリストに
csv_list_file = open('./csvlist.txt', 'r') #csvファイルの一覧テキストファイルを読み込み
csv_list = csv_list_file.readlines()
csv_list_file.close()

#csv一覧からできたリスト分繰り返し
for i in range(len(csv_list)):

    #csvを読み込ませるページに移動
    driver.get(UPLOAD_URL)

    time.sleep(1)

    #ファイルの絶対パスを変数に ファイルは/csv/にある
    file_choice_str = dir_name + '/csv/' + csv_list[i].rstrip()

    #ファイル読み込み
    file_choice = driver.find_element_by_name("fileupload")
    file_choice.send_keys(file_choice_str)

    time.sleep(1)

    #アップロードボタンをクリック
    now_upload = driver.find_element_by_class_name("uploadbotton")
    now_upload.click()

    time.sleep(1)

    #読み込み停止時再実行の為の変数設定
    loop_count = 0

    #読み込み停止時再実行用繰り返し
    while True:

        #再実行しすぎを防止
        loop_count += 1

        if loop_count >= 3:
            #エラーメッセージボックスを表示
            wx.MessageBox('3回失敗', 'Python')
            #エラーが続いたのでプログラムを終了
            sys.exit()

        try:
            #ダイアログの表示取得
            alert_text = Alert(driver).text

            #取得した文字列を表示
            print(alert_text)

            #ダイアログのOKを選択
            Alert(driver).accept()

            time.sleep(1)

            #whileを抜ける
            break

        except:
            print("読み込みエラー")

    #ブラウザに表示されたメッセージを取得
    fin_massege = driver.find_element_by_class_name("massege")
    fin_massege_str = fin_massege.text #文字列として変数に代入
    #複数行の場合改行を半角スペースに置換して1行に、行末に改行
    fin_massege2 = csv_list[i].rstrip() + fin_massege_str.replace("\n"," ") + "\n"
    print(fin_massege2)

    #完了ログ用テキストを開いて追記
    fin_massege_txt = open('./finmassege.txt', 'a')
    fin_massege_txt.write(fin_massege2)
    fin_massege_txt.close()

    #読み込みが完了したcsvをテキストから削除して上書き(実際には作り直し)
    csv_list_file = open('./csvlist.txt', 'r') #読み込み専用で開く
    csv_list2 = csv_list_file.readlines() #行ごとにリスト化
    del csv_list2[0] #1行目にあたるリスト0番目を削除
    csv_list_file = open('./csvlist.txt', 'w') #書き込み専用で開く(この時にテキストファイルは空白になる)
    csv_list_file.writelines(csv_list2) #0番目を削除したリストをテキストファイルに
    csv_list_file.close() #テキストファイルを終了

    #繰り返しの為の初期化
    alert_text = ""

#ブラウザを閉じる
driver.close()

#完了メッセージボックスを表示
wx.MessageBox('完了', 'おっPython')

説明

コードの中身の解説をしていきたいと思います。

読み込み部分

from selenium import webdriver 
from selenium.webdriver.common.alert import Alert
import time
import os
import wx
import sys
  •  ブラウザ操作の為の selenium
  • ダイアログを操作する為の alert
  • 負担軽減の為の time
  • テキストファイル操作の為の os
  • 完了メッセージ表示の為の wx
  • 無限ループ時にプログラム終了させる為の sys

以上のライブラリを読み込んでいます。

ページ情報とログイン情報をまとめる

#サイトログインページ情報とログイン情報をまとめる
TOP_URL = "example.com"
UPLOAD_URL = "http://hogehoge.example/"
ID = "id"
PASSWORD = "password"

ログインページのURLとアップロードページのURLが別なのでそれぞれを変数に代入しています。

ログインIDとパスワードもそれぞれ変数に代入しました。

ディレクトリ取得

#ディレクトリを取得
dir_name = (os.path.dirname(__file__))
dir_name = dir_name.replace('\\', '/') #Windows用?に\を/に置換

テキストファイルを操作するためにファイルの場所を取得しています。

.pyファイルとcsv一覧や完了メッセージ記録のテキストは同一ディレクトリに設置。

ディレクトリを取得したときにパスが ”\” (バックスラッシュ)になっているので “/” (スラッシュ)に置換しています。

この部分はもっといい方法がありそうですね……

 完了メッセージを出力するためにwxPythonを読み込ませる

#完了メッセージ表示用のwxPython
wx_app = wx.App()

PythonでGUIを操作するwxPythonを読み込んでいます。

Seleniumでいう”driver = webdriver.hogehoge”と同じようなもんですかね。

Selenium用のchromedriverを読み込ませる

ブラウザ読み込み
driver = webdriver.Chrome("./chromedriver.exe") #chromedriver.exe読み込み
driver.set_page_load_timeout(600) #ページロード最大600秒
driver.get(TOP_URL) #chrome起動→ログインページに移動

time.sleep(1)

前回紹介した記事を参考にchromedriverを読み込ませます。

csvファイルのアップロードには時間がかかる場合もあるので待ち時間を長めに設定しました。

2~3分で終わるけども10分で設定しています。

リファレンスを参考にdriver.set_page_load_timeout(*)で待ち時間を設定。

接続先への負担分散の為にページ遷移後には1秒の待機を設定。

IDとパスワードを入力してログインボタンをクリック

#ログイン
id = driver.find_element_by_name("loginid")
id.send_keys(ID)
password = driver.find_element_by_name("password")
password.send_keys(PASSWORD)

time.sleep(1)

#ログインボタンをクリック
login_button = driver.find_element_by_name("login")
login_button.click()

time.sleep(1)

send.key().click()を使ってログイン情報を入力してログイン。

ここでもページ遷移後には1秒の待機を設定しています。

読み込ませるcsv一覧のテキストを読み込み

#csv一覧のテキストファイルを読み込みで開いてリストに
csv_list_file = open('./csvlist.txt', 'r') #csvファイルの一覧テキストファイルを読み込み
csv_list = csv_list_file.readlines()
csv_list_file.close()

プログラムと同一ディレクトリに保存しているcsvlist.txtに読み込ませるcsvファイル名をまとめています。

csvlist.txtの内容

product001.csv product002.csv product003.csv product004.csv product005.csv

テキストファイルを読み込み専用で開いて、1行ずつリストに格納しています。

読み込みが終わるとテキストを閉じます。

リストの分繰り返し

#csv一覧からできたリスト分繰り返し
for i in range(len(csv_list)):

    #csvを読み込ませるページに移動
    driver.get(UPLOAD_URL)

    time.sleep(1)

for を使って繰り返しを設定しています。

繰り返し先頭でアップロードページへ移動させています。

アップロードするcsvファイルのパスを変数に設定してアップロード

    #ファイルの絶対パスを変数に ファイルは/csv/にある
    file_choice_str = dir_name + '/csv/' + csv_list[i].rstrip()

    #ファイル読み込み
    file_choice = driver.find_element_by_name("fileupload")
    file_choice.send_keys(file_choice_str)

    time.sleep(1)

    #アップロードボタンをクリック
    now_upload = driver.find_element_by_class_name("uploadbotton")
    now_upload.click()

    time.sleep(1)

アップロードするcsvファイルは/csvフォルダに置いています。

下記記事を参考に.send_keysを使ってcsvファイルのパスを読み込ませています。

アップロードボタンをクリックさせて待機。

読み込みエラーの対応とダイアログの確認・ダイアログ選択

#読み込み停止時再実行の為の変数設定
    loop_count = 0

    #読み込み停止時再実行用繰り返し
    while True:

        #再実行しすぎを防止
        loop_count += 1

        if loop_count >= 3:
            #エラーメッセージボックスを表示
            wx.MessageBox('3回失敗', 'Python')
            #エラーが続いたのでプログラムを終了
            sys.exit()

        try:
            #ダイアログの表示取得
            alert_text = Alert(driver).text

            #取得した文字列を表示
            print(alert_text)

            #ダイアログのOKを選択
            Alert(driver).accept()

            time.sleep(1)

            #whileを抜ける
            break

        except:
            print("読み込みエラー")

稀に読み込みエラーダイアログ表示されずにページ遷移してしまうことがありました。


csv読み込み後にダイアログが表示されずにページ遷移した場合、

try:で設定したAlert(driver).textが取得できずエラーになるので

except:のコードが実行されます。


except:にはbreakを記述していないのでwhileのループが働いて自動再実行の為に繰り返しが発生します。


エラーが3回繰り返された時にはメッセージボックスを表示させてプログラムを終了したいので

以下記事を参考にエラーメッセージを表示させるメッセージボックスを設定しました。

wxPythonを使ったメッセージボックス表示に関する詳しい記事がなかなかみつからなかったので苦戦していましたのでとてもありがたい記事でしたw

エラーが繰り返されているのでプログラムを終了させます。

以下記事を参考にしてエラーが出た場合に終了を設定しました。

正しくcsvファイルが読み込まれた場合、ダイアログが表示されます。

ダイアログの内容を取得して、ダイアログのOKを選択しています。

読み込み完了のメッセージを取得して改行取り除く

    #ブラウザに表示されたメッセージを取得
    fin_massege = driver.find_element_by_class_name("massege")
    fin_massege_str = fin_massege.text #文字列として変数に代入
    #複数行の場合改行を半角スペースに置換して1行に、行末に改行
    fin_massege2 = csv_list[i].rstrip() + fin_massege_str.replace("\n"," ") + "\n"
    print(fin_massege2)

.find_element_by_class_name("*")で要素を変数に代入します。

そのままだとエラーになってしまうので.textを使用して文字列のみを別の変数にします。

読み込ましたcsvファイル名と表示メッセージを結合して改行を半角スペースに置換しました。

完了ログをテキストに残す

    #完了ログ用テキストを開いて追記
    fin_massege_txt = open('./finmassege.txt', 'a')
    fin_massege_txt.write(fin_massege2)
    fin_massege_txt.close()

完了ログを記録したいテキストファイルを同じディレクトリに用意しておきます。

finmassege.txtとして、追記モードで開いて書き込みして、閉じる処理をしています。

再実行したときに重複アップロードを防ぐ為にリストを編集します

    #読み込みが完了したcsvをテキストから削除して上書き(実際には作り直し)
    csv_list_file = open('./csvlist.txt', 'r') #読み込み専用で開く
    csv_list2 = csv_list_file.readlines() #行ごとにリスト化
    del csv_list2[0] #1行目にあたるリスト0番目を削除
    csv_list_file = open('./csvlist.txt', 'w') #書き込み専用で開く(この時にテキストファイルは空白になる)
    csv_list_file.writelines(csv_list2) #0番目を削除したリストをテキストファイルに
    csv_list_file.close() #テキストファイルを終了

途中でプログラムが停止した場合の”念のため”csv一覧のテキストファイルを1行目から削除します。

読み書き専用のr+w+でファイルを開くと開いた段階でテキストファイルの中身が消えてしまいました。

なんでや……w

なので一度読み取り専用で開いて、行ごとにリストに格納しています。


1行目にあたるリスト0番目を削除して、テキストファイルを書き込み専用で開きます。

書き込み専用で開いてリストで全上書き。

.close()と同時に上書き保存。

r+w+a+の違いがわからん、難しい/(^o^)\

繰り返しの為に初期化

    #繰り返しの為の初期化
    alert_text = ""

Pythonにも変数の初期化って必要ですか……?w

エラー繰り返しの表示でおかしくなる可能性があるので変数初期化しています。

いま考えると他にも初期化しないといけないような変数あるりますね……w

まぁいっか\(^o^)/

ブラウザを閉じてメッセージボックスを表示

#ブラウザを閉じる
driver.close()

#完了メッセージボックスを表示
wx.MessageBox('完了', 'おっPython')

繰り返しが終了したのでブラウザを閉じます。

エラー時と同じ要領で完了メッセージボックスを表示。

おっPython!!!

初のPythonプログラミング頑張りました!

おぉぅ……結構長い記事になってしまいましたw

ExcelVBAからIE操作はしたことありましたが、PythonのSeleniumで操作するGoogle Chromeは安定力ハンパないっす。

あと、Visual Studio Code すごいですw

書きやすいしデバックしやすいしw

デバックしてる時に上に戻れたらもっといいのになー……

誰かに添削してもらいたい

1人でプログラム書いてると良いコードなのか悪いコードなのかがわかりません。

動けばいい!っていう方もいらっしゃるとも思いますが、書くなら良いコードを書きたいと思います(`;ω;´)


Pythonプログラマー先輩のみなさま、どうでしょうか……?


一緒にPython勉強してくれる方募集しています!w

あなたにも素敵な情報収集生活が訪れますように

Xでいろいろつぶやいています。
フォローお待ちしております。

この記事を書いた人

つぶ

I'm a computer nerd.

月曜夜のもくもく会 #西中島StudyGroup で西中島だけの🍜情報サイト 西中島 #ヌードル倶楽部 を作っています
Web制作とPythonでの業務効率化とリユースと経営と🍜が好き

https://nishinakajima.ramennoodleclub.com/