pythonのgspreadで、Googleスプレッドシートに関数を直接入力しようとしたら文字列として扱われてしまった
となりの列のセルの文字数をカウントする関数を入力したかったので、以下のような記述をして書き出してみた
cell_list = wks.range('A3:A10')
for i,cell in enumerate(cell_list):
cell.value = "=len(B"+str(i+1)+")"
wks.update_cells(cell_list)
が、これだと '=len(Bi) の形で書き出されてしまい、式ではなく文字列として扱われてしまった。試しにバッチじゃなくて、一ヶ所だけ書き出してみる
wks.update_acell('A1', "=len(B1)")
上記の方法だとうまくいく。が、大量の行には対応できない。範囲していの時は何か特別な事をしないといけないようだ・・・
色々と調べると、Google Sheetsのサイトに APIのリファレンスがあり、updateの際のオプションが書いてあった
INPUT_VALUE_OPTION_UNSPECIFIED | Default input value. This value must not be used.
RAW | The values the user has entered will not be parsed and will be stored as-is.
USER_ENTERED | The values will be parsed as if the user typed them into the UI. Numbers will stay as numbers, but strings may be converted to numbers, dates, etc. following the same rules that are applied when entering text into a cell via the Google Sheets UI.
一つ目はデフォルトだけど、指定しないように書いてあるので、RAWかUSER_ENTEREDを指定するようだ。RAWは、そのまま表示されるということで、試しにしてみたら、文字列として扱われてしまった。続いて、USER_ENTEREDを指定。無事関数が動いた。以下の赤文字のところを追記すればいい。
cell_list = wks.range('A3:A10')
for i,cell in enumerate(cell_list):
cell.value = "=len(B"+str(i+1)+")"
wks.update_cells(cell_list,value_input_option='USER_ENTERED')
ちなみに、今回は関数を動かしたいので、USER_ENTEREDを指定したが、たとえば数字を文字列として入力したい場合などは、RAWを指定すれば日付や数字として変換されないようだ
<$mt:Include module="関連記事" parent="1"$>]]>pythonのgspreadで、Googleスプレッドシートを操作してるときに、大量のデータを入力したらエラーになった
データ自体は150行分位だったが、以下の様なエラーがでてしまった。
raise APIError(response)
gspread.exceptions.APIError: {
"error": {
"code": 429,
"message": "Quota exceeded for quota group 'WriteGroup' and limit 'Write requests per user per 100 seconds' of service 'sheets.googleapis.com' for consumer 'project_number:xxx'.",
"status": "RESOURCE_EXHAUSTED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.Help",
"links": [
{
"description": "Google developer console API key",
"url": "xxxxx"
}
]
}
]
}
}
どうやら、col_values()を使うと大量のデータはエラーを起こしてしまうようだ。まぁそらそうか
以下の様なコードを書いた。
import gspread
#Googleスプレッドシートへのアクセス
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
credentials = ServiceAccountCredentials.from_json_keyfile_name('xxxx.json', scope)
gc = gspread.authorize(credentials)
wks = gc.open('スプレッドシート名').worksheet('シート名')
#テスト用のリスト100個値が入ってるものとする
test_list = ['1','2','3','4'・・・中略,'100']
#編集する範囲を指定、A1セルから、リストの要素数をカウントしたものを指定する
cell_list = wks.range('A1:A'+str(len(test_list)))
#cell_listにtest_listの値を流し込む
for i,cell in enumerate(cell_list):
cell.value = test_list[i]
#最後にupdate_cellsで流し込む
wks.update_cells(cell_list)
大量とはいったものの、150〜200行位のデータだったので、うん千データとか可能かはわからない
<$mt:Include module="関連記事" parent="1"$>]]>pythonでmarkdownのテキストを処理してるときに、テーブルに関してidやclassをつけたかったので、やりかたを調べてみた
たとえば、以下の様な表があって、{#tableid}をどこかにつけたい場合、NG例の場所につけた場合、tableとして認識してくれない。
| aaa | bbb | ccc |
|-----|-----|-----|
| ddd | eee | fff |
| ggg | hhh | iii |
NG例1
| aaa | bbb | ccc |
|-----|-----|-----|
| ddd | eee | fff |
| ggg | hhh | iii |
{#tableid}
NG例2
{#tableid}
| aaa | bbb | ccc |
|-----|-----|-----|
| ddd | eee | fff |
| ggg | hhh | iii |
NG例3
| aaa | bbb | ccc |{#tableid}
|-----|-----|-----|
| ddd | eee | fff |
| ggg | hhh | iii |
では、divでくくって、そのdivにidつけた場合はどうなるだろうか? 実はこれもだめ。インライン要素になるため、そのまま挿入されてしまう。
NG例4
< div id="tableid" >
| aaa | bbb | ccc |
|-----|-----|-----|
| ddd | eee | fff |
| ggg | hhh | iii |
< / div >
で、一応以下の様にして、cssの隣接セレクタすればいいんでね?って記事を読んだけど、空のdiv要素を作るのはちょっと・・・
< div id="tableid" > < / div >
| aaa | bbb | ccc |
|-----|-----|-----|
| ddd | eee | fff |
| ggg | hhh | iii |
コンバートしたhtmlのtableにくっつける事も考えたけど、markdown形式で書いてるテキストの中にhtmlのtableで書いてもpythonで処理できるので、それなら直接tableタグで書くことにした。もし、他人からmarkdown形式で渡されて困ってるなら、typola等でhtmlに直せばいいし、こっちのが気が楽かなと。
<$mt:Include module="関連記事" parent="1"$>]]>python-docxで全文を抽出したら、ハイパーリンクの箇所が抜けていたので、ハイパーリンクの中身を取得する方法を調べた
うーん、色々と調べたのだけれども、とりあえず以下の様にすると、ファイルのハイパーリンクを抜き出す事ができる。
from docx import Document
from docx.opc.constants import RELATIONSHIP_TYPE
document = Document('test.docx')
rels = document.part.rels
test=[]
for rel in rels:
if rels[rel].reltype == RELATIONSHIP_TYPE.HYPERLINK:
test.append(rels[rel]._target)
print(test)
が、これには問題がある。ハイパーリンクを設定している元のテキストがない。ソースを見たのだけれども、ここではないどこかに格納されてるっぽくて、探し出せなかった。
python-docx2txtを使えば、元のテキストをとれるが、肝心のハイパーリンクはない・・・両方併せれば・・・と考えたが、どこにハイパーリンクが設定されてるのかいまいちわからないので、使えなかった。
とりあえず、使わなそうだけど、いつか使う時がくるかもしれないので記載
<$mt:Include module="関連記事" parent="1"$>]]>pythonで相対パス指定で動かそうとしたときはまった話
pythonでもhtmlとかと同じような相対パスの書き方で動くとのことだったので、pyファイルの置き場所から見た相対パスで実行したが、FileNotFoundError: [Errno 2] No such file or directory となってしまった。
例
/py/hoge.py
/aa/aa.json
のようなファイル構成で、hoge.pyから、aa.jsonにアクセスしたかったので、../aa/aa.json のような形でかいた
で、もちろん絶対パスに直すと動くのだけれども、相対パスにすると動かない・・・・
python動かす時にターミナルで動かしていたが、トップディレクトリでフルパスを指定して実行していたのがよくなかった。なので、cd でpythonのフォルダまで移動した上で、実行。そしたら、相対パスでも動いた。
単純な・・・ことでした
<$mt:Include module="関連記事" parent="1"$>]]>普段遣いのmacにwebサーバーを立てて、PHPを動かせて、なおかつ拡張子が.htmlでもPHPを動かせるようにする
なぜ、.htmlでPHPを動かしたいかというと、PHPで出力した内容を使って静的なページを別のところに書き出したかった。いろいろと方法があるとは思うのだけれども、今回はこの方法をとった。拡張子が.htmlでも中に直接PHPを記述できると、URLのリンクを .php から .html に書き直したりせず、出力した結果を純粋にコピーしたものを静的なページとして保存できるから。と考えた。
ということで、今回は mac でwebサーバーを立ち上げて、ルートを指定したところに変えた上で、拡張子が.html でも動くようにする。
Catalinaでもデフォルトで入ってるので、ターミナルアプリを立ち上げて、以下のコマンドをたたく。アカウントパスワードを求められるので、入力してreturn。
sudo apachectl start
webブラウザを立ち上げて、 http://localhost を表示させて、It's Work と出れば、問題ない
ターミナルで以下のコマンドをたたく
sudo vi /etc/apache2/httpd.conf
viエディタの使い方は割愛する。「viの使い方/基本操作 - 空間情報学講座 - 京都大学」などを参照するといい。
Catalinaだと php7が入っているようで、以下の箇所の行頭 # をとって上書き保存。
#LoadModule php7_module libexec/apache2/libphp7.so
なお、phpのバージョンはOSによって入ってるバージョンが異なったりするので、コマンドモードで /LoadModule php で検索して移動すると探しやすいかも
編集が終わったら、Apacheを再起動させる
sudo apachectl restart
これでドキュメントルートにphpファイルを入れれば動くはず。ドキュメントルートについては次の項目
これは必要がある場合のみ変えればいい。webサーバーを立ち上げた際、It works! を書かれたファイルは、/Library/WebServer/Documents フォルダ内にある。そこを編集していけば、localhostで表示される内容は編集できるが、別のファイル場所を参照したい場合は ドキュメントルートを変更する。viで/etc/apache2/httpd.confを再び編集する。
以下の箇所にドキュメントルートの指定する記述があるので、/Library/WebServer/Documents を指定したいファイルの置き場所に変更する。ちなみに、参照させたいフォルダの位置がよくわからない場合は、ターミナルにドロップすると出てくる。
DocumentRoot "/Library/WebServer/Documents"
<Directory "/Library/WebServer/Documents">
編集が終わったら、Apacheを再起動させる
sudo apachectl restart
localhostにアクセスして、指定したファイルフォルダの内容が表示されれば成功
最終目標である、.htmlでphpを動かすには、.htaccess を使用できるようにしないといけないので、viで/etc/apache2/httpd.confを再び編集する。
ドキュメントルートのところにある、Directory内に AllowOverride None の記述があるので、コメントアウトして、AllowOverride All を追記。
DocumentRoot "/Library/WebServer/Documents"
<Directory "/Library/WebServer/Documents">
--中略
#AllowOverride None
AllowOverride All
編集が終わったら、Apacheを再起動させる
sudo apachectl restart
これで.htaccesssが使えるようになる。
最後に、.htaccessファイルを作成して、以下の記述を追記して、ドキュメントルートに保存する
AddHandler application/x-httpd-php .php .html
Apacheの再起動はしなくて大丈夫なはずなので、index.html内とかにphpの記述をしてaccessしてみて、phpが動いていれば成功
<$mt:Include module="関連記事" parent="1"$>]]>webページのダークモード対応を行うことになったので、その際、CSSやSVGなどの対応を行ったので忘れないようにめもめも
【DEMO】 ※ Mojaveなどでダーク/ライトモードの切り替えで確認できます
iOS関連の仕事しているので、macやiOSしか確認できてないのですが、以下のような、CSSの media要素の、prefers-color-scheme を使って各モードの色を指定しておく
//prefers-color-schemeに対応していないOS用
:root {
--background-color: #fff;
--secondary-background-color: #ccc;
--font-color: #000;
}
//指定なし
@media (prefers-color-scheme: no-preference) {
:root {
--background-color: #fff;
--secondary-background-color: #ccc;
--font-color: #000;
}
}
//ライトモード
@media (prefers-color-scheme: light) {
:root {
--background-color: #fff;
--secondary-background-color: #ccc;
--font-color: #000;
}
}
//ダークモード
@media (prefers-color-scheme: dark) {
:root {
--background-color: #262626;
--secondary-background-color: #333;
--font-color: #fff;
}
}
//指定した値を var(CSS名) で指定する
body{
background-color: var(--background-color);
color: var(--font-color);
}
div{
background-color: var(--secondary-background-color);
width: 80%;
height: 500px;
margin: auto;
}
ダークモードに対応する理由としては、ダークモード時に白背景ベースのページが出てくるの眩しく見づらくなるため。
ただ、注意点として通常(ライトモード)でも同じだが、真っ白過ぎるwebページなどは目が疲れるため、見やすくするために少し色をつけていることがほとんどだと思う。それと同じで、ダークモードだからと言って、全体を真っ黒にしすぎると見づらい。少し白色を混ぜた色にすると落ち着いた感じで見れるようだ。
テキストの色も蛍光色をそのまま使うと黒背景時に見づらくなってしまうので、白色を足した淡い色に変えるといいかもしれない。マーカーのように文字の背景に敷く場合は、逆に黒色を足すと見やすくなるような気がする
あと、対応しているのが Safari12.1、Firefox 67以降のバージョン Chromeも76で対応しているので Mojave以前のOSでもブラウザをアップデートしていれば、prefers-color-scheme に対応しているので問題ない。が、iOS12の場合は、prefers-color-schemeに対応していないのでCSSが効かない。効かないだけならいいのだけれども、どうもその要素が無効になってしまうみたいなので、iOS12向けに対応する場合は、スクリプトなどでユーザーエージェントを判定してCSSを切り替える必要がある。
追記:iOS12などprefers-color-schemeに対応してないOS向けに、先頭に root: で記載し、その後 prefers-color-scheme で打ち消すようにすればいいらしい
対応するのであれば、大きく二つに分かれると思う。まず、アイコンやボタンなどの画像だけれども、単色であればSVGに変換してCSSでfillの色を変えることで対応できる。なんだけれど、svgをhtml内に直接書き込む場合は、classなりidを足してcssを割り当てれば大丈夫。けど、外部SVGを読み込む場合は、SVGファイル内にcss読み込む記述をしないとclass名などを付けてもCSSが効かない。
と言うことで、外部読み込みのSVGファイルにCSS読み込みをするのは以下のように記述を書き込む。
<defs>
<style><![CDATA[ @import url(cssファイル.css); ]]></style>
</defs>
以下の用なCSSを書いて、fillの色が指定されているタグないにcssを追記する
#icons{
fill: var(--icon-color);
}
svgにせず、ダークモードとライトモードで画像を切り替える場合は、pictureタグを使って以下のように記述したりもできる
<picture>
<source srcset="dark.png" media="(prefers-color-scheme: dark)">
<img src="light.png">
</picture>
基本的には上記の対応だけでダークモード時の調整はできるはず
<$mt:Include module="関連記事" parent="1"$>]]>今回は、ポップアップメニューのアイテムをリスト化して繰り返し処理する方法
アプリケーションの動作チェックで、ポップアップの項目を一つずつ処理させたかった。とは言え、何十もの項目を書くのはばかばかしいので、ポップアップボタンのメニューをリストとして保存して、それを繰り返し処理させることで対応させた。
と言うことで、ブログ用に環境設定の"一般"で強調表示色の項目を取得して、一件ずつクリックして変えていく処理を作成してみた。
tell application "System Preferences"
activate
end tell
tell application "System Events"
tell application "System Events"
tell process "System Preferences"
tell window 1
click button "すべてを表示" of group 1 of group 2 of toolbar 1
delay 1
tell scroll area 1
click button "一般"
end tell
end tell
delay 3
tell window 1
click pop up button "強調表示色:"
tell menu 1 of pop up button "強調表示色:"
set scroll_List to name of every UI element
click menu item 1
end tell
repeat with curItem in scroll_List
click pop up button "強調表示色:"
delay 1
set select_color to curItem as string
click menu item select_color of menu 1 of pop up button "強調表示色:"
end repeat
end tell
end tell
end tell
end tell
SierraとCatalinaでも動作を確認した。コアとなる部分は、二つ
click pop up button "強調表示色:"
tell menu 1 of pop up button "強調表示色:"
set scroll_List to name of every UI element
click menu item 1
end tell
次にrepeat処理。Applescriptでよくやる方法。変数 in リスト で行う。これでリストの最初から最後まで処理を行える。その時の値は、curItemで取り出すことができる。アプリにもよるみたいで、環境設定ではする必要がないのだけれども、キャストしないと失敗するときがあったので、set select_color to curItem as string で一回キャストしている。クリック動作させるときにさせても駄目なときがあったのでこれが一番っぽい
repeat with curItem in scroll_List
click pop up button "強調表示色:"
delay 1
set select_color to curItem as string
click menu item select_color of menu 1 of pop up button "強調表示色:"
end repeat
あと、リストの値に "missing value" が入る場合があって、その場合スクリプトが失敗して止まる事があった。もしそのようなことになる場合は、条件式を追加して、"missing value"の時は処理をスキップさせるのがいい。
<$mt:Include module="関連記事" parent="1"$>]]>今回は、クリックで変えられない値を変える方法
いまのところ、この二つで click で値を変えることができず、けっこうどはまった。。。
combo box に関しては、暫定的な変え方をメモっておく
まぁ・・・あまりtable要素を見ないが、Excelに要素があったので、それを選択するスクリプトを貼り付けておく。
tell application "Microsoft Excel"
activate
end tell
tell application "System Events"
tell process "Microsoft Excel"
tell window "Web オプション"
tell tab group 1
tell scroll area 1
tell table 1
select row 3
end tell
end tell
end tell
end tell
end tell
end tell
button要素は、クリックで変えられるが、rowはクリックしても選択状態にならないので、selectを使う。それだけの話。
テキストエディットのフォントサイズの指定欄。要素を調べていくと、combo box というのに行き当たる。んでもって、list 1 of scroll area 1 にクリックした際に出てくる数字のリストがでてくるのがわかる。試しに、select text field 1 したら選択されたので、これか〜と思ったら、実際の数値が変わっていないこと気付く。
tell application "TextEdit"
activate
end tell
tell application "System Events"
tell process "TextEdit"
tell window "名称未設定"
tell combo box 1 of group 1
click button 1
tell list 1 of scroll area 1
select text field 1
end tell
end tell
end tell
end tell
end tell
試しに、選択状態で、エンターキー(key code 36)を走らせるが、やはり変わっていない。実際に自分で変えるときはマウスカーソルを合わせてクリックすると変わる。ならば、click text field でかわるのだろうか、と試したが、変わらない。
いろいろと試したのだけれども、うまく変わらないので、暫定的にframeworkを使うことで無理やり値を変えた。
use framework "Foundation"
tell application "TextEdit"
activate
end tell
tell application "System Events"
tell process "TextEdit"
tell window "名称未設定"
tell combo box 1 of group 1
click button 1
end tell
end tell
end tell
end tell
my clickAction(x軸値, y軸値)
on clickAction(clickX, clickY)
set pt to {x:clickX, y:clickY}
tell current application
CGPostMouseEvent(pt, 1, 1, 1)
CGPostMouseEvent(pt, 1, 1, 0)
end tell
end clickAction
on doubleClickAction(clickX, clickY)
my clickAction(clickX, clickY)
delay 0.1
my clickAction(clickX, clickY)
end doubleClickAction
一応、10.15でもこのやり方で動くから、これでなんとかいけるが、座標を計算しないといけないし、決め打ちにしづらいのが難点。selectでなんとかいけないものか・・・
<$mt:Include module="関連記事" parent="1"$>]]>今回は、(なんちゃって)相対パスのようにファイル指定する方法。というのも、今までiCloudにスクリプトをおいてマシンやOSが変わっても動くようにしてたけれども、10.15からどうやらファイルの置き場所が変わるようで、絶対パスではなくて、相対パスが使えないかな〜と調べたのが始まり。
よくある、./ や ../ のようなパス指定はApplescriptでは使えない。基本は絶対パスでないといけない。ほかのApplescriptを読み込むような記述をしている場合、自分のようにiCloudみたいな場所に保存していると何らかの要因でパスがずれることがある。ではどうすればいいのだろうか・・・
ずれる部分を書き換えるしかない。
スクリプトのフォルダパスを調べて、それを使う。path to を使ってスクリプトの場所 と その親フォルダを調べる。以下のようなスクリプトでいける
tell application "Finder"
set ScriptPath to parent of (path to me) as text
end tell
display dialog ScriptPath
たとえば、 /HD/script/a/test.scpt のようなパスのスクリプトにこのスクリプトを走らせると、ダイアログに HD:script:a: と表示される。
で、同一のフォルダに入っている hoge.scpt を呼び出す場合は、以下のように記述すると呼び出せる。
tell application "Finder"
set ScriptPath to parent of (path to me) as text
end tell
#同じフォルダに入っているスクリプトを呼び出す
run script file (ScriptPath & "hoge.scpt")
絶対パスだが、スクリプトフォルダ外が変わっても問題ない。もう一つ。もし、/HD/script/a/test.scpt から、別のフォルダたとえば、/HD/script/b/hoge.scpt のようなファイルを呼び出したい場合は、parent of を増やせばいい。で、ファイルパスに b: を足す。
tell application "Finder"
set ScriptPath to parent of parent of (path to me) as text
end tell
#違うフォルダに入っているスクリプトを呼び出す
run script file (ScriptPath & "b:hoge.scpt")
割りと悩んだけれども、これでいまのところ問題ない
<$mt:Include module="関連記事" parent="1"$>]]>今回は、AppleScriptでポップアップボタン(セレクトボックス)の内容を変える方法
ポップアップボタン(htmlで言うセレクトボックス)の内容を変えるには、2回スクリプトでクリック動作を行う必要がある。また要素を調べる際もポップアップを一度クリックした状態で調べる必要がある。今回もシステム環境設定の「一般」を使用して、一般内にある強調表示色のポップアップボタンを変えてみる。
前回、「AppleScriptでcheckboxを操作する」で使った一般タブの UI element を調べるスクリプトを実行する。
tell application "System Events"
tell process "System Preferences"
tell window "一般"
every UI element
end tell
end tell
end tell
そうすると、次の用な結果を得られ、pop up button "強調表示色:" と言うのがあるのが分かる。名前がついているので分かりやすい
{static text "スクロールバーのクリック時:" , static text "サイドバーのアイコンサイズ:" , radio group 1 , static text "強調表示色:" , pop up button "強調表示色:" , static text "選択すると、開いていた書類とウインドウは、アプリケーションの再開時には復元されません。" , radio group 2 , button 1 , pop up button "サイドバーのアイコンサイズ:" , checkbox "アプリケーションを終了するときにウインドウを閉じる" , checkbox "書類を閉じるときに変更内容を保持するかどうかを確認" , static text "デフォルトのWebブラウザ:" , pop up button 3 , static text "スクロールバーの表示:" , static text "最近使った項目:" , static text "個の書類、アプリケーション、およびサーバ" , checkbox "使用可能な場合は滑らかな文字を使用" , checkbox "このMacとiCloudデバイス間でのHandoffを許可" , pop up button 4 , checkbox "メニューバーを自動的に表示/非表示" , checkbox "ライト" , checkbox "ブルー" , checkbox "ダーク" , static text "外観モード:" , static text "アクセントカラー:" , static text "ライト" , static text "ダーク" , checkbox "パープル" , checkbox "ピンク" , checkbox "レッド" , checkbox "オレンジ" , checkbox "イエロー" , checkbox "グリーン" , checkbox "グラファイト" , button 2 , button 3 , button 4 , toolbar 1 }
と言うことで、pop up button "強調表示色:" のUI element を調べるため、次のスクリプトを走らせる
tell application "System Events"
tell process "System Preferences"
tell window "一般"
tell pop up button "強調表示色:"
every UI element
end tell
end tell
end tell
end tell
すると、空の結果が返ってきてしまう。これを防ぐには、一度ポップアップをクリックした状態で調べる必要がある。
{}
と言うことで、click pop up button "強調表示色:" を tell window "一般" のすぐ後に挿入する。
tell application "System Events"
tell process "System Preferences"
tell window "一般"
click pop up button "強調表示色:"
tell pop up button "強調表示色:"
every UI element
end tell
end tell
end tell
end tell
そうすると、次の結果を得られる。もう一つ下の階層があるのが分かるので、tell pop up button "強調表示色:" を tell menu 1 of pop up button "強調表示色:" としてもう一度調べてみる。その下の階層に選択肢の要素があることが分かる。
{menu item "ブルー" , menu item "パープル" , menu item "ピンク" , menu item "レッド" , menu item "オレンジ" , menu item "イエロー" , menu item "グリーン" , menu item "グラファイト" , menu item "その他" }
以上の要素の手がかりを元に、二つのクリックを走らせる。1・click pop up button "強調表示色:" 2・click menu item "変えたい色" of menu 1 of pop up button "強調表示色:" で実際に色を変える。
tell application "System Events"
tell process "System Preferences"
tell window "一般"
click pop up button "強調表示色:"
click menu item "ピンク" of menu 1 of pop up button "強調表示色:"
end tell
end tell
end tell
これで強調表示色がピンクに変わっていればスクリプト成功。
<$mt:Include module="関連記事" parent="1"$>]]>個人的に大量に画像のあるページを作成する必要があったので、画像の遅延読み込みを行って負荷を減らそうとしてみた。その中で使いやすかった Lazy Load を使用したのだけれども、ちょっとはまった箇所もあったので、メモ。
1.x系と2.x系の2種類がサイトで紹介されているが、1.x系はjqueryを使用する必要があり、2.x系は単独で動かす事ができる。
よく使われている 1.x系のインストールと使い方
インストールは、Git hub に公開されている1.x系のファイルをダウンロード
jquery.lazyload.js を自分のサイトのスクリプト置き場に設置する。head内にjqueryとjquery.lazyload.jsのリンクを追加。パスは自分の環境に直して使う
<script src="jquery.js"></script>
<script src="jquery.lazyload.js"></script>
とりあえず、デフォルトの動作を確認するので、img タグに class="lazy" と srcで書くファイルのパスを data-original として記載。
最後にスクリプトで lazyload を呼び出す。画像より前にスクリプトを書くと動かない事もあるので、公開元のドキュメント通り、最後に書くのがいいかな。
<img class="lazy" data-original="img/example.jpg" width="640" height="480">
<script>
$(function() {
$("img.lazy").lazyload();
});
</script>
画像が問題なく表示されていれば、スクリプトが正しく動作しているが、ちょっと分かりづらいのでオプションを付けて動作を確認してみる
オプションを付ける場合は、lazyload()内に{}を追加し、付けたいオプションを付ける。とりあえず、分かりやすくするために、thresholdとeffectを付ける。これで、画面外に表示されているはずの画像がスクロールした際に読み込まれ表示されるのが分かる。
$(function() {
$("img.lazy").lazyload(
{
threshold: 10, // 10pxの距離まで近づいたら表示する
effect: "fadeIn" // フェードインアニメーションで表示
}
);
});
event | |
---|---|
click | クリックまたはタップ時に表示 |
mouseover | マウスカーソルを上に乗せた表示 |
sporty | *1 |
effect | |
---|---|
fadeIn | 浮き上がるアニメーションで表示 |
effect_speed | |
---|---|
fast | 素早く表示 |
slow | ゆっくり表示 |
数値 | 数値で表示スピードを指定(1000で1秒) |
threshold | |
---|---|
数値 | 指定したピクセルの距離まで近づいたら表示。たとえば、100なら、100ピクセルの距離まできたら表示する |
failure_limit | |
---|---|
数値 | 画面外にある画像のチェック枚数(デフォルトでは1)*2 |
*1 公式サイトでは、以下のコードで遅延処理できると書いているが、jqueryのバージョンの問題か動かない。
$(function() {
$("img.lazy").lazyload({
event : "sporty"
});
});
$(window).bind("load", function() {
var timeout = setTimeout(function() {
$("img.lazy").trigger("sporty")
}, 2000);
});
遅延処理で行う場合は以下の様に記載して動かすと良いかも。デモでは2秒後になると画像が表示される。
var hoge = function() {
$("img.lazy").lazyload();
}
$(window).on("load", function() {
var timeout = setTimeout( function(){
$("img.lazy").lazyload();
}, 2000);
});
*2 公式サイトの説明文では、以下の様に説明されている。
アンロードされた画像を介してページプラグインループをスクロールした後。画像が見えるようになったかどうかループチェックします。デフォルトでは、ビューポートの外側の最初の画像が見つかるとループは停止します。これは次の仮定に基づいています。ページ上の画像の順序は、HTMLコード内の画像の順序と同じです。レイアウトによっては、これが間違っている可能性があります。 failure_limit設定でロード動作を制御できます。
横並びのブロックレイアウトがある場合など、DOM順だとスクロールと意図しない画像の順番になっていることがあるので複数の画像のチェックをすることでそれを防ぐ方法です。
オプション以外にも色々とできることがあるので、いくつ記載。まずは、プレースホルダーの指定。こちらは、通常のsrcに画像が表示されるまでの代替画像を入れることができます。
<img src="/imo_common/images/demo/loading.gif" class="lazy" data-original="/imo_common/images/demo/demo1.jpeg">
普通にすると代替画像が分かりにくいので、クリックで表示する様にしたデモを用意しました。これだと画面外の画像を表示しようとした際、代替画像が表示されていて、クリックしないと表示されないようになっています。
最後にブラウザのジャバスクリプトが無効になっている場合の対応ですが、基本は noscript で対応してフォールバックする方法が公式で紹介されている。
<img src="/imo_common/images/demo/loading.gif" class="lazy" data-original="/imo_common/images/demo/demo1.jpeg"><noscript>
<img src="/imo_common/images/demo/demo1.jpeg" /></noscript>
ただ、問題なのはプレースホルダーを指定している場合、ジャバスクリプトを無効にしていると、プレースホルダー用の画像とフォールバック用の画像の二つが出てしまう問題がある。なので、それを回避するために、class="lazy" にcssを追記しておく必要がある。
.lazy {
display: none;
}
こうすることでジャバスクリプトが無効になっていてフォールバック用の画像が表示されても、プレースホルダー用の画像はnoneになっているので出ない。デモも用意した。ジャバスクリプトを無効にした場合、下の二枚はnoscriptがないので、表示されないようにした。
次は、jqueryがなくても動く 2.x系のインストールと使い方
インストールは、Git hub に公開されている2.x系のファイルをダウンロード
lazyload.js を自分のサイトのスクリプト置き場に設置する。head内にlazyload.jsのリンクを追加。パスは自分の環境に直して使う。jqueryはいらない。
<script src="lazyload.js"></script>
1.x系とは違うのは、classをlazyload deta-original を data-src として指定する。プレースホルダーを指定したい場合は、1.x系と同じでsrcで指定する。
<img class="lazyload" src="/imo_common/images/demo/loading.gif" data-src="/imo_common/images/demo/demo1.jpeg">
最後にスクリプトでlazyloadを指定する。
<script>
lazyload();
</script>
公式サイトを見た限りでは、1.x系のようなオプションの指定はできないようなので、基本的にはこれで動かす。
一応、今のところ使うかもしれない遅延実行の処理も。と言っても、1.x系の現在と同じで、settimeout を使って実行を遅らせるだけ。
<script>
window.addEventListener("load", function(event) {
let timeout = setTimeout(function() {
lazyload();
}, 1000);
});
</script>
一応デモも用意。
なんだか調べるのに疲れたな
<$mt:Include module="関連記事" parent="1"$>]]>今回は、AppleScriptでチェックボックスの操作を行う
チェックボックスには、オンとオフの状態があるので現在の状態を調べて求めている値に変える必要がある。今回は、システム環境設定の「一般」で「メニューバーを自動的に表示/非表示」の状態を切り替えを例に説明していく
最終的なスクリプトの流れとして、システム環境設定を立ち上げる→「一般」を選択する→「メニューバーを自動的に表示/非表示」をオンにする にする。
とりあえず、必要な情報を調べる。システム環境設定の要素がどうなってるのか知りたいので、環境設定を立ち上げた状態で以下のスクリプトで要素を調べる。
tell application "System Events"
tell process "System Preferences"
every UI element
end tell
end tell
結果の中に、radio group 1 というのがあるので、スクリプトの変数に radio group 1 of を書き足して実行させる
tell application "System Events"
set pla to radio group 1 of group 1 of window "名称未設定" of application process "TextEdit" of application "System Events"
tell pla
every UI element
end tell
end tell
以下の結果を得られる。(例のごとく、of application process "System Preferences" of application "System Events" は長いので置換して削除してある)
{window "システム環境設定" , menu bar 1 , UI element 3 }
window "システム環境設定"の要素を調べていく
tell application "System Events"
tell process "System Preferences"
tell window "システム環境設定"
every UI element
end tell
end tell
end tell
以下の結果を得られる。(例のごとく、いらん部分は置換して削除してある)
{scroll area 1 , button 1 , button 2 , button 3 , toolbar 1 }
今度は、scroll area 1 を調べてみる
tell application "System Events"
tell process "System Preferences"
tell window "システム環境設定"
tell scroll area 1
every UI element
end tell
end tell
end tell
end tell
お目当てのものの要素が出てくる、と言うことで、scroll area 1のボタンをクリックすれば望むメニューに行くことができる。それはあとで使うとして、手動で"一般"を選んで、チェックボックスの在りかを調べていく
{button "一般" , button "デスクトップとスクリーンセーバ" , button "Dock" , button "MissionControl" , button "言語と地域" , button "セキュリティとプライバシー" , button "Spotlight" , button "通知" , button "ディスプレイ" , button "省エネルギー" , button "キーボード" , button "マウス" ,button "トラックパッド" , button "プリンタとスキャナ" , button "サウンド" , button "起動ディスク" , button "iCloud" , button "インターネットアカウント" , button "WalletとApple Pay" , button "ソフトウェアアップデート" , button "ネットワーク" , button "Bluetooth" , button "機能拡張" , button "共有" , button "Touch ID" , button "ユーザとグループ" , button "ペアレンタルコントロール" , button "Siri" , button "日付と時刻" , button "TimeMachine" , button "アクセシビリティ" , button "Flash Player" }
と言うことで、一般に移動すると、環境設定のウインドウ名が "一般" に変わるので UI element で要素を調べる
tell application "System Events"
tell process "System Preferences"
tell window "一般"
every UI element
end tell
end tell
end tell
と、以下の結果を得られる
{static text "スクロールバーのクリック時:" , static text "サイドバーのアイコンサイズ:" , radio group 1 , static text "強調表示色:" , pop up button "強調表示色:" , static text "選択すると、開いていた書類とウインドウは、アプリケーションの再開時には復元されません。" , radio group 2 , button 1 , pop up button "サイドバーのアイコンサイズ:" , checkbox "アプリケーションを終了するときにウインドウを閉じる" , checkbox "書類を閉じるときに変更内容を保持するかどうかを確認" , static text "デフォルトのWebブラウザ:" , pop up button 3 , static text "スクロールバーの表示:" , static text "最近使った項目:" , static text "個の書類、アプリケーション、およびサーバ" , checkbox "使用可能な場合は滑らかな文字を使用" , checkbox "このMacとiCloudデバイス間でのHandoffを許可" , pop up button 4 , checkbox "メニューバーを自動的に表示/非表示" , checkbox "ライト" , checkbox "ブルー" , checkbox "ダーク" , static text "外観モード:" , static text "アクセントカラー:" , static text "ライト" , static text "ダーク" , checkbox "パープル" , checkbox "ピンク" , checkbox "レッド" , checkbox "オレンジ" , checkbox "イエロー" , checkbox "グリーン" , checkbox "グラファイト" , button 2 , button 3 , button 4 , toolbar 1 }
checkbox "メニューバーを自動的に表示/非表示" があるのが分かる。環境設定では要素名が付けられているので分かりやすいが、数字の連番だと総当たりで行くしかない。この項目が真ん中位にあるのは、おそらく後から追加された機能だからなんじゃなかろうかと思っている。何にせよ、名前を付けてくれているのでもうまんたい。
で、click checkbox "メニューバーを自動的に表示/非表示" をすればcheckbox自体はクリックできるが、それだとどの状態になるのか分からないので条件式で状態を調べてクリックさせる。チェックがある場合は、value が1 ない場合は、0なので、たとえば必ずcheckboxをオンにしたい場合は以下のようなスクリプトを走らせる
tell application "System Events"
tell process "System Preferences"
tell window "一般"
#オフの場合
if (value of checkbox "メニューバーを自動的に表示/非表示") = 0 then
click checkbox "メニューバーを自動的に表示/非表示"
end if
end tell
end tell
end tell
と言うことで、すべての動作をがっちゃんこさせる。これで、スクリプトを走らせると、"メニューバーを自動的に表示/非表示"のcheckboxがオンになる
tell application "System Preferences"
activate
end tell
tell application "System Events"
tell application "System Events"
tell process "System Preferences"
tell window 1
click button "すべてを表示" of group 1 of group 2 of toolbar 1
tell scroll area 1
click button "一般"
end tell
end tell
delay 1
tell window 1
#オフの場合
if (value of checkbox "メニューバーを自動的に表示/非表示") = 0 then
click checkbox "メニューバーを自動的に表示/非表示"
end if
end tell
end tell
end tell
end tell
最初に、システム環境設定を立ち上げて、activateさせる。続いて、"一般"に移動して、checkboxをクリックさせるが、その間には delay 1 を加えている。と言うのも、次の処理を遅らせないとマシンによっては動作しないことがある。
で、システム環境設定は同時に二枚でないので、window名を 1 として、click button "すべてを表示" of group 1 of group 2 of toolbar 1 を入れることで、万が一システム環境設定が立ち上がっていて、他のメニューに移動していても最初のメニュー画面に戻るので動くはず。
<$mt:Include module="関連記事" parent="1"$>]]>今回は、ラジオボタンを操作する方法
今回もテキストエディットを例に進める。普通のボタンと同じでラジオボタンも要素を指定してclickを走らせればいい。テキストエディットでは、上部の文字揃えの箇所がラジオボタンになっているので調べてclickさせる。
前回「AppleScriptで操作したいアプリの要素を調べる方法」で名称未設定のファイルの要素を調べる動作を説明して、その際、tell動作が重なってしまって分かりづらくなってきたので、変数を使ってすっきりさせる。
tell application "System Events"
set pla to group 1 of window "名称未設定" of application process "TextEdit" of application "System Events"
tell pla
every UI element
end tell
end tell
結果の中に、radio group 1 というのがあるので、スクリプトの変数に radio group 1 of を書き足して実行させる
tell application "System Events"
set pla to radio group 1 of group 1 of window "名称未設定" of application process "TextEdit" of application "System Events"
tell pla
every UI element
end tell
end tell
そうすると、以下の様な結果が得られてラジオボタンが4つあることが分かる。(of radio group 1 of group 1 of window "名称未設定2" of application process "TextEdit" of application "System Events" は長いので置換して削除してある)
{radio button 1 , radio button 2 , radio button 3 , radio button 4 }
スクリプト用に名前が付けられていないので、このラジオグループもそうだが、このラジオボタンがどのボタンに対応しているのかは実際にスクリプトを走らせないと分からない。
tell application "System Events"
set pla to radio group 1 of group 1 of window "名称未設定" of application process "TextEdit" of application "System Events"
tell pla
click radio button 2
end tell
end tell
2番を走らせると、「テキスト中央揃い」のボタンがクリックされる。この要領で探していくしかない。
<$mt:Include module="関連記事" parent="1"$>]]>今回は、指定したアプリ要素を調べる方法
AppleScriptを用いて操作を自動化したい場合、scriptを使ってアプリの要素を調べて組み立てる方法がある。Autometer で記録してやる方法のが楽そうだけども、OSが変わったりするとエラーが起きたるするので、基本AppleScriptやpythonなどを使って操作するのが望ましいと思う。
話が少しそれたけれども、今回はテキストエディットで書類ウインドウの上部にある固有のボタンをクリックする方法を例にあげつつ要素を調べる方法をまとめる。とりあえず、テキストエディットで新規書類を作成して、次のようなスクリプトを走らせる。
tell application "System Events"
tell process "TextEdit"
every UI element
end tell
end tell
だいたい、次のような結果を得られる。書類に名前がついている場合は、名称未設定ではなく、つけた名前が入っているはず。必要なのは、window名なので、window "名称未設定" をコピっておく。
{window "名称未設定" of application process "TextEdit" of application "System Events",
menu bar 1 of application process "TextEdit" of application "System Events",
UI element 3 of application process "TextEdit" of application "System Events"
}
そしたら、次のようなスクリプトで書類ウインドウのUI elementを調べる。ウインドウ名は先ほどコピったものにする
tell application "System Events"
tell process "TextEdit"
tell window "名称未設定"
every UI element
end tell
end tell
end tell
次のような結果を得られる
{scroll area 1 of window "名称未設定" of application process "TextEdit" of application "System Events", button 1 of window "名称未設定" of application process "TextEdit" of application "System Events", button 2 of window "名称未設定" of application process "TextEdit" of application "System Events", button 3 of window "名称未設定" of application process "TextEdit" of application "System Events", menu button 1 of window "名称未設定" of application process "TextEdit" of application "System Events", group 1 of window "名称未設定" of application process "TextEdit" of application "System Events", static text "名称未設定" of window "名称未設定" of application process "TextEdit" of application "System Events"}
が、見づらいので、of window "名称未設定" of application process "TextEdit" of application "System Events" を置換して削除
{scroll area 1 , button 1 , button 2 , button 3 , menu button 1 , group 1 , static text "名称未設定" }
ボタン要素がいくつかあるのがわかるが、これがどれに対応しているのかは、試してみないとわからない。ので、この情報をもとにクリックイベントを走らせる。
tell application "System Events"
tell process "TextEdit"
tell window "名称未設定"
click button 1
end tell
end tell
end tell
(多分昔から変わっていないと思うけど)Mojaveでは、ウインドウが閉じる。ので、button 1がウインドウの閉じるボタンだというのがわかる。要素名が定まっていない場合は、総当たりで調べていくしかない。次に group 1 の要素を調べてみる
tell application "System Events"
tell process "TextEdit"
tell window "名称未設定"
tell group 1
every UI element
end tell
end tell
end tell
end tell
そうすると、次のような結果を得られる(of group 1 of window "名称未設定" of application process "TextEdit" of application "System Events" をすでに置換済み)
{menu button "¶" , pop up button 1 , pop up button 2 , combo box 1 , color well 1 , color well 2 , group 1 , radio group 1 , pop up button 3 , menu button 2 }
menu button "¶" とあるので、テキストエディット固有のメニューのことだとわかる。なので、次のようにして試してみる
tell application "System Events"
tell process "TextEdit"
tell window "名称未設定"
tell group 1
click menu button "¶"
end tell
end tell
end tell
end tell
一番左のボタンがクリックされて、"¶"が出てくる。こうすると自分が作成したものでなくともアプリの要素を調べて操作することができる。
今回はあくまで要素を調べる方法なので、リストから選択する方法や、特殊なボタンの選択方法などは別の記事にまとめる。
<$mt:Include module="関連記事" parent="1"$>]]>