なにこれ
GoでWebDriverを使いたくて、試しに阿部寛のホームページでも回遊するかー。と軽いノリで手をつけたらちょいハマったのでメモ。
最終的に👇みたいなプログラムができた。
この記事読んで得られるモノ
- 阿部寛のホームページでメンズノンノ時代の阿部寛のスクショを取れるようになる
-
frameset
およびframe
が利用されているwebページを操作できるようになる - Go言語でブラウザ操作を行えるようになる
必要なもの
macなら以下でChromeDriverとAgoutiをインストールできます。簡単ね。
brew install chromedriver
go get github.com/sclevine/agouti
回遊する方法
以下コードで回遊できます。
package main
import (
"log"
"github.com/sclevine/agouti"
)
func main() {
driver := agouti.ChromeDriver()
// headlessにする場合はこっちを使う
// driver := agouti.ChromeDriver(
// agouti.ChromeOptions("args", []string{"--headless", "--disable-gpu", "--no-sandbox"}),
// )
if err := driver.Start(); err != nil {
log.Fatalf("driverの起動に失敗しました : %v", err)
}
defer driver.Stop()
page, err := driver.NewPage(agouti.Browser("chrome"))
if err != nil {
log.Fatalf("セッション作成に失敗しました : %v", err)
}
// 阿部寛のウェブページに遷移する
if err := page.Navigate("http://abehiroshi.la.coocan.jp/"); err != nil {
log.Fatalf("阿部寛になにかあったかもしれません : %v", err)
}
// 写真集のリンクを検索する
// framesetの中の要素を検索するには一旦該当のフレームにフォーカスしなければならない
// 左側のフレームにフォーカスする
if err := page.FindByXPath("/html/frameset/frame[1]").SwitchToFrame(); err != nil {
log.Fatalf("阿部寛の左側frameにフォーカスできませんでした : %v", err)
}
// 「写真集」をクリック
if err := page.FindByXPath("html/body/table/tbody/tr[10]/td[3]/p/a").Click(); err != nil {
log.Fatalf("阿部寛の写真集が見つかりませんでした : %v", err)
}
// フレームのフォーカス外すためrootにもどる
if err := page.SwitchToRootFrame(); err != nil {
log.Fatalf("しょうも無いエラーが発生しました : %v", err)
}
// 右側のフレームにフォーカスする
if err := page.FindByXPath("/html/frameset/frame[2]").SwitchToFrame(); err != nil {
log.Fatalf("阿部寛の右側frameにフォーカスできませんでした : %v", err)
}
// 「メンズノンノ阿部寛」をクリック
if err := page.FindByXPath("/html/body/table/tbody/tr[8]/td[2]/strong/a").Click(); err != nil {
log.Fatalf("阿部寛のメンズノンノがみつかりませんでした : %v", err)
}
// スクショとる
if err := page.Screenshot("./abe_hiroshi.jpg"); err != nil {
log.Fatalf("スクショ取れまへん : %v", err)
}
}
ハマったこと
frame内部の要素にアクセスできないよぉぉぉ😭
コードで言うと// 写真集のリンクを検索する
のコメント以下でハマってた。。。
トップページから写真集のリンクをクリックしようとGoogle ChromeのDeveloper ToolsでXPath
をコピーしてFindByXPath
に貼り付けたのですが、要素が見つからないエラーが発生した。
failed to select elements from selection 'XPath: html/body/table/tbody/tr[10]/td[3]/p/a [single]': element not found
なんで。。。
ちゃんとHTMLを読んで見るとframesetおよびframe
の存在を見つけました。
あれ?Developer ToolsでコピーしたXPathはhtml/body/table/tbody/tr[10]/td[3]/p/a
ですね。これじゃ見つからないですね。
html/frameset/frame/.......
って書けば良いのかな?
ん?#document
ってなにこれ?っていうかframeってなに?わからぬ。。。
...
どうやら阿部寛のホームページは以下のように2つのframeで構成されているということがわかった。
解決方法
AgoutiのドキュメントでFrameで検索してみるとSwitchToFrame()
ってメソッドを見つけた。
func (s *Selection) SwitchToFrame() error
SwitchToFrame focuses on the frame specified by the selection. All new and existing selections will refer to the new frame. All further Page methods will apply to this frame as well.
https://godoc.org/github.com/sclevine/agouti#Selection.SwitchToFrame
どうやらframeにフォーカスを当てる必要があるらしい。
そのためframeを指定してから要素を検索すればOK。
またframeのフォーカスを外す SwitchToRootFrame()
ってメソッドも用意されていた。
なので、以下方針でリンクをクリックすることにする
- トップページにアクセス
- 左側のフレームにフォーカスする
-
写真集
リンクをクリックする - フレームのフォーカスをRootに戻す
- 右側のフレームにフォーカスする
-
メンズノンノ阿部寛
リンクをクリックする
// 写真集のリンクを検索する
// frameの中の要素を検索するには一旦該当のフレームにフォーカスしなければならない
// 左側のフレームにフォーカスする
page.FindByXPath("/html/frameset/frame[1]").SwitchToFrame()
// 「写真集」をクリック
page.FindByXPath("html/body/table/tbody/tr[10]/td[3]/p/a").Click()
// 左側フレームのフォーカス外すためrootにもどる
page.SwitchToRootFrame()
// 右側のフレームにフォーカスする
page.FindByXPath("/html/frameset/frame[2]").SwitchToFrame()
// 「メンズノンノ阿部寛」をクリック
page.FindByXPath("/html/body/table/tbody/tr[8]/td[2]/strong/a").Click()
これでframeを利用しているWebページに回遊できるようになりました👍