舎路(シアトル)日記

シアトルで働く日本人プログラマの日記です

iKnow をスクレイピングしようとしたら https://iknow.jp/login が派手に JavaScript を使っていた。

仕方がないので Ghost Driver 経由で PhantomJS を呼ぼうと思ったら、最近 Ghost Driver はあまりメンテナンスされていないらしく

If you need a better maintained WebDriver implementation, and write your code in Java, why not checkout Machine Publishers’ jBrowserDriver? Tell Dan Hollingsworth I sent you.

代わりに、jBrowserDriver がすすめられていた。jBrowserDriver は

A programmable, embedded web browser driver compatible with the Selenium WebDriver spec – fast, headless, WebKit-based, 100% pure Java, and no browser dependencies

をうたうライブラリで、JavaFX の javafx.scene.web.WebView を使っている。

    val driver = new JBrowserDriver(Settings.builder.timezone(Timezone.AMERICA_NEWYORK).build)

    driver.get("https://iknow.jp/login")

    driver.findElement(By.name("user[email]")).sendKeys("alice@example.com")
    driver.findElement(By.name("user[password]")).sendKeys("pa55w0rd")

    driver.findElement(By.tagName("form")).submit()

こんな感じに使える。

実装

実装を少し見てみると、JBrowserDriver を new するたびに、java を子プロセスとして起動して

  public JBrowserDriver(final Settings settings) {
    ...
    sessionId = new SessionId(launchProcess(settings, configuredPortGroup.get()));
    if (actualPortGroup.get() == null) {
      Util.handleException(new IllegalStateException("Could not launch browser."));
    }
    JBrowserDriverRemote instanceTmp = null;
    try {
      synchronized (lock) {
        instanceTmp = (JBrowserDriverRemote) LocateRegistry
            .getRegistry(settings.host(), (int) actualPortGroup.get().child,
                new SocketFactory(settings.host(), actualPortGroup.get(), locks))
            .lookup("JBrowserDriverRemote");
        instanceTmp.setUp(settings);
      }
    } catch (Throwable t) {
      Util.handleException(t);
    }
    remote = instanceTmp;
    ...
  }

子プロセスとは RMI 経由で通信していた。

  @Override
  public String getPageSource() {
    try {
      synchronized (lock) {
        return remote.getPageSource();
      }
    } catch (Throwable t) {
      Util.handleException(t);
      return null;
    }
  }

なにもインストールせずに Java から簡単に WebKit が呼べるというのはちょっと面白い。