numbersでエクセルのwebクエリのような機能はありますか?

webのデータを自動取得をしたいのですが、numbersでできる方法がありますか?

MacBook Air (11-inch, Mid 2012), OS X Mountain Lion (10.8.2)

投稿日 2012/10/18 23:08

返信
返信: 19

2014/05/07 19:47 T22T への返信

ブラウザ上で選択したテーブルの中身を CSV/TSV で出力...ですが、Camino だと選択部分の HTML ソースが AppleScript で取得できるので、比較的簡単にできそうです。


↓ 表を選択

↓ AppleScript で選択部分の HTML ソースを取得

↓ CSV/TSV に加工

↓ 出力


# Camino は開発が終了してしまったので、おすすめできないのが、最大の欠点...。


ーーーーー


別案としては Safari + Automator サービスを使った方法。


ユーザがアップロードしたファイル


↓ Bookmarklet か do JavaScript からテーブル番号を挿入

↓ その番号を選択して Automator サービス実行 (テキストを受け取る)

↓ CSV/TSV に加工 (do JavaScript)

↓ 出力


bookmarklet はこんな感じ (長いけど1行です)


javascript:(function(){var tables=document.getElementsByTagName('table');for(i=0;i<tables.length;i++){var div=document.createElement('div');div.innerHTML=i;div.style.backgroundColor='lightgreen';var table=document.getElementsByTagName('table').item(i);table.parentNode.insertBefore(div,table);}})();


# Automator サービスで選択したテキストを取得して...とするのが最も簡単なのですが、セル内改行があると期待どおりにデータが取得できないので、こんな面倒なことに...。


# ワンタッチではないので、ちょっとかっこ悪いけど、まあ我慢できるかなと。というか、JavaScript で全部やろうとしたけどできませんでした。


ーーーーー


あと、決まったデータを定期的に取得する場合は、ブラウザを使わずにスクリプト言語で直接 HTML ソースを取得→解析→出力する方法もあります。


HTML の解析ツールはいろいろありますが、PHP の Simple HTML DOM Parser が使いやすいと思います。AppleScript から使う場合は、スクリプトバンドル形式にして、バンドル内に突っ込んじゃうと良いでしょう。


Simple HTML DOM Parser

http://sourceforge.net/projects/simplehtmldom/

2014/05/11 20:53 T22T への返信

度々、失礼致します。 do JavaScriptコマンドを実行して定義した変数は、Safari?に保持されているようなので、再度、do JavaScriptコマンドを実行する際にそのまま使うことが出来る様です。 なので、マウスクリックで表を選択するイベントを付け加えてみました。


tell document 1 of application "Safari"


activate



-- 表にidが無ければidを付ける

set theScript to "

var tables=document.getElementsByTagName('table');

for(i=0;i<tables.length;i++)

{

if(tables[i].id==='')

{

tables[i].id='tbl_'.concat(i.toString());

}

}"


do JavaScripttheScript




-- 表のデータ(TSV)を返す関数を定義

set theScript to "

var theData =function(tableId){

var table=document.getElementById(tableId);

var str='';

var rows=table.rows;

for(r=0;r<rows.length;r++){

var cells=rows[r].cells;

for(c=0;c<cells.length;c++){

str=str+cells[c].textContent.trim().replace(/(\\r\\n|\\n|\\r|\\t)/gm,''); // テキスト中の改行やタブを取り除く

if(c<cells.length-1){str=str+'\\t'};

};

if(r<rows.length-1){str=str+'\\n'};

};

return str;

}

"

set theData to do JavaScripttheScript




--- 表にマウスオーバーイベントを付ける(枠の強調表示と背景色の変化、TSVデータのタイトル表示)

set theScript to "

for(i=0;i<tables.length;i++)

{

tables[i].onmouseover=function(){

this.style.backgroundColor='lightgreen'; // 背景色の設定

this.style.border='medium solid #0000EF'; // 枠の強調

};

tables[i].onmouseout=function(){

this.style.backgroundColor=''; // 背景色の解除

this.style.border=''; // 枠の解除

};

tables[i].title=theData(tables[i].id); // タイトルにデータを設定

}"


do JavaScripttheScript




--- 表にクリックイベントを付ける(クリックした表のidを変数_theIdに保存)

set theScript to "

var theId='';

for(i=0;i<tables.length;i++)

{

tables[i].onclick=function(){theId=this.id}

}

theId"

set theId to do JavaScripttheScript




-- クリックイベントを待つ


do JavaScript "alert('選択する表をクリックしてください。\\n\\n表にマウスを載せると強調表示されます。')"

try

repeat while (theId is "")

delay 1

set theId to do JavaScript "theId"

end repeat

set theId to quoted form of theId

set theData to do JavaScript "document.getElementById(" & theId & ").title"




-- クリップボードにデータを保存


set the clipboard totheData


do JavaScript "alert('データをクリップボードに保存致しました。')"

on error

do JavaScript "alert('処理を中断致しました.')"

end try


do JavaScript "location.reload()" # ページを再ロード


end tell

ユーザがアップロードしたファイル

Numbersに読む込む操作や、自動的に表の内容を更新する操作は、今後検討していきます。

2014/04/23 12:31 blue-mint への返信

試しに、気象庁のWeb pageにある、アメダスデータの表から富士山の現在の気温データを取得し、Numbersの表の選択したセルに入力するAutomatorのワークフローを作ってみました(下図)。『指定されたURLを取得』アクションには、『富士山(フジサン) 毎正時の観測データ』のURLを入力しています。

ユーザがアップロードしたファイル

2014/05/12 15:26 T22T への返信

