using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.IO; using System.IO.Compression; using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Support.UI; using CSVDownloader.Code; using CSVDownloader.Store.CreditCSVData; using CSVDownloader.Store.QRCSVData; using CSVDownloader.Store.ElectronicMoneyDataStore; using ExpectedConditions = OpenQA.Selenium.Support.UI.ExpectedConditions; namespace CSVDownloader.Web { abstract class WebController { protected log4net.ILog logger_ = log4net.LogManager.GetLogger(""); protected ChromeDriver driver_; protected WebDriverWait wait_; private const int interval_milisec_ = 1000; protected CreditAgent agent_; /// /// 駐車場名とSpotIDのマッピング /// protected IDictionary dic_; public WebController(ChromeDriver driver) { driver_ = driver; wait_ = new WebDriverWait(driver_, TimeSpan.FromSeconds(10)); } public virtual void SetParkingDic(IDictionary dic) { dic_ = dic; } public CreditAgent GetCreditAgent() { return agent_; } abstract public ResultCode Login(LoginInfo login_info); abstract public ResultCode Download(DateTime from, DateTime to); abstract public ResultCode Logout(); public ResultCode Archive(String archive_filename) { logger_.Info("アーカイブ開始"); var dir_name = "archive"; if (!Directory.Exists(dir_name)) { Directory.CreateDirectory(dir_name); } String target = @$"{dir_name}\{archive_filename}"; logger_.Info($"{target}"); if (System.IO.File.Exists(target)) { logger_.Info($"上書き:{target}"); System.IO.File.Delete(target); } ZipFile.CreateFromDirectory("download", target); logger_.Info("アーカイブ終了"); return ResultCode.OK; } public virtual List GetCreditCSVDataList() { return new List(); } public virtual List GetQRCSVDataList() { return new List(); } public virtual List GetElectronicMoneyCSVDataList() { return new List(); } protected void Click(String xpath, bool wait = true) { if (wait) { var ele = wait_.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xpath))); ele.Click(); } else { var ele = driver_.FindElementByXPath(xpath); ele.Click(); } Console.WriteLine($"Click {xpath}"); Wait(interval_milisec_); } protected void Click(IWebElement ele) { ele.Click(); Wait(interval_milisec_); } protected void Send(String xpath, String value, bool enter = false) { var ele = wait_.Until(ExpectedConditions.ElementIsVisible(By.XPath(xpath))); ele.SendKeys(value); if (enter) { ele.SendKeys(OpenQA.Selenium.Keys.Enter); } Wait(interval_milisec_); } protected void Clear(String xpath) { var ele = wait_.Until(ExpectedConditions.ElementExists(By.XPath(xpath))); ele.Clear(); Wait(interval_milisec_); } protected void Select(String xpath, String value) { try { var ele = wait_.Until(ExpectedConditions.ElementIsVisible(By.XPath(xpath))); var select = new SelectElement(ele); var options = select.Options; select.SelectByValue(value); Wait(interval_milisec_); } catch (Exception e) { Console.WriteLine($" Select failed xpath:{xpath} value:{value}"); throw e; } } /// /// ダウンロードを開始したファイルを完了まで監視する /// 完了後はダウンロード完了ディレクトリに移動する /// /// protected void WaitForDownload(String filename) { String tmpdownload_dir = DriverFactory.GetTmpDownloadDir(); String download_dir = DriverFactory.GetDownloadDir(); int limit_start = 0; long last_size = 0; String complete_filename = ""; while (true) { var dir = new DirectoryInfo(tmpdownload_dir); var files = dir.GetFiles(); if (files.Length != 0) { var file = files[0]; if (file.Name.Contains(".crdownload") || file.Name.Contains(".tmp")) { // ダウンロード継続 last_size = file.Length; logger_.Info($"ダウンロード監視中:{file.Name} size:{file.Length}"); } else if (file.Length == last_size) { // ダウンロード完了 logger_.Info($"ダウンロード完了:{file.Name} size:{file.Length}"); complete_filename = file.Name; break; } else { // ダウンロード継続 last_size = file.Length; logger_.Info($"ダウンロード監視中:{file.Name} size:{file.Length}"); } } else { // ファイルが存在しない場合は、一定回数リトライし // 規定回数存在しない場合は失敗とする。 if (10 < limit_start) { throw new Exception("ダウンロード開始失敗"); } logger_.Info($"ダウンロード開始待ち"); limit_start++; } Wait(500); } // ファイルの移動 String source_filename = $@"{tmpdownload_dir}\{complete_filename}"; String dest_filename = $@"{download_dir}\{filename}"; System.IO.File.Move(source_filename, dest_filename, true); } protected void Wait(int milisec) { Thread.Sleep(milisec); } protected String GetSpotID(String parking_name) { if (!dic_.ContainsKey(parking_name)) { throw new ArgumentException(); } return dic_[parking_name]; } protected class CSVConfig { public bool header = false; public List remove_char = new List(); } protected List ReadCsv(String csvpath, CSVConfig config, Encoding enc) { var list = new List(); var fs = new FileStream(csvpath, FileMode.Open); var data = new byte[fs.Length]; fs.Read(data, 0, data.Length); fs.Close(); var content = enc.GetString(data); var lines = content.Split("\n"); bool header_skip = config.header; foreach (var line in lines) { var tmpline = line; line.Trim(); // 空の行はスキップ if (line.Length == 0) { continue; } // ヘッダー行のスキップ制御 if (header_skip) { header_skip = false; continue; } // 囲み文字の削除 if (config.remove_char != null) { foreach (var remove_char in config.remove_char) { tmpline = tmpline.Replace(remove_char, ""); } } var values = tmpline.Split(","); var elements = new String[values.Length]; int index = 0; foreach (var ele in values) { elements[index++] = ele.Trim(); } list.Add(elements); } return list; } /// /// デフォルトのフレームにもどる /// protected void SwitchToFrame() { driver_.SwitchTo().DefaultContent(); } /// /// フレームを切り替える。 /// /// protected void SwitchToFrame(String xpath) { var frame = wait_.Until(ExpectedConditions.ElementExists(By.XPath(xpath))); driver_.SwitchTo().Frame(frame); } /// /// 空の可能性があるソースをDateTimeへ変換する際、Null許容型として変換する。 /// /// /// protected DateTime? GetDateTime(String source) { if (source != null && 0 < source.Length) { return DateTime.Parse(source); } else { return null; } } protected void CloseAlert() { try { var alert = wait_.Until(ExpectedConditions.AlertIsPresent()); alert.Accept(); } catch (Exception) { logger_.Info("アラート表示なし"); return; } } } }