2009年10月5日月曜日

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

applescriptの、`open location` 命令を使ってSafariを起動し、 開いたページのDOMを `do javascript` 命令でいじくる、 このやり方で、applescriptからSafariを自動制御することが可能だ。
でも、`open location` をした後で、 すぐに `do javascript` 命令を発行しても、 ページの内容が完全にロードされていなかったりして、うまくいかない場合がある。
そこで、それら一連のロード待ち処理を行う、 applescriptのハンドラを書いてみた。

以下がそのサンプルソース。
-- open `theUrl` and check to complete page loading
--   timeoutSec: timeout(sec)
--   Return true if success
on openWithWait(theUrl, timeoutSec)
  tell application "Safari"
    open location "about:blank"
    -- display dialog URL of document 1 as text
    activate
    delay 0.5
    do JavaScript "location.href=\"" & theUrl & "\";" in document 1
    repeat timeoutSec times
      delay 1
      if ((URL of document 1 as text) does not start with "about:") then
        set state to do JavaScript "document.readyState" in document 1
        if (state = "complete") then return true
      end if
    end repeat
    return false
  end tell
end openWithWait

-- Handler that waits for page to be loaded
--   timeoutSec:  timeout(sec)
-- ex. my markDoc() 
--     do JavaScript "document.forms[0].submit();" in document 1
--     if my waitForLoad(30) then ... else ... endif
on waitForLoad(timeoutSec)
  tell application "Safari"
    delay 0.5
    repeat timeoutSec times
      delay 1
      if not my isMarkDoc() then
        set state to do JavaScript "document.readyState" in document 1
        if (state = "complete") then return true
      else
        -- log ("markd")
      end if
    end repeat
    return false
  end tell
end waitForLoad

on markDoc()
  tell application "Safari"
    do JavaScript "document['(@_@)'] = '@_@';" in document 1
  end tell
end markDoc

on isMarkDoc()
  tell application "Safari"
    set scp to do JavaScript "document['(@_@)'];" in document 1
    -- log ("scp=" & scp)
    return scp = "@_@"
  end tell
end isMarkDoc

-- A Sample for openWithWait() and waitForLoad()
-- ( Open wikipedia, and set `applescript` to the textfield, 
--   and then submit form)
tell application "Safari"
  -- set theUrl to "http://en.wikipedia.org/wiki/Main_Page"
  set theUrl to "http://ja.wikipedia.org/wiki/"
  if (my openWithWait(theUrl, 10)) then
    tell document 1
      set title to (do JavaScript "document.title")
      do JavaScript "document.forms[0].search.value = 'applescript';"
      my markDoc() -- Mark current document
      do JavaScript "document.forms[0].submit();"
      if (my waitForLoad(10)) then
        display dialog "Success to open " & title & " and submit"
      else
        display dialog "Cannot submit"
      end if
    end tell
  else
    display dialog "Cannot open " & theUrl
  end if
end tell
サンプルの内容は、Safariでwikipediaを開き、 検索フォームに`applescript`を指定、最後にサブミット、という至って単純なもの。

ここで、openWithWait は、引数で指定したURLをsafariで開き、 新しいウィンドウでのページロード終了を待つハンドラ。うまくいけばtrueを返す。
ページロードの終了を待つのに、 ダミーでブランクページを開いているのがミソ。
document.readyState == "complete"だけで判断すると、 safariが前に表示していた documentをみていたりしてうまく動作しない時がある。 そこで一旦、about:blankを開き、documentのURLがabout: から http: になるのを待ってから、 document.readyStateをチェックするようにしている。

一方 waitForLoad は、ページ遷移後のロード終了を待つハンドラ。 submit()やlocation.href = xxx などの発行後に使う。 これもうまくいけばtrueを返し、失敗すればfalseでリターンする。
一般的な使い方はこんな感じだ。
  tell application "Safari"
    ......................
    -- ページ遷移をさせる前に、 現在のdocumentにダミーの
    -- javascriptプロパティーをマークする
    my markDoc()

    -- ページを遷移させる
    do JavaScript "document.forms[0].submit();" in document 1 

    -- ページロードを待つ (timeoutは10秒)
    if my waitForLoad(10) then
      ..........................
    end if
    ......................
  end tell
ページの遷移を起こす前に、 今見ているdocumentに適当なダミーの属性を与え、 遷移後はその属性が消えている事を確認してから、document.readyState をチェックするという、かなり怪しい方法なのだが.... いちおう動いている。

ところで、Safariでブランクページを表示するURLは、 about:blank というので本当に正しいのだろうか?
about:hoge でも about:qweqwe でも、 about: が付けばなんでもブランクページになるようだが...

0 件のコメント:

コメントを投稿