アレアレ

お役立ち情報、お悩み解決情報を発信!

xcode

Mac OSのCocoaアプリでSafariを自動操作する方法

Mac OSのCocoaアプリでSafariを自動操作する方法

今回は、Safariを使ったブラウザのネット操作を自動化したい人に伝えたいお役立ち情報です。

Mac OSにおいて、Safariを自動操作する方法としては、AutomatorやApple Scriptを利用した方法があります。これらの方法は、簡単な自動操作を定義する分には、とても役立つものです。

一方で、ちょっと凝ったことをしたい場合は、これらの方法では、困ることになるんですね。例えば、Safariに読み込んだ画面のHTMLのソースを解析して、「このような条件だったら、こうする」のような処理を定義するのが、AutomatorやApple Scriptでは難しいわけです。

そこで、ご紹介したいのが、今回の方法です。具体的には、Mac OSのCocoaアプリ、つまりデスクトップアプリを作り、そのアプリ上でWebViewを利用して、Safariの自動操作を行う方法です。

この方法を使うと、プログラミング言語のSwiftを利用して、ブラウザの自動操作を記述できるため、AutomatorやApple Scriptで作るよりも、複雑なことが記述しやすいんですね。

今回は、CocoaアプリからSafariを自動操作するサンプルとして、Googleの検索画面を表示し、そこにキーワード「hello」と入れて検索する、という処理を実現する方法をご紹介します。

開発環境

はじめに、今回の方法が動作することを確認が取れている環境ですが、次の通りです。

  • Mac OS: OS X El Capitan(バージョン10.11.6)
  • Xcode: Version 7.3.1(7D1014)
  • Swift: version 2.2 (swiftlang-703.0.18.8 clang-703.0.31)

Cocoa Applicationプロジェクトの新規作成

では、早速始めましょう。まず、Xcodeを起動したら、Cocoa Applicationプロジェクトを新規に作成します。

cocoa1

作成するプロジェクトの名前は、任意です。ここでは、「WebViewSample」と名付けることにします。開発言語は、「Swift」を選択してください。

cocoa2

WebKit ViewをViewに貼り付ける

以上の手順で、まっさらなCocoa Applicationプロジェクトを作成したら、次に、左のメニューからMain.storyboardを開きます。

そして、Main.storyboard内にあるView ControllerのViewに対して、WebKit Viewを貼り付けます。

cocoa3

続いて、今貼り付けたWebKit Viewのコンテキストメニューを開き、frameLoadDelegateに対し、View Controllerを関連付けます。次の図を参考に、frameLoadDelegateの右側の◯を、グイっとView Controllerまで引っ張っればその関連付けができます。

cocoa4

この関連付けを行わないと、WebViewに指定したURLのページをロードし終えたタイミングを判定できなくなります。なので、この関連付けは必ず行う必要があります。

ViewController.swiftのソースを修正する

以上のMain.storyboard側の設定を終えたら、いよいよ最後にプログラミングをして完了です。具体的には、ViewController.swiftのソースを修正していきます。

で、先に結論からご紹介すると、次のようにViewController.swiftを修正します。

import Cocoa
import WebKit //追加

class ViewController: NSViewController {

    @IBOutlet weak var webview: WebView!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Googleをロードする
        let url = NSURL(string: "https://www.google.com")
        let request = NSURLRequest(URL: url!)
        webview.mainFrame.loadRequest(request)
        
    }
    
    //ロード完了時
    func webView(sender: WebView!, didFinishLoadForFrame frame: WebFrame!)
    {
        //テキストボックスにキーワードを入力する
        webview.stringByEvaluatingJavaScriptFromString("document.getElementsByName('q')[0].value = 'hello';")

        //検索する
        webview.stringByEvaluatingJavaScriptFromString("document.getElementsByName('f')[0].submit();")       
    }

    override var representedObject: AnyObject? {
        didSet {
        }
    }
}

では、このソースの修正内容について解説します。

まず、上でWebKit ViewをViewに貼り付ける説明時に、解説しなかったのですが、貼り付けたWebKit Viewは、ViewController.swift側にOutlet「webview」として関連付ける必要があります。貼り付けたWebKit Viewをソース側から操作するためです。

貼り付けたWebKit ViewをViewController.swiftにOutletとして関連づけるためには、Main.storyboardを表示した状態で、XcodeのメニューのView→Assistant Editor→Show Assistant Editorを選択し、アシスタント・エディターを表示させます。

で、Main.storyboard上の貼り付けたWebKit ViewをControlキーを押しながら選択し、アシスタント・エディターに表示したViewController.swiftにグイっと引っ張ります。

すると、ViewController.swiftに、WebKit ViewをOutletとして関連付けられます。その際に、「webview」という名前で関連づけるというわけですね。

あとは、その関連付けた「webview」を使って、ブラウザの自動操作を行うだけです。で、このソースでは、まずviewDidLoadのタイミングで、WebViewに、Googleの検索画面をロードしています。

次にロード完了時の「webView(sender: WebView!, didFinishLoadForFrame frame: WebFrame!)」にて、ロードしたGoogleの検索画面に対し「キーワードを設定し検索する」という処理を行っています。

で、Googleの検索画面の入力欄にキーワードを入力したり、検索を行わせたりする処理は、実際には、WebViewにロードしたブラウザに対し、WebViewの「stringByEvaluatingJavaScriptFromString」メソッドを利用して、JavaScriptのコードを実行させて行っています。

このようにJavaScriptを実行することによって、WebViewにロードした画面に対し、自動操作を定義できるというわけです。

cocoa5

◯秒後に処理を実行する方法

このように、JavaScriptを使って、自動処理を記述できるため、WebViewにロードした画面に対して、「◯秒後に処理を実行する」ということも簡単に実現できます。

例えば、上のコードでは、Googleの画面が出たらすぐに検索してしまっていますが、それを「3秒後に検索する」という風に変更することもできます。

具体的には、次のようにロード完了時の処理を変更することで、それが実現できます。

    //ロード完了時
    func webView(sender: WebView!, didFinishLoadForFrame frame: WebFrame!)
    {
        //キーワードを入力し検索する関数search()を定義する
        webview.stringByEvaluatingJavaScriptFromString("function search(){ document.getElementsByName('q')[0].value = 'hello'; document.getElementsByName('f')[0].submit();}")

        //3秒後にsearch()を実行する
        webview.stringByEvaluatingJavaScriptFromString("setTimeout('search()', 3000)")
    }

このコードですが、キーワードを入力し検索する関数を定義し、それをJavaScriptの標準関数setTimeoutを利用して、指定秒後に実行しているだけです。

ちなみに、非同期でデータを読み込む画面において、完了条件を判定するのが面倒な時に、この方法が役立ちます。

Return Top