きなこもち.net

.NET Framework × UiPath,Orchestrator × Azure × AWS × Angularなどの忘備録

Selenium × .NET 5 × Console AppでRPA風のことをしてみたメモ

目的

Seleniumを使ったConsoleApplicationの環境構築メモ。
RPAっぽいことをするためのことはじめ。

準備

Nugetでインストールするもの

そのほか

ターゲットフレームワークは、.NET 5.0を選択。

Helloworld

Seleniumのサイトのサンプルコードを使って動作確認。

class Program
{
    public Program()
    {
    }
    static void Main(string[] args)
    {
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((context, services) =>
            {
                services.AddTransient<Program>();
            })
            .Build().Services
            .GetRequiredService<Program>()
            .Run(args);
    }
    public void Run(string[] args)
    {
        Console.WriteLine("Hello");
        using (var driver = new ChromeDriver("."))
        {
            //Navigate to DotNet website
            driver.Navigate().GoToUrl("https://dotnet.microsoft.com/");
            //Click the Get Started button
            driver.FindElement(By.LinkText("Get Started")).Click();
            // Get Started section is a multi-step wizard
            // The following sections will find the visible next step button until there's no next step button left
            IWebElement nextLink = null;
            do
            {
                nextLink?.Click();
                nextLink = driver.FindElements(By.CssSelector(".step:not([style='display:none;']):not([style='display: none;']) .step-select")).FirstOrDefault();
            } while (nextLink != null);
            // on the last step, grab the title of the step wich should be equal to "Next steps"
            var lastStepTitle = driver.FindElement(By.CssSelector(".step:not([style='display:none;']):not([style='display: none;']) h2")).Text;
            // verify the title is the expected value "Next steps"
            Console.WriteLine(lastStepTitle); 
        }
    }
}

Unit Test用のサンプルだったため、最後にAssertの処理があったが、ConsoleWriteLineに変更してコンソールアプリとして動くようにした。

Yahooの乗換案内から、料金を取得する。

ソースコード

public string GetFareOfRoute1(string from, string to)
{
    using (var driver = new ChromeDriver())
    {
        driver.Navigate().GoToUrl("https://transit.yahoo.co.jp/");
        var sFrom = driver.FindElement(By.Id("sfrom"));
        sFrom.Clear();
        sFrom.SendKeys(from);
        sFrom.SendTabKey();
        
        var sTo = driver.SwitchTo().ActiveElement();
        sTo.SendKeys(to);
        var searchModule = driver.FindElement(By.Id("searchModuleSubmit"));
        searchModule.Click();
        searchModule.DelayAction(1000);
        var fare = driver.FindElement(By.XPath("//*[@id=\"rsltlst\"]/li[1]/dl/dd/ul/li[2]")).Text;
        return fare;
    }
}

検索結果の表には、IDが指定されていたが、表の中の各項目にはそれらしいIDがなかったため、Xpathを利用して対象のElementを特定し、そこから値を取得するようにした。その他の項目については、IDが指定されていたため、ID経由でアクセスすることができた。
タブキーの送信と、待機処理は後々のことを考えて拡張メソッドとして定義した。キーボード操作はほかにもいろいろあるため、必要に応じてここのメソッドを拡張していこうと思う。

public static class SeleniumDriverExtension
{
    public static void SendTabKey(this IWebElement element)
    {
        element.SendKeys("\uE004");
    }
    public static void DelayAction(this IWebElement element, int millisecondsDelay)
    {
        Task.Delay(millisecondsDelay).Wait();
    }
}