Chrome
Selenium
python3
mydns
selene

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

Dockerイメージの作成

環境を汚したくないので、Dockerを使います。
Dockerfile中のgoogle-chromeの内容は
EC2 UbuntuでGoogle Chromeをヘッドレス実行してスクリーンショットを採取する手順を参考にしています。

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 ラッパーありますを参考にさせて頂きました。

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で定期実行してみる

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中で取得したスクリーンショットの保存が行えます。