C# Seleniumを使ってChromeを自動操作してみる

C#

背景

  友達に自動予約ツールを作れほしいと頼まれましたので、ブラウザを自動操作し、2秒以内に予約確定が必要とのことでした。手動で予約を取るときに、コース予約が大人気のため、なかなか予約を取れずにこの依頼に至りました。

  上記の自動予約ツール以外にもブラウザ自動操作ができれば、いろなことができるはずです。リアル売買の自動処理とか株の売買も高額の資金の管理は決定権は人に任せたほうが良いですが、多少アルゴリズムにジャージのサポートはほしいですよね。あとは、物販の販売にも定期的に自動出品も可能になります。

C#コンソールアプリのプロジェクトを作成する

VisualStudioを立ち上げ、C#のコンソールアプリを作成します。

Seleniumを使えるようにNuGetより2つのパッケージをダウンロードします。

  • Selenium.WebDriver
  • Selenium.WebDriver.ChromeDriver

C# Selenium Chromeを自動で開く

using System;
using System.IO;
using System.Reflection;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;

namespace gymReserve
{
    class Program
    {
        static void Main(string[] args)
        {
            // Webドライバーのインスタンス化
            IWebDriver driver = new ChromeDriver(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));

            // URLに移動します。
            driver.Navigate().GoToUrl(@"https://www.yahoo.co.jp/");

            // なにかコンソールに文字を入力したらクロームを閉じる
            Console.ReadKey();
            driver.Quit();
        }
    }
}

C#でINIファイル読み込み

iniファイルを準備する

[SETTING]
;ID
ID=XXXX
;パスワード
PASSWORD=XXXX
;予約パスワード
RESERVATION_PASSWORD=XXXX
;予約タイムラグ(ms)
WAIT_TIME=100
;リトライ回数
RETRY_COUNT=10
;リトライ間隔(秒)
RETRY_INTERVAL=2

C#でiniファイル読み込むクラスを用意する

    class CSharpIni
    {
        // DLL関数の定義です。
        [DllImport("KERNEL32.DLL")]
        public static extern uint GetPrivateProfileString(
            string lpAppName,
            string lpKeyName,
            string lpDefault,
            StringBuilder lpReturnedString,
            uint nSize,
            string lpFileName);

        [DllImport("KERNEL32.DLL")]
        public static extern uint GetPrivateProfileInt(
            string lpAppName,
            string lpKeyName,
            int nDefault,
            string lpFileName);

        // DLL関数をラップしたメソッドです。
        public string GetValueString(string section, string key, string fileName)
        {
            var sb = new StringBuilder(1024);
            GetPrivateProfileString(section, key, "", sb, Convert.ToUInt32(sb.Capacity), fileName);
            return sb.ToString();
        }

        public int GetValueInt(string section, string key, string fileName)
        {
            var sb = new StringBuilder(1024);
            return (int)GetPrivateProfileInt(section, key, 0, fileName);
        }
    }

C#でiniファイルを読み込み

//iniファイル読み込み
var readIniFile = new CSharpIni();
var ID = readIniFile.GetValueString("SETTING", "ID", ".\\設定情報.ini");
var PASSWORD = readIniFile.GetValueString("SETTING", "PASSWORD", ".\\設定情報.ini");
var RESERVATION_PASSWORD = readIniFile.GetValueString("SETTING", "RESERVATION_PASSWORD", ".\\設定情報.ini");
var WAIT_TIME = readIniFile.GetValueString("SETTING", "WAIT_TIME", ".\\設定情報.ini");
int RETRY_COUNT = readIniFile.GetValueInt("SETTING", "RETRY_COUNT", ".\\設定情報.ini");
int RETRY_INTERVAL = readIniFile.GetValueInt("SETTING", "RETRY_INTERVAL", ".\\設定情報.ini");

C#でCSVファイル読み込み

CSVファイルを準備する

有料/無料区分,店舗,曜日,開始時間帯,プログラム名
無料,XXX,月,13時台,XXX
有料,XXX,火,21時台,XXX
有料,XXX,水,22時台,XXX
無料,XXX,木,15時台,XXX
無料,XXX,金,18時台,XXX
無料,XXX,土,19時台,XXX

