1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Seleniumでasm15を操作する

Posted at

はじめに

Seleniumとは

Selenium

Webブラウザを自動で操作できるツール。
多くのプログラミング言語がサポートされているが、今回はPythonを用いる。

asm15とは

asm15 assembler for IchigoJam / IchigoLatte (本家)
asm15 assembler for IchigoJam / IchigoLatte (筆者による改造版)

IchigoJam向けのマシン語のアセンブルを目的に開発されたアセンブラ。
Webブラウザ上で入出力を行うため、ファイルとの連携は一手間かかる。

※IchigoJamはjig.jpの登録商標です。

今回の目的

Webブラウザ自動操作ツールSeleniumでアセンブラasm15を操作し、
標準入力から受け取ったアセンブリのソースコードをアセンブルして結果を標準出力に出力する。

Seleniumのインストール

今回は、PythonおよびGoogle Chromeが既にインストールされているWindows環境でインストールを行った。
インストール方法および一部の操作方法は、この記事を参考にした。

10分で理解する Selenium - Qiita

コマンドプロンプトでPythonのvirtualenv環境を用意し、
以下のコマンドを実行することで、インストールできた。

pip install chromedriver-binary==96.*
pip install selenium

chromedriver-binary==に続く数字は、記事に従い、
インストールされているGoogle Chromeのバージョンに合わせた。
Google Chromeのバージョンが上がった際のトラブルを避けるため、virtualenvを用いることにした。

Seleniumによるasm15の操作

SeleniumによるWebブラウザの操作は、Pythonのインタラクティブモードで試すことができる。

Webブラウザ (Google Chrome) の起動

以下のプログラムにより、Google Chromeを起動してSeleniumで操作できる状態にできる。

import chromedriver_binary
from selenium import webdriver
driver = webdriver.Chrome()

import chromedriver_binary はGoogle Chrome起動の準備をしているようで、
これを実行しないとGoogle Chromeの起動に失敗した。

また、--headless オプションを用いると、Google Chromeのウィンドウを隠した状態で起動できる。

options = webdriver.ChromeOptions()
options.add_argument("--headless")
driver = webdriver.Chrome(options=options)

Webブラウザの終了

quit関数により、Seleniumで起動したWebブラウザを終了できる。

driver.quit()

また、with構文を用いることで、ブロックの実行終了時に自動で終了してくれる。

with webdriver.Chrome(options=options) as driver:
	# do work

Working with windows and tabs | Selenium

指定のURLへの遷移

get関数により、指定のURLに遷移できる。

driver.get("https://ichigojam.github.io/asm15/")

HTML要素のハンドラの取得

find_element関数により、操作対象のHTML要素を選択し、ハンドラを取得できる。
今回は、要素のid属性に基づいて選択するBy.IDを用いる。

from selenium.webdriver.common.by import By
textarea = driver.find_element(By.ID, "textarea1")

Finding web elements | Selenium

該当する要素が存在しない場合、
selenium.common.exceptions.NoSuchElementException例外が発生するようである。

入力欄への文字列の入力

send_keys関数により、HTML要素の入力欄に文字列を入力できる。
英語の大文字や小文字、記号、日本語も指定通りに入力できるようである。

textarea.send_keys("' テスト (test)\nRET\n")

clear関数により、HTML要素の入力欄に入力されている文字を消去できる。

textarea.clear()

Keyboard Actions | Selenium

入力欄からの文字列の取得

get_attribute関数によりHTML要素の属性の値を取得でき、
入力欄に入力されている文字列もこれで取得できるようである。

textarea.get_attribute("value")

textプロパティもあり、執筆時点におけるasm15のアセンブル結果はこれでも取得できたが、
入力した内容は反映されないようだった。

textarea.text

Information about web elements | Selenium
(執筆時点において、属性の取得については書かれていないようである)

SELECT要素の操作

HTMLのSELECT要素の操作は、Selectオブジェクトを用いて行うことができる。
例えば、select_by_visible_text関数を用いると、表示される文字列を指定して選択できる。

from selenium.webdriver.support.select import Select
selfmt = driver.find_element(By.ID, "selfmt")
selfmt_selobj = Select(selfmt)
selfmt_selobj.select_by_visible_text("bas (hex)")

Working with select list elements | Selenium

ボタンのクリック

click関数により、HTML要素をクリックできる。

btn = driver.find_element(By.ID, "submit-button")
btn.click()

アラートダイアログへの対処

執筆時点におけるasm15は、アセンブル時のエラーをアラートダイアログで表示する。
アラートダイアログが出ているかをチェックするため、タイムアウトを短く設定したWebDriverWaitを用い、
wait関数でアラートダイアログが出るまで待たせる。
タイムアウトは、WebDriverWaitの第2引数で、秒単位で設定できるようである。
アラートダイアログが出ていればそのダイアログのハンドラが返り、
出ていなければselenium.common.exceptions.TimeoutException例外が発生するようである。

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 1)
alert = wait.until(EC.alert_is_present())

アラートダイアログが出ていた場合、textプロパティでアラートダイアログの内容を取得し、
accept関数でアラートダイアログを閉じることができる。

alert.text
alert.accept()

Waits | Selenium
JavaScript alerts, prompts and confirmations | Selenium

まとめ

今回紹介した要素を組み合わせた以下のプログラムにより、asm15を操作し、
標準入力から受け取ったソースコードをアセンブルして結果を標準出力に出力できる。
また、発生したエラーは標準エラー出力に出力する。

selenium_asm15.py
import sys
import chromedriver_binary
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.select import Select
from selenium.common.exceptions import TimeoutException

# open Chrome
options = webdriver.ChromeOptions()
options.add_argument("--headless")

with webdriver.Chrome(options=options) as driver:
	# open asm15
	driver.get("https://ichigojam.github.io/asm15/")

	# set output format
	selfmt = driver.find_element(By.ID, "selfmt")
	selfmt_selobj = Select(selfmt)
	selfmt_selobj.select_by_visible_text("bas (hex)")

	# set assembly source
	asm_source = sys.stdin.read()
	textarea_asm = driver.find_element(By.ID, "textarea1")
	textarea_asm.clear()
	textarea_asm.send_keys(asm_source)

	# assemble
	assemble_button = driver.find_element(By.ID, "submit-button")
	assemble_button.click()

	# get errors from alert dialog(s)
	wait = WebDriverWait(driver, 1)
	while True:
		try:
			alert = wait.until(EC.alert_is_present())
		except TimeoutException:
			break
		sys.stderr.write(alert.text + "\n")
		alert.accept()

	# get assembled result
	textarea_res = driver.find_element(By.ID, "textarea2")
	res = textarea_res.get_attribute("value")
	sys.stdout.write(res)

テスト用に以下のソースコードを用意した。

test.txt
R0 = R0 + 1
RET
test_error.txt
R0 = R0 + 1234
RET

実行してみると、システムから余計な出力がされるものの、
アセンブル結果とアセンブル時のエラーを取得できていることがわかる。
1回の実行には7秒くらいかかった。

(ve) YUKI.N>selenium_asm15.py < test.txt > test_out.txt

DevTools listening on ws://127.0.0.1:59356/devtools/browser/6cc184b3-4a60-4d3c-b9a4-e36045d28b75
[0103/170014.011:INFO:CONSOLE(0)] "Error with Permissions-Policy header: Unrecognized feature: 'interest-cohort'.", source:  (0)

(ve) YUKI.N>cat test_out.txt
10 poke #700,#40,#1C,#70,#47

(ve) YUKI.N>selenium_asm15.py < test_error.txt > test_error_out.txt

DevTools listening on ws://127.0.0.1:59375/devtools/browser/04e8fb18-1d26-4a91-8764-cfbf4553e7db
[0103/170156.926:INFO:CONSOLE(0)] "Error with Permissions-Policy header: Unrecognized feature: 'interest-cohort'.", source:  (0)
asm error in 1
R0 = R0 + 1234
Error: over!

(ve) YUKI.N>cat test_error_out.txt
10 poke #700,#70,#47

(ve) YUKI.N>
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?