PythonでAm●zon自動購入bot作ってみた④(入力項目・バリデーション・処理時刻算出)
押忍!
某youtuberの登場キャラでおなじみ「鎖骨打ちのサトJ」です!
前回の続きです。
前回の記事はこちら
今回からいよいよプログラムについてです。
今日は前回記事のこの箇所の解説をしていきます
あらかじめ言っておきますが、今回Python使ったのは初めてです!
変数宣言とか構成がpythonっぽくない書き方なところも多々あるかと思いますがご了承願います。
■入力項目・バリデーション
入力項目に関しては①②③⑦を必須、その他は任意にしております。
まずは①②③から
LOGIN_URL = "https://www.amazon.co.jp/ap/signin?openid.pape.max_auth_age=0&openid.return_to=https%3A%2F%2Fwww.amazon.co.jp%2F%3Fref_%3Dnav_custrec_signin&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=jpflex&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&"
while True:
login = input("*ログインID(半角)>")
if login != "":
if CheckUtiltys.CheckMailAddress(login):
break
elif CheckUtiltys.CheckPhoneNumber(login):
break
else:
print("ログインIDが不正です。")
else:
print("ログインID(半角)は必須です。")
while True:
password = stdiomask.getpass("*ログインPassWord(半角)>")
if password != "":
if CheckUtiltys.CheckHankakuEisuziKigou(password):
break
else:
print("ログインpasswordが不正です。")
else:
print("ログインPassWord(半角)は必須です。")
while True:
purchaseGoodsUrl = input("*買いたい商品のURL>")
if purchaseGoodsUrl != "":
if CheckUtiltys.CheckURL(purchaseGoodsUrl,"www.amazon.co.jp"):
break
else:
print("AmazonのURLを入力してください。")
else:
print("買いたい商品のURLは必須です。")
こんな感じで書きました。どれもWhile文で回してバリデーションチェックでTrueがきたらbreakで抜けるって感じにしてます。
ログインIDに関しては電話番号でもメールアドレスでも使えるようなのでどっちかクリアすればOKな仕様にしました。
基本的に入力はinput関数を使ってますがパスワードだけstudiomaskっていうモジュールのgetpass関数を使ってます。studiomask.getpassを使うと通常のinput関数のように入力できるようになりますが入力したときの文字表示がすべて「*」になります。パスワードとかショルダーハッキングされないように配慮しました。
一応リンク載せておきます
なおLOGIN_URLはAmazonのログインページのURLをそのままコピってます。
ここでびっくりしたのがPythonって「readonly」とか「const」ってないんですね。ログインURLは変わらないように定数化しようとしたんですがどうすればいいのかわからず。調べたらPythonで定数定義するときは変数名を全部大文字にする的なこと書いてありました。
謎い
「;」がないのはVB.NETで慣れてたんであんま抵抗なかったです。
なお上記コードで一番ツボったのは「elif」ですw
他にもいろいろ突っ込みどころはありましたがそれはまたいつか
ちなみにバリデーションはすべてCheckUtiltysってクラスにまとめております。
class CheckUtiltys():
#メールアドレスかどうか確認する
#mail : メールアドレス
#return : True(ok)/False(ng)
def CheckMailAddress(mail:str):
return re.match("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$", mail)
#半角英数字記号かどうか確認する
#target : 対象の文字列
#return : True(ok)/False(ng)
def CheckHankakuEisuziKigou(target:str):
return re.match("^[a-zA-Z0-9!-/:-@¥[-`{-~]*$", target)
#URLかどうか確認する
#target : 対象の文字列
#fqdn : 指定のFQDN
#return : True(ok)/False(ng)
def CheckURL(target:str,fqdn:str):
return re.match("https?://" + fqdn + "+", target)
#電話番号かどうか確認する
#phoneNumber : 電話番号
#return : True(ok)/False(ng)
def CheckPhoneNumber(phoneNumber:str):
#ハイフンありの場合
if re.match(r"[\(]{0,1}[0-9]{2,4}[\)\-\(]{0,1}[0-9]{2,4}[\)\-]{0,1}[0-9]{3,4}", phoneNumber):
return True
#ハイフンなしの場合
elif re.match("[0-9]{10,11}", phoneNumber):
return True
else:
return False
全部正規表現でチェックしております。
なお正規表現は全部ネットのパクリですw
電話番号はハイフンありなしどちらでもいけたのでどちらでも対応できるようにしてます。ハイフンなしのケースはとりあえず数値かつ10または11桁ならokにしました。(手抜きです)
URLチェックに関してはAm●zon以外のURLはいれてほしくないのでFQDNまでとりあえずチェックしてます。存在しないページかどうかまでは見てません。一応汎用性高めたかったのでFQDNを引数で渡してチェックをかける仕様にしました。
引数に型定義をわざわざしているのは普段型宣言する言語を使っているのでしないのが気持ち悪かっただけで特に意味はありません。
④⑤⑥に関してはここではバリデーションはかけておりません。この時点ではwebdriverは定義してないので有効な値かどうかはこの段階ではわからないからです。
④⑤⑥のチェックは購入処理操作時に入れてます。
checkColor = input("カラーを選択する場合は左または上から順に0から半角数値で入力してください。未入力可。(例)一番左を選択の場合「0」>")
checkSize = input("サイズを選択する場合は左または上から順に0から半角数値で入力してください。未入力可。(例)一番上を選択の場合「0」>")
quantity = input("2つ以上購入する場合は購入個数を入力してください。1つの場合は未入力。>")
ここで設定する0とか1とかは商品ページのここを見ております。
ここのcolor_name_[n]の値を入力することになります。
この値でどのリストの値を選択するかを決めてます。
■処理時刻算出・バリデーション
処理時刻算出はこんな感じでしました。
while True:
try:
start = datetime.strptime(input("*購入時間(hh:mm)>") + ":00","%H:%M:%S").time()
before2Minites = datetime.combine(date.today(), start) - timedelta(minutes=2)
loginTime = datetime.combine(date.today(), before2Minites.time()) #購入予定時刻の2分前
before1Seconds = datetime.combine(date.today(), start) - timedelta(seconds=1)
purchaseTime = datetime.combine(date.today(), before1Seconds.time()) #購入予定時刻の1秒前
break
except Exception as e:
print("[error]開始時刻が不正です。もう一度入力してください")
continue
こちらもWhile文で回してバリデーションチェックでTrueがきたらbreakで抜けるって感じにしてます。
文字列で入力された時刻をdatetime型に変えてログイン予定時刻と購入処理予定時刻を求めて最後は今日の日付とくっつけてる感じです。
これは結構パクりましたw
なおエラー処理に関してはhh:ss以外の値を入れたらどうせ落ちるんでtry-catchさせてます。catchに関してはめんどくさいのでExceptionでとりました。ほんとはもっと明確にとったほうがいいと思うけど許してw
■おわりに
いかがでしょうか?
参考になった方ならなかった方いるかと思いますが参考になった方はぜひぜひパクって使ってみてください。
次回は
PC時刻と実時刻について解説していきます。