CSVライブラリを参照する

using Csv;  // ライブラリCsv を使うのに必要です

C#でCSVファイルを文字列として取得

//CSVファイル読み込み
// ファイルの全内容を文字列に読込みます
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
string csv = File.ReadAllText(@".\XXXX.csv", Encoding.GetEncoding("Shift_JIS"));

C#でCSVファイルの行毎にLoop

//CSVファイルの行ごとにループ
foreach (ICsvLine line in CsvReader.ReadFromText(csv))

C#でCSVファイルの行のカラム項目を取得

string clock = line[@"開始時間帯"];

HTML要素の操作

IWebElement element = driver.FindElement(By.Id("ここにIDを入力"));

F12ボタンを押し、Chromeの開発者ツール(ディベロッパーツール)からウェブ要素を確認することができます。

WebDriverには標準のロケータが8種類あります。
https://www.selenium.dev/ja/documentation/webdriver/elements/locators/

ロケータ詳細
class nameclass名に値を含む要素を探す (複合クラス名は使えない)
css selectorCSSセレクタが一致する要素を探す
idid属性が一致する要素を探す
namename属性が一致する要素を探す
link texta要素のテキストが一致する要素を探す
partial link texta要素のテキストが部分一致する要素を探す
tag nameタグ名が一致する要素を探す
xpathXPathと一致する要素を探す

HTML要素のプルダウン選択

//検索条件入力画面
IWebElement selectElement = driver.FindElement(By.Name("XXXX"));
var selectObject = new SelectElement(selectElement);

// Select an <option> based upon its text
selectObject.SelectByText(line[@"有料/無料区分"]);

HTML要素複数checkBox選択

IList<IWebElement> elements = driver.FindElements(By.Name("dow[]"));
foreach (IWebElement e in elements)

if e.GetAttribute("value")= line[@"曜日"]
e.Click();

HTML要素button押す操作

//ボタンを押す操作
driver.FindElement(By.ClassName("btn")).Click();
//ボタンを押す操作
driver.FindElement(By.ClassName("btn")).Submit();

HTML要素button複数がある場合の配列処理

driver.FindElements(By.Name("id"))[1].SendKeys(ID);

HTML要素の文字列を入力

driver.FindElement(By.Name("pw")).SendKeys(RESERVATION_PASSWORD);

HTML要素の入力テキストをクリア

driver.FindElement(By.Name("XXXX")).Clear();

HTML要素文字列取得と判定

string resulText = driver.FindElement(By.ClassName("mgb15")).Text;
if (resulText.Contains("ありません"))

    ...
}

HTML要素取得の待ち処理

Thread.Sleep(RETRY_INTERVAL * 1000);

Chrome F5 Refresh更新処理

driver.Navigate().Refresh();

Chrome終了させる処理

driver.Quit();
Environment.Exit(0);

参考サイト

  • https://www.selenium.dev/ja/documentation/webdriver/
  • https://www.hanachiru-blog.com/entry/2020/03/12/120000
  • https://c-taquna.hatenablog.com/entry/2019/05/27/004135
  • https://www.toolsqa.com/selenium-c-sharp/
  • https://qiita.com/ymk1102_1t/items/42aa7c588ce97e3312b6
  • https://codechacha.com/ja/selenium-explicit-implicit-wait/
  • https://www.fenet.jp/dotnet/column/language/python/7851/#PythonSelenium%E3%81%A7%E3%81%AEwait%E3%81%AE%E6%96%B9%E6%B3%95%E3%81%A8%E3%81%AF%EF%BC%9F ページ遷移の待機方法 Python
  • https://www.webdevqa.jp.net/ja/c%23/selenium-c%EF%BC%83webdriver%EF%BC%9A%E8%A6%81%E7%B4%A0%E3%81%8C%E8%A1%A8%E7%A4%BA%E3%81%95%E3%82%8C%E3%82%8B%E3%81%BE%E3%81%A7%E5%BE%85%E3%81%A4/940710157/ ページ遷移の待機方法 C#
  • https://www.selenium.dev/ja/documentation/webdriver/waits/ 待機方法
  • https://tech-and-investment.com/csv2/ csvファイル読み込みと使用方法

コメント

タイトルとURLをコピーしました