Python3+Selenium(Selene)+Chrome(headless)でMyDNS.jpを自動更新する

#Dockerイメージの作成
環境を汚したくないので、Dockerを使います。
Dockerfile中のgoogle-chromeの内容は
[EC2 UbuntuでGoogle Chromeをヘッドレス実行してスクリーンショットを採取する手順](https://qiita.com/shinsaka/items/37436e256c813d277d6d)を参考にしています。

```dockerfile:Dockerfile
FROM	python:3.6-stretch

ENV     DEBIAN_FRONTEND noninteractive

RUN	apt-get update && \
        apt-get install -y --no-install-recommends unzip wget curl unzip fontconfig && \
	wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add - && \
	echo "deb http://dl.google.com/linux/chrome/deb/ stable main" | tee /etc/apt/sources.list.d/google-chrome.list && \
	apt-get update && \
	apt-get -y install --no-install-recommends  google-chrome-stable

RUN     apt-get update && \
        apt-get install -y --no-install-recommends python3-dev python3-pip && \
        rm -rf /var/lib/apt/lists/*
RUN     pip3 install selene --pre

RUN	wget https://chromedriver.storage.googleapis.com/2.31/chromedriver_linux64.zip && \
	unzip chromedriver_linux64.zip -d /usr/bin/

WORKDIR /data
VOLUME  /data

COPY	IPAfont00303.zip /data/IPAfont00303.zip

RUN	unzip IPAfont00303.zip -d /usr/share/fonts/ && \
	fc-cache -fv
```
IPAfont00303.zipファイルのダウンロードはDockerfile中にwgetすると終了コードがエラーになって失敗するため事前にzipファイルでダウンロードしておき、ビルド時にホストからコピーします。

#MyDNS.jp更新用のスクリプト作成
Python経由でSeleniumを使用して更新を行います。
Selenium単体だと要素の指定が面倒なため、
CSSセレクタなどで要素の選択ができる「Selene」を使用します。

※Seleneの導入については、[Selene : Python にも Selenide ライクな Selenium ラッパーあります](https://qiita.com/kobanyan/items/d75d3176038ee80d006f)を参考にさせて頂きました。

```python3:mydns.py
# -*- coding: utf-8 -*-
import os
import traceback
import sys
import logging

from selene import config
from selene.browsers import BrowserName
from selene.api import *
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

def main():
    args = sys.argv
    logger = logging.getLogger(__name__)
 
    username = os.getenv("MYDNS_USER", "guest")
    password = os.getenv("MYDNS_PASS", "password")
    
    if len(args) < 2:
        raise ValueError("Please specify one of the least argument")
    
    options = Options()
    
    # google-chromeのインストールパス指定
    options.binary_location = '/usr/bin/google-chrome'
    
    # ヘッドレスモードで起動
    options.add_argument('--headless')
    options.add_argument('--no-sandbox')
    
    # 画面サイズ指定
    options.add_argument('--window-size=1280,1024')
    
    driver = webdriver.Chrome('chromedriver', chrome_options=options)
    
    config.browser_name = BrowserName.CHROME
    
    browser.set_driver(driver)
    
    # Mydnsトップページを開く
    browser.open_url('https://www.mydns.jp/')

    # ユーザー名,パスワード入力してログインボタンをクリック
    setvalue_nophoto('dd.content12:nth-child(3) > input:nth-child(1)',username)
    setvalue('dd.content12:nth-child(5) > input:nth-child(1)',password)
    clickbutton('dd.content12:nth-child(7) > input:nth-child(1)')
    
    # IP ADDE DIRECTを選択
    clickbutton('''body > table:nth-child(1) > tbody:nth-child(1) > 
                    tr:nth-child(4) > td:nth-child(1) > table:nth-child(1) > 
                    tbody:nth-child(1) > tr:nth-child(5) > td:nth-child(1) > 
                    a:nth-child(1) > img:nth-child(1)''')

    # IP v4アドレスをセット
    setvalue('dd.content14:nth-child(4) > input:nth-child(1)',args[1])
    
    # checkボタン押下
    clickbutton('dd.content12:nth-child(9) > input:nth-child(1)')
    
    # okボタン押下
    clickbutton('''table.content14:nth-child(3) > tbody:nth-child(1) > 
                    tr:nth-child(6) > td:nth-child(1) > input:nth-child(1)''')

    driver.quit()
 
def setvalue(cssselector,value):
    setvalue_nophoto(cssselector,value)
    browser.take_screenshot("mydns")
     
def clickbutton(cssselector):
    clickbutton_nophoto(cssselector)
    browser.take_screenshot("mydns")
   
def setvalue_nophoto(cssselector,value):
    s(by.css(cssselector)).set_value(value)
    
def clickbutton_nophoto(cssselector):
    s(by.css(cssselector)).click()
    
if __name__ == '__main__':
    main()
```
要素のCSSセレクタはブラウザからの取得そのままなので、最適ではない可能性があります。
第一引数には設定するIPv4アドレスを設定します。

#Jenkinsで定期実行してみる
```groovy:jenkinsfile
pipeline {
    agent {
        docker {
            image '(ビルドしたdockerイメージ名)'
        }
    }
    environment {
        MYDNS_USER="(mydnsのユーザー名)"
        MYDNS_PASS="(mydnsのパスワード)"
    }       
    stages() {
        stage('update-mydns')
        {
            steps() {
                checkout scm
                script { 
                    def ipaddress = globalip()

                    sh script: 'python mydns.py ' + ipaddress

                    archiveArtifacts artifacts: 'mydns/*.png'
                }
            }
        }        
    }

}

def globalip() {
    sh (
        returnStdout: true, 
        script: '''
            curl ifconfig.io
        '''
    )
}
```
archiveArtifactsしておけば、Selenium中で取得したスクリーンショットの保存が行えます。