目次

毎日1時間かかる更新作業やブログ投稿を自動化する

やりたいこと - 契約メディアにアクセス - ログインして更新箇所をクリック - 各通知はDiscordに報告し、各サイトチェックチャンネルにて一括管理 - 毎日のブログを投稿する(書き溜めたTips系記事をルーティン投稿)

Golang Agouti’s Tips

  1. ChromedriverはChrome browserとversionを合わせる
  2. driverは各処理ごとにNew
  3. ログインして、特定のボタンをクリックする
  4. iframeはObject().SwitchToFrame()してFocusする
    • iframeから離脱するときはPage().SwitchToParentFrame()

それぞれ叶えていく

1. ChromedriverはChrome browserとversionを合わせる

Chrome browserとChromedriverのversionをあわせて、命令と実行を連携、動く状態を作る Google chromedriver versions

2. driverは各処理ごとにNewして、処理終われば閉じる

go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Newで必要なdriver, pageを作成する
func NewPage() (*Client, error) {
	d := agouti.ChromeDriver(
		agouti.ChromeOptions(
			"args", []string{
				"--headless", // headlessモードの指定
				"--disable-gpu",
				"no-sandbox",
				"--window-size=1280,800", // ウィンドウサイズの指定
			}),
		agouti.Debug,
	)
	d.Start()

	page, err := d.NewPage()
	if err != nil {
		return nil, err
	}

    // 通知用
	dsc := new(notify.Discord)
	dsc.ID = "discord id"
	dsc.Token = "discord token"

	return &Client{
		D:    d,
		page: page,

		discord: dsc,
	}, nil
}

func (p *Client) Close() {
    // chromedriver chrome browser pageを閉じる
	p.page.Destroy()
    // chromedriver を閉じる
	p.D.Stop()
}

3. ログインして、特定のボタンをクリックする

go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
func AutoAccess() {
    // (弊プラクティス的には)
    // 実行関数にdriver pointer持ち歩くのではなく、処理ごとにNewしてCloseする
    if !do { // 実行するかのif 関数を挟む
        return
    }

    // 上記の関数で必要なものを作る
	c, err := NewPage()
	if err != nil {
		log.Error(err)
		return
	}
    // 作業が終わったら全部閉じる
	defer c.Close()

    // ログイン画面に移動
    if err := c.page.Navigate("<url>"); err != nil {
		log.Error(err)
		return
	}
    // ページアクセス後はしっかり待機する
	time.Sleep(time.Second)

    // input#idに入力
	if err := c.page.FirstByName("login").Fill("<login name>"); err != nil {
		log.Error(err)
		return
	}
	if err := c.page.FirstByName("pass").Fill("<password>"); err != nil {
		log.Error(err)
		return
	}
    // FormをSubmitする
	if err := c.page.FirstByName("form").Submit(); err != nil {
		log.Error(err)
		return
	}
	time.Sleep(time.Second)

    // ログイン後モーダルやポップアップがあれば承認する
    // - モーダル有無
	isVisible, err := c.page.FirstByClass("popup").Visible()
	if err != nil {
		log.Error(err)
		return
	}
	time.Sleep(time.Second)

    // モーダルがあれば、
	if isVisible {
		if err := c.page.FirstByClass("delete_popup").Click(); err != nil {
			log.Error(err)
			return
		}
	}

    /*
        // javascript alertなら
        if err := c.page.ConfirmPupup(); err != nil {
			log.Error(err)
			return
		}
    */


    // 本丸のアクセスクリック
	if err := c.page.FindByID("access").Click(); err != nil {
		log.Error(err)
		return
	}
	time.Sleep(time.Second)

}

4. iframeはObject().SwitchToFrame()してFocusする

例えば、Wordpressなどでよく使用されているCKEditor textbox iframeにフォーカスしたり、上位に離脱したりする場合に活用

go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// TextBoxのiframeにフォーカス
// iframe srcに直接アクセスする方法もあるが割愛
if err := c.page.Find("#textbox_frame > iframe").SwitchToFrame(); err != nil {
	log.Error(err)
	return
}

// フォーカスしたら、要素に文章なりを挿入していく
if err := c.page.Find("body").Fill("ブログ本文"); err != nil {
	log.Error(err)
	return
}

// フォーカスしたiframeから離脱したいときはRootまたはParentにSwitch
if err := c.page.SwitchToParentFrame(); err != nil {
	log.Error(err)
	return
}

// formなどのsubmit、またはbutton submitのクリック
if err := c.page.FindByName("submit").Clich(); err != nil {
	log.Error(err)
	return
}
time.Sleep(time.Second)

まとめ

これで、日々の広報活動や定時投稿などが自動化できますね。

日々更新で1時間かかっていれば、1ヶ月で30時間弱が違う仕事に充てられます。
経営者視点では同時間の人件費分が生産性向上に充当できるメリットがあります。

定義できる仕事は、適宜自動化に置き換えて、豊かな時間の使い方をしたいですね。