Last active
November 29, 2019 07:05
-
-
Save tokchin/a7dc211ca2560d6c373217cc2b50a196 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Selenium関連のモジュール読み込み | |
from selenium import webdriver #ブラウザ制御 | |
from selenium.webdriver.firefox.options import Options #ブラウザ制御を始める時のオプション設定 | |
from selenium.webdriver.common.by import By #要素の選択方法 | |
from selenium.webdriver.support.ui import WebDriverWait #待機 | |
from selenium.webdriver.support import expected_conditions as EC #待機条件指定 | |
from time import sleep | |
import os | |
class MiimeDutchAuctionBot: | |
def __init__(self, token_address, token_id, headless=False): | |
#値段を書き換える、トークンのアドレスとIDを指定 | |
self.token_address = token_address | |
self.token_id = token_id | |
#ブラウザを描画するかどうか指定 | |
if headless: | |
#ブラウザ制御のオプション設定を読み込み | |
options = Options() | |
#オプション設定に-headlessを追加 | |
options.add_argument("-headless") | |
#ブラウザ制御オプションをブラウザ(webdriver)に設定して、ブラウザを起動 | |
self.browser = webdriver.Firefox(options=options) | |
else: | |
#オプション無しでブラウザ(webdriver)を読み込む | |
self.browser = webdriver.Firefox() | |
#metamaskのエクステンションをwebdriverに読み込む | |
#gecko driver(firefox)が絶対パスしか受け付けないので、相対パスから絶対パスに変換 | |
abspath = os.path.abspath('./lib/metamask-firefox.zip') | |
#ブラウザにmetamaskをインストール | |
self.browser.install_addon( | |
abspath, temporary=True) | |
#価格を下げるfunction(今回使うメイン関数) | |
def deduct_price(self, dummy_backup_phrase, dummy_password, privatekey, deduction): | |
#メタマスク初期化 | |
self.metamask_init(dummy_backup_phrase, dummy_password, privatekey) | |
#miime.ioを開く | |
self.open_miime() | |
#metamaskをミームと繋ぐ | |
self.metamask_connect() | |
#価格を下げるtアイテムのページを | |
self.open_item_page(self.token_address, self.token_id) | |
#価格変更 | |
self.change_price(deduction) | |
#メタマスクで署名する | |
self.metamask_sign() | |
#メタマスクで承認する | |
self.metamask_approve() | |
#完了報告 | |
print("price_changed") | |
#表示されたら、指定したXpathのボタンをクリックする。 | |
def wait_and_click(self, xpath): | |
#seleniumの待機用のオブジェクトを呼び出し | |
wait = WebDriverWait(self.browser, 10) | |
#xpathの要素がクリック可能になるまで待ってから、その要素をelementにいれる | |
element = wait.until(EC.element_to_be_clickable((By.XPATH, xpath))) | |
#elementに保存されている要素をクリックする。 | |
element.click() | |
#表示されたら、指定したXpathに入力する。 | |
def wait_and_input(self, xpath, value): | |
wait = WebDriverWait(self.browser, 10) | |
#xpathの要素が出現するまで待ってから、その要素をelementにいれる | |
element = wait.until(EC.presence_of_element_located((By.XPATH, xpath))) | |
#elementに保存されている要素にvalueを入力する。 | |
element.send_keys(value) | |
#num個の画面が出現するまで待つ | |
def wait_for_window(self, num): | |
wait = WebDriverWait(self.browser, 10) | |
#windowの数がnumになるまで待つ | |
#wait.until()の中身はfunctionにしておかないと、動かない。Boolだとだめ。 | |
wait.until(lambda x: len(self.browser.window_handles)==num) | |
#xpathにテキストが出現するまで待ってから、テキストを返す | |
def wait_for_text(self, xpath): | |
wait = WebDriverWait(self.browser, 10) | |
element = wait.until(EC.presence_of_element_located((By.XPATH, xpath))) | |
#elementに保存されている要素のtextを返す。 | |
return element.text | |
#N番目のウィンドウに変更する。0スタートなので、[a,b,c]でbが欲しい場合1を指定 | |
def change_window(self, num): | |
#num番目のウィンドウを取得しhandleに保存 | |
handle = self.browser.window_handles[num] | |
#handleに保存されているウィンドウに移動 | |
self.browser.switch_to_window(handle) | |
#メタマスク初期化 | |
def metamask_init(self, dummy_backup_phrase, dummy_password, privatekey): | |
#新しいwindowが出現する場合少しsleepを入れておかないとたまに失敗する。 | |
#0.1秒待機 | |
sleep(0.1) | |
#windowが2個表示されるまで待つ | |
self.wait_for_window(2) | |
#0から数えて1番目のwindowに移動,[a,b,c]のb | |
self.change_window(1) | |
#'/html/body/div/div/div[3]/div/div/div/button'はXpath | |
#このxpathのボタンが出現したら、ボタンをクリックする。 | |
self.wait_and_click( | |
'/html/body/div/div/div[3]/div/div/div/button') | |
#xpathを探してクリックする。 | |
self.browser.find_element_by_xpath( | |
'/html/body/div/div/div[3]/div/div/div[2]/div/div[2]/div[1]/button').click() | |
self.browser.find_element_by_xpath( | |
'/html/body/div/div/div[3]/div/div/div/div[5]/div[1]/header/button[1]').click() | |
#xpathが表示されるまで待ってから、バックアップフレーズを入力する。 | |
#waitを入れないと、たまに入力に失敗するのでwait_and_inputを指定 | |
self.wait_and_input( | |
'/html/body/div/div/div[3]/div/div/form/div[4]/textarea',dummy_backup_phrase) | |
#xpathを探してパスワードを入力する | |
self.browser.find_element_by_xpath( | |
'//*[@id="password"]').send_keys(dummy_password) | |
#xpathを探して確認用パスワードを入力する | |
self.browser.find_element_by_xpath( | |
'//*[@id="confirm-password"]').send_keys(dummy_password) | |
#ボタンをクリックして画面を遷移させる | |
self.browser.find_element_by_xpath( | |
'/html/body/div/div/div[3]/div/div/form/div[7]/div').click() | |
self.browser.find_element_by_xpath( | |
'/html/body/div/div/div[3]/div/div/form/button').click() | |
self.wait_and_click('/html/body/div/div/div[3]/div/div/button') | |
self.wait_and_click('/html/body/div/div/div[1]/div/div[2]/div[2]') | |
self.browser.find_element_by_xpath( | |
'/html/body/div/div/div[4]/div[7]/div[2]').click() | |
#xpathを探して、プライベートキーを入力する。 | |
self.browser.find_element_by_xpath( | |
'//*[@id="private-key-box"]').send_keys(privatekey) | |
self.browser.find_element_by_xpath( | |
'/html/body/div/div/div[4]/div/div[2]/div/div[3]/div[2]/button[2]').click() | |
def open_miime(self): | |
#ミームのページを開く | |
self.browser.get("https://miime.io") | |
#メタマスク接続 | |
def metamask_connect(self): | |
#お約束、新ウィンドウ開くときは0.1秒待機 | |
sleep(0.1) | |
#ウィンドウの個数が3個になるまで待つ | |
self.wait_for_window(3) | |
#0から数えて2番目のウィンドウに移動(メタマスクの接続承認ウィンドウ)が出てくるまで待つ | |
self.change_window(2) | |
#接続ボタンを押す | |
self.wait_and_click( | |
'/html/body/div/div/div[3]/div/div[3]/header/button[2]') | |
#ウィンドウの個数が2個になるまで待つ | |
self.wait_for_window(2) | |
#0から数えて1番目のウィンドウに移動 | |
self.change_window(1) | |
def metamask_sign(self): | |
#お約束、新ウィンドウ開くときは0.1秒待機 | |
sleep(0.1) | |
#ウィンドウの個数が3個になるまで待つ | |
self.wait_for_window(3) | |
#0から数えて2番目のウィンドウに移動(メタマスクの署名ウィンドウ)が出てくるまで待つ | |
self.change_window(2) | |
#0から数えて2番目のウィンドウに移動(メタマスクの署名ウィンドウ)が出てくるまで待つ | |
self.wait_and_click('/html/body/div/div/div[3]/div/div[4]/button[2]') | |
#0から数えて1番目のウィンドウに移動 | |
self.change_window(1) | |
def metamask_approve(self): | |
#お約束、新ウィンドウ開くときは0.1秒待機 | |
sleep(0.1) | |
#ウィンドウの個数が3個になるまで待つ | |
self.wait_for_window(3) | |
#0から数えて2番目のウィンドウに移動(メタマスクの接続承認ウィンドウ)が出てくるまで待つ | |
self.change_window(2) | |
#署名ボタンを押す | |
self.wait_and_click('/html/body/div/div/div[3]/div/div[3]/button[2]') | |
#0から数えて1番目のウィンドウに移動 | |
self.change_window(1) | |
def open_item_page(self, token_address, token_id): | |
#変数token_addressとtoken_idを入力して | |
self.browser.get(f"https://miime.io/assets/{token_address}/{token_id}") | |
#今回は使わない出品機能 | |
def sell(self, price): | |
#アイテムページで出品ボタンが出現したら、出品ボタンを押す | |
self.wait_and_click('/html/body/div[1]/div/div/main/div/div/button') | |
#入力欄が出現したら価格を入力する。 | |
self.wait_and_input( | |
'/html/body/div[1]/div/div/main/div/div[2]/div[2]/div/input', price) | |
#購入ボタンがクリック可能状態になったら、ボタンを押す | |
self.wait_and_click('/html/body/div[1]/div/div/main/div/div[3]/button') | |
#価格をdeuctionの金額だけ、減らす機能 | |
def deduct_price(self, deduction): | |
#金額変更ボタンを押す | |
self.wait_and_click('/html/body/div[1]/div/div/main/div/div/button') | |
#xpathの位置に保管されている、現在の価格を取得して、current_priceに保存 | |
current_price = self.wait_for_text( | |
'/html/body/div[1]/div/div/main/div[2]/div[2]/div/div[1]') | |
#現在価格をコンソールに出力 | |
print(f"current price:{current_price}") | |
#現在価格から、deduction削減価格を差し引いた値を小数点2桁で切り上げする | |
new_price = round(float(current_price) - deduction, 2) | |
#新価格をコンソールに出力 | |
print(f"current price:{new_price}") | |
#新価格を入力スル | |
self.wait_and_input( | |
'/html/body/div[1]/div/div/main/div[2]/div[3]/div/input', str(new_price)) | |
#価格変更ボタンを押す | |
self.wait_and_click('/html/body/div[1]/div/div/main/div[3]/button') | |
def main(): | |
#環境変数に保存してあるプライベートキーを読み込む。 | |
privatekey = os.environ['privatekey'] | |
#使い捨てのバックアップフレーズを読み込む | |
privatekey = os.environ['privatekey'] | |
dummy_backup_phrase = "cart vicious rebuild traffic gospel wheat nice true sand concert drastic sentence" | |
dummy_password = "password" | |
#価格を変更したいアイテムのトークンアドレスとIDを実装する。 | |
token_address = '0xdceaf1652a131f32a821468dc03a92df0edd86ea' | |
token_id = '10141042' | |
bot = MiimeDutchAuctionBot(token_address, token_id) | |
bot.deduct_price(dummy_backup_phrase, dummy_password, privatekey, 0.01) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment