ねもぷらす

ふぁいんでぃんぐねもの日記。プログラミングとか育児とか

SikuliX-2.0.5 で openpyxl を使う

qiita.com
Qiitaに書いてみました。技術系はQiitaのほうが書きやすい…


sikulix で openpyxl を利用する方法が見当たらなかったので、整理のため久々にブログを更新しました。


sikulix.com


2022/8/22現在、SikuliXの最新安定バージョンは 2.0.5 です。
無料で使えるRPAツールの先駆者ですが、エクセルの操作は Excel2003 以前の拡張子「.xls」しか操作できません。
また、エクセルは読み込みのみか、書き込みのみで操作する必要があり、
編集したい場合は xlrd で全件読み込んだ後、xlwt で1発で保存する、という必要があります。

import xlrd
import xlwt

openpyxl であれば、拡張子「.xlsx」に対する 読み・書き が可能です。
エクセルを利用した転記や情報収集などをRPA化したいとき、逐次エクセルへ操作中の状況が書込・保存できれば
SikuliXが予期せず終了した場合に安心できます。

ここから SikuliX-2.0.5 で openpyxl を無理やり利用する方法を記載しますが、
下記Q/Aのとおり、現バージョンでは推奨されていない手法になりますので利用にはご注意ください。

answers.launchpad.net


お品書き

  1. Python2.7用の openpyxl を収集、配備する
    1. openpyxl 2.6.4
    2. jdcal-1.4.1
    3. et_xmlfile-1.0.1
  2. Java用の XMLパーサ(Apache Xerces)を入手する
  3. SikuliX-2.0.5 をコマンドから起動する

1. Python2.7用の openpyxl を収集、配備する

SikuliX は Python2.7 相当で動作する Jython2.7 が採用されており、
pypi からダウンロードしたソースコード
手作業で『%USERPROFILE%\AppData\Roaming\Sikulix\Lib\site-packages』へ配備することで利用できるようになります。

Pythonは2.x系と3.x系に大別され、2.x系のサポートは 2021/2/1 に終了していますが、
バージョンを指定することで 2.x系 に対応した Python モジュールを入手可能です。
モジュールの利用可否を判断するのが大変なので、Python2.7.18 をインストールして
pipコマンドで入手することにしました。

$ pip download openpyxl==2.6.4 -d src
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
Collecting openpyxl==2.6.4
  Using cached openpyxl-2.6.4.tar.gz (173 kB)
Collecting jdcal
  Using cached jdcal-1.4.1-py2.py3-none-any.whl (9.5 kB)
Collecting et_xmlfile
  Using cached et_xmlfile-1.0.1.tar.gz (8.4 kB)
Saved c:\python27\src\openpyxl-2.6.4.tar.gz
Saved c:\python27\src\jdcal-1.4.1-py2.py3-none-any.whl
Saved c:\python27\src\et_xmlfile-1.0.1.tar.gz
Successfully downloaded openpyxl jdcal et-xmlfile

openpyxl 2.6.4 をダウンロードすると、合わせて jdcal-1.4.1、et_xmlfile-1.0.1 がダウンロードされるので、すべてSikuliXのライブラリフォルダに格納します。

  • openpyxl-2.6.4.tar.gz

圧縮ファイルを解凍し、
dist\openpyxl-2.6.4.tar\openpyxl-2.6.4\openpyxl をフォルダごと
%USERPROFILE%\AppData\Roaming\Sikulix\Lib\site-packages にコピー

  • jdcal-1.4.1-py2.py3-none-any.whl

拡張子「.whl」は圧縮ファイル。
解凍して、直下の「jdcal.py」ファイルを
%USERPROFILE%\AppData\Roaming\Sikulix\Lib\site-packages にコピー

  • et_xmlfile-1.0.1.tar.gz

圧縮ファイルを解凍し、
et_xmlfile-1.0.1\et_xmlfile をフォルダごと
%USERPROFILE%\AppData\Roaming\Sikulix\Lib\site-packages にコピー


これでPythonモジュールは配備されましたが、SikuliXを起動し、

import openpyxl

とすると、下記のエラーが得られます。

[error] JythonRunner: runPython: (
import openpyxl
) raised: Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "%USERPROFILE%\AppData\Roaming\Sikulix\Lib\openpyxl\__init__.py", line 6, in <module>

... 略 ...

ory.loadClass(XMLReaderFactory.java:200)
	at java.xml/org.xml.sax.helpers.XMLReaderFactory.createXMLReader(XMLReaderFactory.java:191)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
org.xml.sax.SAXException: org.xml.sax.SAXException: SAX2 driver class org.apache.xerces.parsers.SAXParser not found
java.lang.ClassNotFoundException: org.apache.xerces.parsers.SAXParser


org.apache.xerces.parsers.SAXParser がない、と怒られているので、
Apache Xerces のクラスファイルを入手・配備します。


2. Java用の XMLパーサ(Apache Xerces)を入手する

Apache Xerces(アパッチ ザーシーズ)から、Java用のバイナリファイルを入手します。
xerces.apache.org

作業時点で、バージョンは Xerces2 Java 2.12.2 - zip でした。
入手した圧縮ファイルから「xercesImpl.jar」ファイルを取得し、
C:\Users\fccl8912\AppData\Roaming\Sikulix\Extensions」フォルダに格納します。

以上で準備が整いました。

3. SikuliX-2.0.5 を起動する