do JavaScriptコマンドを実行して定義した変数は、Safari?に保持されているようなので、再度、do JavaScriptコマンドを実行する際にそのまま使うことが出来る様です。


ここに引っかかって、過去の自分のスクリプトを眺めてみたところ、重要なことを思い出しました。


do JavaScript だと、変数がグローバルになってしまうようなので、同名変数が既にある場合にちょっとまずいことになる可能性があります。変数汚染問題ってやつです。


これは無名関数にすると回避できますが、そうすると、値を返すことができなくなります。また、ページをリロードすればすべて御破算になりますが、ネットショッピング中とかはやるべきではありません。


根本的にひっくり返すような話で申し訳ありません。もっと早く思い出すべきでした。


ーーーーー


Bookmarklet - ブックマークレットのグローバル変数汚染デモ

http://www.teria.com/~koseki/memo/bookmarklets/blet_global.html


例えば、「表にクリックイベントを付ける(クリックした表のidを変数_theIdに保存」の変数名「i」を「n」にして、上記ページで試すと、クリックしても何も起こらなくなります。


もうちょっと分かりやすい例だとこんな感じ。


-- スクリプトA

tell document 1 of application "Safari"
    do JavaScript "
        document.body.style.color='green'
        var n = 5;
        n
    "
end tell


-- スクリプトB 無名関数

tell document 1 of application "Safari"
    do JavaScript "
        (function() {
            document.body.style.color='green'
            var n = 20;
            n
        })();
    "
end tell


検証手順

1. スクリプトA を実行した後で「アラート表示」ボタンを押す

2. ページをリロード

3. スクリプトB を実行した後で「アラート表示」ボタンを押す


アラート回数と値の取得状況を比べると良く分かると思います。

2014/05/03 20:17 T22T への返信

> delay 1


ここだけ。下のリンク先にある openWithWait() を使うと、ページの読み込み完了まで待ってくれます。Safari 最新版でちゃんと動くか分かりませんが、当方 (Safari 5.1.10) では大丈夫です。


applescript: Safariでページロードを待つ処理

http://tezfm.blogspot.jp/2009/10/applescript.html


AppleScriptでSafariのwebarchiveを保存したい

https://discussionsjapan.apple.com/thread/10124724

2014/05/11 22:14 T22T への返信

素晴らしい!感動しました!


Numbersに読む込む操作


ええと、CSV/TSV と書いておいてなんですが...、最初のスクリプトみたいに配列で渡してはどうでしょうか。実は Numbers のことが完全に頭から抜けてました...。何か申し訳ない...。


例えばこんな感じで行毎の多次元配列にしてみてはどうでしょうか?下手に改行を削ると、1\n2 → 12 みたいになっちゃうので、配列で渡せるならそうした方が安全かと。Numbers を使ってないので、どのようなカタチで渡せば良いか分かりませんが、一応参考まで。


-- 富士山
on run
    set n to 4
    my parse_table(n)
end run
--
on parse_table(n)
    tell document 1 of application "Safari"
        do JavaScript ("
            var table = document.getElementsByTagName('table')[" & n & "]
            var ary1 = []
            for (var r = 0; r < table.rows.length; r++) {
                var ary2 = []
                for(var c = 0; c < table.rows[r].cells.length; c++) {
                    data = table.rows[r].cells[c].innerHTML
                    //ここでテキスト処理
                    ary2.push(data)
                }
                ary1.push(ary2)
            }
            ary1
        ")
    end tell
end parse_table

2014/05/12 20:25 Hiro__S への返信

Hiro.S 様、


 重要な情報を頂きまして、有り難うございます。 ページのJavaScriptで定義されているグローバル変数と同じ名前をAppleScript側で再定義してしまうと、本来のページの機能が損なわれてしまう訳ですね。 tablesとか、tableとか、rowsとか、theData、theIdなど、いかにも重複しそうな変数名を使うのは駄目ですね。 他の変数名を使うにしても、重複していないかどうか確かめる処理が必要になるので、複雑になりそうです。 もう少し考えてみます。 とても参考になりました。 改めて、御礼申し上げます。  

2014/05/17 10:02 Hiro__S への返信

度々、失礼致します。 WebページのJavaScriptで定義されているグローバル変数の一覧を含むプロパティをObject.keys(windows)で取得できるようです。なので、予め変数に重複があるかどうか調べることができました。


tell document 1 of application "Safari"


set theScript to "Object.keys(window)"

set theGVs to (do JavaScripttheScript)


set theKeywords to {"tables", "theData", "theId"}

repeat with theWord in theKeywords

if (theGVs contains theWord) then

display alert ("このページにはグローバル変数 " & quoted form of theWord & " を含んでいます。¬


do JavaScriptで定義する変数名を変える必要があります。")

end if

end repeat


end tell


少し手間ですが、変数汚染を回避する良い方法がみるかるまで、ひとつひとつのWebページでグローバル変数を調べる必要がありそうです。

2014/05/03 20:23 Hiro__S への返信

Hiro.S 様


有り難うございます。 そうですねdelayコマンドで適当な時間を設定するよりも、ページが完全に読み込まれるまで待つ様にした方が良いですね。 リンク先のAppleScriptを勉強してみます。 有用な情報を頂きまして、ありがとうございました。 

このスレッドはシステム、またはAppleコミュニティチームによってロックされました。 問題解決の参考になる情報であれば、どの投稿にでも投票いただけます。またコミュニティで他の回答を検索することもできます。

numbersでエクセルのwebクエリのような機能はありますか?

Apple サポートコミュニティへようこそ
Apple ユーザ同士でお使いの製品について助け合うフォーラムです。Apple Account を使ってご参加ください。