sikulixide-2.0.5.jar ファイルをダブルクリックするか、
配備されたフォルダ内で

$ java -jar sikulixide-2.0.5.jar

と実行することで SikuliX を起動できます。

自己責任の操作となりますが、
以下のような簡単な操作であれば特に問題なく動作させることができました。

import openpyxl

# エクセルを作成
wb = openpyxl.Workbook()

# シート名を変更し、A1セルに値を書き込み
ws = wb.worksheets[0]
ws.title = u"サンプル"
ws.cell(row=1, column=1).value = u"A1セルに値を書き込み"

# 保存
wb.save(u"テスト.xlsx")

popup(u"作成しました。")


# エクセルの更新
wb = openpyxl.load_workbook(u"テスト.xlsx")

# シートを選択して、内容編集
ws = wb[u"サンプル"]
ws.cell(row=2,column=1).value = u"値を設定"
ws.cell(row=3,column=1).value = ws.cell(row=2,column=1).value

# 更新
wb.save(u"テスト.xlsx")

popup(u"更新しました。")


特殊な操作をするとどうなるかわかりませんが、データの読み書き程度の操作であれば行けるかも?
SikuliXなら簡単に GUI 操作の自動化が可能です。
高価な RPA ツールからの脱却に、SikuliX、いかがでしょうか!

scikit-learnで丹次郎の血液型を推測する(未完成)

scikit-learn を付属のデータセットを使用せずに理解しようと思い立ったものの、
「名前から性別を推測する」という何の役にも立たない例しか思いつかないうえに
文字列を含むCSVを読めば

ValueError: could not convert string to float: '氏名'

無理やり読み込んだ変数を fit に渡せば

ValueError: could not convert string to float: '氏名'


解決策にたどり着くことができず…
より正しい方法があるはずですが、今のところ下記の方法が精一杯。

import numpy as np
from sklearn.svm import SVC
from sklearn import preprocessing
from sklearn.model_selection import train_test_split

# 文字列対応。np.loadtxt ではエラーになる
data = np.genfromtxt('personal_infomation.csv', delimiter=',', dtype=None, encoding="utf-8_sig")

# 日本語文字列を含む列は1文字ずつコードポイントに変換
# 
def codelist(s):
    return [ord(i) for i in s.ljust(10)]

x = [codelist(i[0]) for i in data]
y = [i[1] for i in data]

# 学習の実行
clf = SVC()
clf.fit(x, y)

# 予測
clf.predict([codelist('竈門丹次郎')])


personal_infomation.csv は疑似個人情報データ生成サービスを利用して
氏名と血液型のみのデータを1,5000件ほど作成。
ちなみに丹次郎は B型 と予測されました。
精度検証するのを忘れていたのでやり直しorz

pyautogui スクリーンショットのアクティブウィンドウに枠線を引く

pyautogui で自動運転を作りこんでいる時、クリック操作前後のスクショを残しておきたかったので書いたヤツ。
python はやりたいことがズバズバ書けて面白い

import pyautogui
from pyautogui import Point
from datetime import datetime
from pyrect import Box
from PIL import ImageDraw

PREFIX = ''
SUFFIX = ''

def save(position:Point=None, box:Box=None, color:tuple=(255,0,0), filename:str=None):
    im = pyautogui.screenshot()
    
    if filename is None:
        filename = "{0}{1:%Y%m%d_%H%M%S_%f}{2}.jpg".format(PREFIX, datetime.now(), SUFFIX)
    
    if position is None:
        (x, y) = pyautogui.position()
    else:
        (x, y) = position
    
    if box is None:
        box = pyautogui.getActiveWindow().box
    xy = (box[0], box[1], box[0]+box[2], box[1]+box[3])
    
    draw = ImageDraw.Draw(im)
    for i in [5, 10]:
        draw.arc(xy=(x-i, y-i ,x+i, y+i), start=0, end=360, fill=color, width=3)
    draw.rectangle(xy, width=5, outline=color)
    
    im.save(filename)
    return filename


if __name__=='__main__':
    import __main__
    __main__.PREFIX = 'screenshot_'
    print(__main__.save())

15年前の登山靴

高校三年間+大学四年間使ったあと、軽く洗って実家に放置してた我が相棒。
久しぶりにみたらこの状態…
f:id:yamazaru_rengou:20180421172517j:plain

捨てられたと思ってた分、まだ生きてたので履けるなら履こうと思い水洗い。

f:id:yamazaru_rengou:20180421172526j:plain

なんだか行けそうな気がする!
とりあえず一晩乾かして様子見~

raspberry pi zero w 一日目

木曜日の夜、夕食後。



長男のメディア許容時間は30分なので、19:30~20:00が勝負。
今日は電源入れる所までを目標、osインストール済みだから楽勝♪
f:id:yamazaru_rengou:20180419193157j:plain
繋いで…電源オン!と言ってもスイッチは無いので電源を接続。するとテレビに…
f:id:yamazaru_rengou:20180419193228j:plain
ラズパイマークが!

でも…


すすまなーーーい!!

f:id:yamazaru_rengou:20180419193245j:plain

osを認識してくれない?
仕方ないのでsdカードをフォーマットしてos入れ直し。
時間もないし祈る気持ちで再度電源オン!
いきなり起動できた!!
f:id:yamazaru_rengou:20180419195545j:plain

焦って写真とれずorz
ここからosインストールで20分くらいかかりました。
週末はScratchまで使えるかな~