protected ApiClient(string address, TimeZoneKind timeZone, string apiKey, string apiSecret, TimeSpan?rateLimit = null, int version = 2) : base(address, timeZone) { _rateLimit = rateLimit ?? TimeSpan.FromSeconds(5); ApiKey = apiKey; ApiSecret = apiSecret; }
protected SeleniumClient(string address, TimeZoneKind timeZone, string login, string password, bool headlessMode) : base(address, timeZone) { _login = login; _password = password; _headlessMode = headlessMode; _sdm = new SeleniumDriverManager(); }
public TestCase(string srcTag, string normalizedTag, TimeZoneKind kind, int utcOffset) { m_srcTag = srcTag; m_normalizedTag = normalizedTag; m_kind = kind; m_utcOffset = utcOffset; }
public static DateTime ToDateTime(Double javaScriptTime, TimeZoneKind timezoneKind) { var timezoneInfo = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneKindDictionary[timezoneKind]); var inputDateTime = UnixEpoch.AddMilliseconds(javaScriptTime); var convertDateTime = inputDateTime.AddTicks(timezoneInfo.BaseUtcOffset.Ticks); return convertDateTime; }
public static Double ToDouble(DateTime dateTime, TimeZoneKind timezoneKind) { dateTime = dateTime.AddMilliseconds(-1 * dateTime.Millisecond); var timezoneInfo = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneKindDictionary[timezoneKind]); var target = dateTime.AddTicks(-1 * timezoneInfo.BaseUtcOffset.Ticks); var timespan = new TimeSpan(target.Ticks - UnixEpoch.Ticks); return timespan.TotalMilliseconds; }
public static DateTime ToDateTime(Double javaScriptTime, TimeZoneKind timezoneKind) { var timezoneInfo = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneKindDictionary[timezoneKind]); var inputDateTime = UnixEpoch.AddMilliseconds(javaScriptTime); var convertDateTime = inputDateTime.AddTicks(timezoneInfo.BaseUtcOffset.Ticks); return(convertDateTime); }
public static Double ToDouble(DateTime dateTime, TimeZoneKind timezoneKind) { dateTime = dateTime.AddMilliseconds(-1 * dateTime.Millisecond); var timezoneInfo = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneKindDictionary[timezoneKind]); var target = dateTime.AddTicks(-1 * timezoneInfo.BaseUtcOffset.Ticks); var timespan = new TimeSpan(target.Ticks - UnixEpoch.Ticks); return(timespan.TotalMilliseconds); }
public BetsResponse Parse(string html, AgilityRestManager arm, TipsterResponse tipster, ExtendedTime fromDateClientLocal, TimeZoneKind serverTimezone) { HandleErrors(html); var fromDate = fromDateClientLocal?.ToTimezone(serverTimezone); // konwertuj na strefę czasową serwera, nie znamy czasu serwera, prawdopodobnie UTC var newBets = new List <BetResponse>(); var spanBettingPicks = html.HtmlRoot() .Descendants() .Where(n => n.HasClass("bettingpick")) .ToArray(); var i = 0; var brpLs = LocalizationManager.GetLoaderBetshootResponseParseLocalizedStrings(); foreach (var spanBp in spanBettingPicks) { OnInformationSending($"{brpLs[0][0]} ({++i} {brpLs[0][1]} {spanBettingPicks.Length})..."); // ($"Wczytywanie zakładów ({++i} z {spanBettingPicks.Length})..."); var strDate = spanBp.Descendants() .Single(x => x.HasClass("bettingpickdate")) .InnerText; var dateArr = strDate.Split('-').Swap(0, 2); var date = new ExtendedTime(new DateTime(dateArr[2].ToInt(), dateArr[1].ToInt(), dateArr[0].ToInt())); var spanBetResultClass = spanBp.Descendants("span") .Single(span => span.HasClass("mgreen", "mred", "morange", "munits2")) .GetOnlyClass(); // fix opisany w konwerterze var stake = spanBp.Descendants("span").Single(span => span.HasClass("pick-stake")).InnerText.Trim().ToInt(); var profit = spanBp.Descendants("span").Single(span => span.HasClass("munits")).InnerText.Trim().ToDoubleN(); var pickStr = spanBp.Descendants("span").Single(span => span.HasClass("predict")).InnerText.RemoveHTMLSymbols(); var spanPickTeams = spanBp.Descendants("span").Single(span => span.HasClass("pick-teams")); var aPickTeams = spanPickTeams.Descendants("a").SingleOrDefault(); var matchStr = (aPickTeams ?? spanPickTeams).InnerText.RemoveHTMLSymbols(); var rawMatchResultStr = spanBp.Descendants("span").Single(x => x.HasClass("mresult")).InnerText; var odds = spanBp.Descendants("span").Single(x => x.HasClass("pick-odd")).InnerText.ToDouble(); var hrefAPickTeams = aPickTeams?.GetAttributeValue("href", ""); string disciplineStr = null; string leagueName = null; if (hrefAPickTeams != null) { var disciplineLeagueStr = arm.GetHtml(hrefAPickTeams).HtmlRoot().Descendants("p") .Single(p => p.InnerText.Trim().EndsWithAny(tipster.Name)).InnerText.RemoveHTMLSymbols().Split(" - "); disciplineStr = disciplineLeagueStr[0]; leagueName = disciplineLeagueStr[1]; } var newBet = new BetResponse { Date = date, HomeName = matchStr.BeforeFirst(" - "), AwayName = matchStr.AfterFirst(" - "), Pick = PickConverter.ParseToPickResponse(pickStr, matchStr), MatchResult = MatchConverter.ToMatchResultResponse(rawMatchResultStr), BetResult = BetConverter.ParseBetshootResultStringToBetResult(spanBetResultClass, stake, odds, profit), Odds = odds, Discipline = DisciplineConverter.ToDisciplineTypeOrNull(disciplineStr), LeagueName = leagueName }; if (fromDate != null && date < fromDate) { break; } newBets.Add(newBet); } OnInformationSending(brpLs[1][0]); Tipster = tipster; Bets = newBets; return(this); }
public BetResponse Parse(AsianoddsSeleniumDriverManager sdm, BetRequest betRequest, TimeZoneKind tz, AsianoddsClient ao) { OnInformationSending("Wyszukiwanie zakładu..."); HandleErrors(sdm); if (!betRequest.PickChoice?.In(_supportedPickChoices) == true) { throw new AsianoddsException("Typ zakładu nie jest wspierany przez Asianodds"); } var ddlDisciplineType = sdm.FindElementByXPath("//*[@id='selAdvSearchSportType']"); var optionDisciplines = ddlDisciplineType.FindElements(By.TagName("option")).ToArray(); var avalDisciplines = optionDisciplines.Select(o => o.Text.ToEnum <DisciplineType>()); var disciplinesToSearch = (betRequest.Discipline?.ToEnumerable() ?? avalDisciplines).ToArray(); var searchTerms = $"{betRequest.MatchHomeName} {betRequest.MatchAwayName}".Trim().Split(" ") .Select(w => w.Trim().ToLower()).Where(w => w.Length > 2 && !w.ContainsAny("(", ")")).Distinct().ToArray(); var resultsNum = 0; var candidateBets = new List <BetRequest>(); const string xpathDivSearchInfo = ".//div[@id='gamecontainer']//div[@class='divNoEvent']"; var txtSearchMatch = sdm.FindElementByXPath("//*[@id='txtFilterGamesAndLeauges']"); bool timedOut; do { timedOut = sdm.WaitUntilOrTimeout(d => optionDisciplines.All(o => o.Text.Length > 0)); // Poczekaj na załadowanie ddl dyscyplin if (timedOut) { ao.EnsureLogin(); } } while (timedOut); bool IsSearchInProgress() { bool?searchInProgress = null; sdm.TryUntilElementAttachedToPage(() => searchInProgress = sdm.FindElementsByXPath(xpathDivSearchInfo).SingleOrDefault()?.Text .ContainsAny("searching for") == true, true); return(searchInProgress.ToBool()); } bool areNoResultsFound() { bool?noResultsFound = null; sdm.TryUntilElementAttachedToPage(() => noResultsFound = sdm.FindElementsByXPath(xpathDivSearchInfo).SingleOrDefault()?.Text .ContainsAny("too many", "no result") == true, true); return(noResultsFound.ToBool()); } IWebElement[] divLeagues = null; bool areLeaguesFound() { divLeagues = null; sdm.TryUntilElementAttachedToPage(() => divLeagues = sdm.FindElementsByXPath(".//div[@id='gamecontainer']//div[@class='ileaugegroup']") .Where(div => !div.FindElement(By.ClassName("leauge")).GetAttribute("value") .ContainsAny("NO. OF", "FANTASY MATCH", "- TO KICK OF", "SCORED")).ToArray(), true); return(divLeagues?.Any() == true); } foreach (var discipline in disciplinesToSearch) { var strDisciplineLocalized = DisciplineConverter.DisciplineTypeToLocalizedString(discipline); OnInformationSending($"Przeszukiwanie dyscypliny: {strDisciplineLocalized}..."); var strD = discipline.EnumToString(); var optionDiscipline = optionDisciplines.Single(o => o.Text.EqIgnoreCase(strD)); ddlDisciplineType.Click(); optionDiscipline.Click(); foreach (var searchTerm in searchTerms) { OnInformationSending($"Przeszukiwanie dyscypliny: {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\"..."); var divTimePeriods = (discipline == DisciplineType.Basketball ? sdm.FindElementsByXPath("//div[@id='lbl_running_basketball' or @id='lbl_today_basketball' or @id='lbl_early_basketball']") : sdm.FindElementsByXPath("//div[@id='lbl_running' or @id='lbl_today' or @id='lbl_early']")).ToArray(); if (divTimePeriods.Length != 3) { throw new AsianoddsException("Pobrano niepoprawne menu przedziałów czasowych"); } foreach (var divTimePeriod in divTimePeriods) { var divTimePeriodId = divTimePeriod.GetId(); var localizedTimePeriod = divTimePeriodId.ContainsAny("running") ? "na żywo" : divTimePeriodId.ContainsAny("today") ? "dziś" : divTimePeriodId.ContainsAny("early") ? "późniejsze wydarzenia" : "nieznany przedział czasowy"; OnInformationSending($"Przeszukiwanie dyscypliny: {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\", przedział czasowy: \"{localizedTimePeriod}\"..."); sdm.HideElement(By.XPath("//*[@id='footer']")); divTimePeriod.Click(); txtSearchMatch.Clear(); txtSearchMatch.SendKeys(searchTerm); OnInformationSending($"Oczekiwanie na rozpoczęcie wyszukiwania: {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\", przedział czasowy: \"{localizedTimePeriod}\"..."); sdm.Wait.Until(d => IsSearchInProgress()); OnInformationSending($"Oczekiwanie na wyniki: {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\", przedział czasowy: \"{localizedTimePeriod}\"..."); sdm.Wait.Until(d => areNoResultsFound() || areLeaguesFound()); var areResultsFound = divLeagues?.Any() == true; if (areResultsFound) { OnInformationSending($"Znaleziono wyniki (ligi: {divLeagues.Length}): {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\", przedział czasowy: \"{localizedTimePeriod}\""); foreach (var divLeague in divLeagues) { var tblGameRows = divLeague.FindElements(By.CssSelector("table.game_panel_tmp.igametable")).ToArray(); foreach (var tblGameRow in tblGameRows) { try { string league = null; sdm.TryUntilElementAttachedToPage(() => league = tblGameRow.FindElement(By.XPath(".//td[1]/input[@class='leauge']")).GetAttribute("value").AfterLast("*").Trim()); string strTime = null; sdm.TryUntilElementAttachedToPage(() => strTime = tblGameRow.FindElement(By.XPath(".//td[1]/input[@class='hidKickofTime']")).GetAttribute("value").Trim()); IWebElement tdTeamNames = null; sdm.TryUntilElementAttachedToPage(() => tdTeamNames = tblGameRow.FindElement(By.XPath(".//td[2]"))); var time = strTime.ToExtendedTime("MM/dd/yyyy hh:mm:ss.fff tt", tz); // 04/28/2018 06:30:00.000 PM string homeName = null; sdm.TryUntilElementAttachedToPage(() => homeName = tdTeamNames.FindElement(By.XPath(".//span[contains(@class, 'Home') and contains(@class, 'samehidegroup1')]")).GetAttribute("innerText").Trim()); string awayName = null; sdm.TryUntilElementAttachedToPage(() => awayName = tdTeamNames.FindElement(By.XPath(".//span[contains(@class, 'Away') and contains(@class, 'samehidegroup1')]")).GetAttribute("innerText").Trim()); bool correctWordCondition(string w) => !w.ContainsAny("(", ")"); var homeSameWords = homeName.SameWords(betRequest.MatchHomeName, 3, correctWordCondition); var awaySameWords = awayName.SameWords(betRequest.MatchHomeName, 3, correctWordCondition); var timeDifference = (time - betRequest.Date).Abs(); IWebElement[] spanBetItems = null; sdm.TryUntilElementAttachedToPage(() => spanBetItems = tblGameRow.FindElements(By.XPath(".//span[contains(@class, 'BetItem')]")) .Where(bi => !string.IsNullOrWhiteSpace(bi.Text)).ToArray()); foreach (var spanBetItem in spanBetItems) { OnInformationSending($"Budowa ścieżki dla elementu nr {++resultsNum}: {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\", przedział czasowy: \"{localizedTimePeriod}\"..."); var candidateBetReq = new BetRequest { Discipline = discipline, Date = time, MatchHomeName = homeName.Split(" ").Select(w => w.Length > 0 ? w.Take(1).ToUpper() + w.Skip(1).ToLower() : w).JoinAsString(" "), MatchAwayName = awayName.Split(" ").Select(w => w.Length > 0 ? w.Take(1).ToUpper() + w.Skip(1).ToLower() : w).JoinAsString(" "), LeagueName = league, MatchId = betRequest.MatchId, Keyword = searchTerm, HomeCommonWords = homeSameWords.Length, AwayCommonWords = awaySameWords.Length, TimeDifference = timeDifference, XPath = spanBetItem.XPath(), TimePeriodXPath = $"//div[@id='{divTimePeriodId}']" }; OnInformationSending($"Aktualizacja elementu nr {++resultsNum}: {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\", przedział czasowy: \"{localizedTimePeriod}\"..."); var spanBetItemClasses = spanBetItem.GetClasses(); if (spanBetItemClasses.Contains("FTHomeOdd")) { candidateBetReq.PickChoice = PickChoice.Home; candidateBetReq.PickValue = null; } else if (spanBetItemClasses.Contains("FTAwayOdd")) { candidateBetReq.PickChoice = PickChoice.Away; candidateBetReq.PickValue = null; } else if (spanBetItemClasses.Contains("FTDrawOdd")) { candidateBetReq.PickChoice = PickChoice.Draw; candidateBetReq.PickValue = null; } else if (spanBetItemClasses.ContainsAny("FTHDPHomeOdd", "FTHDPAwayOdd")) { double?handicapHome = null; sdm.TryUntilElementAttachedToPage(() => { var strFTHDPHome = tblGameRow.FindElement(By.XPath(".//span[contains(@class, 'FTHDPHome') and not(contains(@class, 'BetItem'))]")).Text.Trim(); if (!string.IsNullOrEmpty(strFTHDPHome)) { handicapHome = StrSplitToDouble(strFTHDPHome.Split("-")); } }); double?handicapAway = null; sdm.TryUntilElementAttachedToPage(() => { var strFTHDPAway = tblGameRow.FindElement(By.XPath(".//span[contains(@class, 'FTHDPAway') and not(contains(@class, 'BetItem'))]")).Text.Trim(); if (!string.IsNullOrEmpty(strFTHDPAway)) { handicapAway = StrSplitToDouble(strFTHDPAway.Split("-")); } }); if (handicapHome == null && handicapAway == null) { throw new AsianoddsException("Nie można pobrac wartości handicapu dla zakładu"); } if (spanBetItemClasses.ContainsAny("FTHDPHomeOdd")) { if (handicapHome != null) { candidateBetReq.PickChoice = PickChoice.HomeAsianHandicapSubtract; candidateBetReq.PickValue = handicapHome; // - } else { candidateBetReq.PickChoice = PickChoice.HomeAsianHandicapAdd; candidateBetReq.PickValue = handicapAway; } } else if (spanBetItemClasses.ContainsAny("FTHDPAwayOdd")) { if (handicapAway != null) { candidateBetReq.PickChoice = PickChoice.AwayAsianHandicapSubtract; candidateBetReq.PickValue = handicapAway; // - } else { candidateBetReq.PickChoice = PickChoice.AwayAsianHandicapAdd; candidateBetReq.PickValue = handicapHome; } } } else if (spanBetItemClasses.ContainsAny("FTOver", "FTUnder")) { string[] goalsThresholdSplit = null; sdm.TryUntilElementAttachedToPage(() => goalsThresholdSplit = tblGameRow.FindElement(By.XPath(".//span[contains(@class, 'FTGoal') and not(contains(@class, 'BetItem'))]")).Text.Trim() .Split("-")); var goals = StrSplitToDouble(goalsThresholdSplit); candidateBetReq.PickChoice = spanBetItemClasses.ContainsAny("FTOver") ? PickChoice.Over : PickChoice.Under; candidateBetReq.PickValue = goals.Round(2); } else { continue; } candidateBets.Add(candidateBetReq); OnInformationSending($"Zaaktualizowano element nr {++resultsNum}: {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\", przedział czasowy: \"{localizedTimePeriod}\"..."); } } catch (StaleElementReferenceException) { OnInformationSending($"Błąd elementu nr {++resultsNum} (element przestał być aktualny): {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\", przedział czasowy: \"{localizedTimePeriod}\""); // wiersz został usunięty, bo zakład jest np nieaktualny, dotyczy zwłaszcza LIVE } } } break; } OnInformationSending($"Brak wyników: {strDisciplineLocalized}, słowo kluczowe: \"{searchTerm}\", przedział czasowy: \"{localizedTimePeriod}\""); } } } if (!candidateBets.Any()) { throw new AsianoddsException("Brak zakładów dla wybranego meczu"); } var candidateBetsDistinct = candidateBets.Distinct().OrderBy(b => b.MatchHomeName) .ThenBy(b => b.PickChoice.EnumToString()).ThenBy(b => b.PickValue).ToList(); OnInformationSending($"Filtrowanie potencjalnych zakładów {candidateBetsDistinct.Count}..."); var candidateBetsWithLowestTimeDifference = candidateBetsDistinct.Where(b => b.TimeDifference < TimeSpan.FromDays(2)).ToList(); var candidateBetsWithSamePick = candidateBetsWithLowestTimeDifference .Where(b => b.PickChoice == betRequest.PickChoice && b.PickValue.Eq(betRequest.PickValue)).ToList(); if (!candidateBetsWithSamePick.Any() && betRequest.PickValue.Eq(0)) { if (betRequest.PickChoice == PickChoice.HomeAsianHandicapAdd) { betRequest.PickChoice = PickChoice.HomeAsianHandicapSubtract; } else if (betRequest.PickChoice == PickChoice.AwayAsianHandicapAdd) { betRequest.PickChoice = PickChoice.AwayAsianHandicapSubtract; } } candidateBetsWithSamePick = candidateBetsWithLowestTimeDifference .Where(b => b.PickChoice == betRequest.PickChoice && b.PickValue.Eq(betRequest.PickValue)).ToList(); var finalBet = candidateBetsWithSamePick .Where(b => b.HomeCommonWords + b.AwayCommonWords >= 1) .MaxBy(b => b.HomeCommonWords + b.AwayCommonWords); OnInformationSending("Znaleziono zakład"); var stake = (betRequest.Stake / 1).Round(); // TODO: użyć API do konwersji walut OnInformationSending("Zawieranie zakładu..."); var divFinalTimePeriod = sdm.FindElementByXPath(finalBet.TimePeriodXPath); divFinalTimePeriod.Click(); txtSearchMatch.Clear(); txtSearchMatch.SendKeys(finalBet.Keyword); sdm.Wait.Until(d => IsSearchInProgress()); sdm.Wait.Until(d => areNoResultsFound() || areLeaguesFound()); var spanBet = sdm.FindElementByXPath(finalBet.XPath); spanBet.Click(); var txtStake = sdm.FindElementByXPath("//*[@id='betdlg_USR_AMOUNT']"); var btnPlaceBet = sdm.FindElementByXPath("//*[@id='btnDlgPlaceBetSubmit']"); txtStake.SendKeys($"{stake:0}"); sdm.Wait.Until(d => btnPlaceBet.Enabled); btnPlaceBet.Click(); var btnConfirmBet = sdm.FindElementByXPath("//*[@id='dlgPlaceBet']/div/div[6]/button[2]"); // //*[@id='dlgPlaceBet']//button[contains(@class, 'btnYes')] sdm.Wait.Until(d => btnConfirmBet.Displayed && btnConfirmBet.Enabled); btnConfirmBet.Click(); OnInformationSending("Wczytywanie informacji o zakładzie..."); var liMenuOutstandingBets = sdm.FindElementByXPath("//*[@id='liMemuOutsandingBets']"); try { liMenuOutstandingBets.Click(); } catch (InvalidOperationException ex) { if (ex.Message.ContainsAny("Other element would receive the click")) { throw new AsianoddsException("Próba kliknięcia przycisku 'Place Bet' nie udała się, serwer zwrócił błąd"); } throw; } var tableOutstandingBets = sdm.FindElementByXPath("//*[@id='OutstandingBetsContanier']//table[@class='tableOutsanding']"); var trOutstandingBets = tableOutstandingBets.FindElements(By.XPath(".//tbody/tr[@class='trItem']")).Where(tr => tr.Displayed).ToArray(); IWebElement getTrPlacedBet() => trOutstandingBets.SingleOrDefault(tr => tr .FindElement(By.ClassName("span_homeName_awayName")).Text.AfterLast("]") .Trim().EqIgnoreCase($"{finalBet.MatchHomeName} -vs- {finalBet.MatchAwayName}")); IWebElement trPlacedBet = null; sdm.Wait.Until(d => (trPlacedBet = getTrPlacedBet()) != null); var oddsResp = trPlacedBet.FindElement(By.ClassName("span_odds")).Text.Trim().ToDouble(); var stakeResp = trPlacedBet.FindElement(By.ClassName("spanStake_Currency")).Text.BeforeFirst("EUR").Trim().ToDouble(); Date = finalBet.Date; Discipline = finalBet.Discipline; LeagueName = finalBet.LeagueName; MatchHomeName = finalBet.MatchHomeName; MatchAwayName = finalBet.MatchAwayName; PickChoice = (PickChoice)finalBet.PickChoice; PickValue = finalBet.PickValue; BetResult = BetResult.Pending; Stake = stakeResp; Odds = oddsResp; MatchId = finalBet.MatchId; OnInformationSending("Zakład został poprawnie zawarty..."); return(this); }
public BetsResponse Parse(AsianoddsSeleniumDriverManager sdm, ExtendedTime fromDate, TimeZoneKind timeZone) { HandleErrors(sdm); OnInformationSending("Wczytywanie informacji o zakładach..."); sdm.HideElement(By.Id("footer")); var ddlDisciplineType = sdm.FindElementByXPath("//*[@id='selAdvSearchSportType']"); var optionSelectedDiscipline = ddlDisciplineType.FindElements(By.TagName("option")).Single(o => o.Selected); var discipline = optionSelectedDiscipline.Text.ToEnum <DisciplineType>(); var liMenuHistory = sdm.FindElementByXPath("//*[@id='liMenuHistory']"); liMenuHistory.Click(); var txtDateFrom = sdm.FindElementByXPath("//*[@id='txtPlacementDateFrom']"); txtDateFrom.Click(); var divCalendar = sdm.FindElementByXPath("//*[@id='ui-datepicker-div']"); IWebElement aDpPrevBtn() => divCalendar.FindElements(By.TagName("a")).Single(a => a.HasClass("ui-datepicker-prev")); while (!aDpPrevBtn().HasClass("ui-state-disabled")) { aDpPrevBtn().Click(); } var tdDays = divCalendar.FindElements(By.XPath(".//td[@data-handler='selectDay']")); var tdFirstDay = tdDays.MinBy(td => td.FindElement(By.TagName("a")).Text.ToInt()); tdFirstDay.Click(); var btnSearchHistory = sdm.FindElementByXPath("//*[@id='btnSearchHistorySearchPanel']"); btnSearchHistory.TryClickUntilNotCovered(); const string df = "M/d/yyyy"; var newBets = new List <BetResponse>(); IWebElement divHistoricalBets() => sdm.FindElementById("HistoryPageBetsContanier"); IEnumerable <IWebElement> spanDates() => divHistoricalBets().FindElements(By.ClassName("spanDateDay")) .Where(span => span.Text?.Length > 0); sdm.Wait.Until(d => spanDates().Any()); var dates = spanDates().Select(span => span.Text.ToDateTimeExact(df)).Where(d => d.ToExtendedTime() >= fromDate).ToArray(); var unusedDates = dates.ToList(); while (unusedDates.Any()) { OnInformationSending($"Ładowanie zakładów, dzień {dates.Length - unusedDates.Count + 1} z {dates.Length}..."); var currDate = unusedDates.Min(); var spanCurrDate = spanDates().Single(span => span.Text.ToDateTimeExact(df) == currDate); var trCurrStatementItem = spanCurrDate.FindElement(By.XPath(".//ancestor::tr[@class='trStatementItem']")); trCurrStatementItem.Click(); var divDayHistoricalBets = sdm.FindElementById("HistoryPageBetsContanier"); var trBets = divDayHistoricalBets.FindElements(By.ClassName("trSummaryItem")).Where(tr => tr.Displayed).ToArray(); foreach (var trBet in trBets) { var bet = new BetResponse(); var spanTeams = trBet.FindElement(By.ClassName("span_homeName_awayName")); var homeAway = spanTeams.Text.AfterFirst("]").Trim().Split(" -VS- "); var home = homeAway[0].BeforeFirst(" - "); var away = homeAway[1].BeforeFirst(" - "); var spanDate = trBet.FindElement(By.ClassName("spanDate")); var strTime = spanDate.Text.Trim(); var spanLeague = trBet.FindElement(By.ClassName("span_leagueName")); var strLeague = spanLeague.Text.Trim().AfterFirst("*").Split(" ") .Select(w => w.Length > 0 ? w.Take(1).ToUpper() + w.Skip(1).ToLower() : w).JoinAsString(" "); var spanPick = trBet.FindElement(By.ClassName("span_homeaway_hdporgoal")); var strPick = spanPick.Text.Trim(); var spanOdds = trBet.FindElement(By.ClassName("span_odds")); var strOdds = spanOdds.Text.Trim(); var spanStatus = trBet.FindElement(By.ClassName("spanStatus")); var strStatus = spanStatus.Text.Trim(); var spanStake = trBet.FindElement(By.ClassName("spanStake")); var strStake = spanStake.Text.Trim(); var spanScores = trBet.FindElement(By.ClassName("spanScores")); var strMatchResult = spanScores.Text.AfterFirst("FT").Trim(); bet.Date = strTime.ToExtendedTime("MM/dd/yyyy h:mm tt", timeZone); bet.Discipline = discipline; bet.LeagueName = strLeague; bet.MatchHomeName = home; bet.MatchAwayName = away; bet.PickChoice = ParsePickChoice(strPick, home, away); bet.PickValue = strPick.ContainsAll("[", "]") ? strPick.Between("[", "]").ToDoubleN()?.Abs() : null; bet.Odds = strOdds.ToDouble(); bet.BetResult = ParseBetResult(strStatus); bet.Stake = strStake.ToDouble(); bet.HomeScore = strMatchResult.BeforeFirst(":").Trim().ToIntN(); bet.AwayScore = strMatchResult.AfterFirst(":").Trim().ToIntN(); newBets.Add(bet); } var btnBackToStatements = sdm.FindElementByClassName("BackToStatements"); btnBackToStatements.Click(); unusedDates.Remove(currDate); } OnInformationSending("Zakłady zostały pobrane z AsianOdds..."); Bets = newBets; return(this); }
public BetsResponse Parse(HintwiseSeleniumDriverManager sdm, TipsterResponse tipster, ExtendedTime fromDateClientLocal, TimeZoneKind serverTimezone) { HandleErrors(sdm); OnInformationSending("Zbieranie dodatkowych informacji..."); const string matchSep = " vs "; var originalAddress = sdm.Url; var fromDate = fromDateClientLocal?.ToTimezone(serverTimezone); // konwertuj na strefę czasową serwera var newBets = new List <BetResponse>(); IWebElement getDivCurrentPredictions() => sdm.FindElementByXPath(".//div[@id='predictions-grid']"); var divCurrentPredictions = getDivCurrentPredictions(); var currPredLastPageQueries = sdm.PagerLastPageQueries(divCurrentPredictions); var currPredPagesCount = sdm.PagerLastPage(currPredLastPageQueries); IWebElement getDivHistoricalPredictions() => sdm.FindElementByXPath(".//div[@id='history-predictions']"); var divHistoricalPredictions = getDivHistoricalPredictions(); var histPredLastPageQueries = sdm.PagerLastPageQueries(divHistoricalPredictions); var histPredPagesCount = sdm.PagerLastPage(histPredLastPageQueries); var previousDate = ExtendedTime.UtcNow.ToTimezone(serverTimezone); // w strefie czassowej serwera var year = previousDate.Rfc1123.Year; OnInformationSending("Wczytywanie informacji o zakładach..."); // Obecne Zakłady for (var currPage = 1; currPage <= currPredPagesCount; currPage++) { OnInformationSending($"Wczytywanie nowych zakładów (strona {currPage} z {currPredPagesCount})..."); if (divCurrentPredictions.FindElement(By.TagName("span")).Text.ToLower().Contains("no results found")) { break; } sdm.PagerNavigateToCurrentPage(currPage, currPredLastPageQueries, originalAddress); divCurrentPredictions = getDivCurrentPredictions(); var trCurrPredRows = divCurrentPredictions.FindElements(By.XPath(".//table[@class='items']/tbody/tr")); foreach (var trCurrPredRow in trCurrPredRows) { var tdCurrPredRowCells = trCurrPredRow.FindElements(By.TagName("td")); sdm.DisableWaitingForElements(); var isFree = tdCurrPredRowCells[3].FindElements(By.XPath("input[@type='button']")).Count == 0; sdm.EnableWaitingForElements(); var extDate = ParseDate(tdCurrPredRowCells[0].Text, previousDate, serverTimezone, ref year); var discipline = DisciplineConverter.ToDisciplineType(tdCurrPredRowCells[1].Text.Trim()); var matchStr = tdCurrPredRowCells[2].FindElement(By.TagName("a")).Text.RemoveHTMLSymbols().Trim(); var pickStr = isFree ? tdCurrPredRowCells[3].Text.BeforeFirst("(").RemoveHTMLSymbols().Trim() : "Ukryty"; var newBet = new BetResponse { Date = extDate, // czas pobierany ma być zawsze w UTC HomeName = matchStr.BeforeFirst(matchSep), AwayName = matchStr.AfterFirst(matchSep), Pick = PickConverter.ParseToPickResponse(pickStr, matchStr), MatchResult = MatchResult.Inconclusive(), BetResult = BetResult.Pending, Odds = 0, Discipline = discipline }; newBets.Add(newBet); } } // Historyczne wyniki for (var currPage = 1; currPage <= histPredPagesCount; currPage++) // { OnInformationSending($"Wczytywanie historycznych zakładów (strona {currPage} z {histPredPagesCount})..."); if (divHistoricalPredictions.FindElement(By.TagName("span")).Text.ToLower().Contains("no results found")) { break; } sdm.PagerNavigateToCurrentPage(currPage, histPredLastPageQueries, originalAddress); divHistoricalPredictions = getDivHistoricalPredictions(); var trHistPredRows = divHistoricalPredictions.FindElements(By.XPath(".//table[@class='items']/tbody/tr")); foreach (var trHistPredRow in trHistPredRows) { var tdHistPredRowCells = trHistPredRow.FindElements(By.TagName("td")); var extDate = ParseDate(tdHistPredRowCells[0].Text, previousDate, serverTimezone, ref year); var discipline = DisciplineConverter.ToDisciplineType(tdHistPredRowCells[1].Text.Trim()); var matchStr = tdHistPredRowCells[2].FindElement(By.TagName("a")).Text.RemoveHTMLSymbols().Trim(); var pickStr = tdHistPredRowCells[3].Text.BeforeFirst("(").RemoveHTMLSymbols().Trim(); var rawMatchResultStr = tdHistPredRowCells[4].Text.RemoveHTMLSymbols().Trim(); var betResult = tdHistPredRowCells[5].Text.BeforeFirst("(").RemoveHTMLSymbols().Trim().ToLower() == "win" ? BetResult.Won : BetResult.Lost; var odds = tdHistPredRowCells[3].Text.Between("(", ")").RemoveHTMLSymbols().Trim().ToDouble(); var newBet = new BetResponse { Date = extDate, HomeName = matchStr.BeforeFirst(matchSep), AwayName = matchStr.AfterFirst(matchSep), Pick = PickConverter.ParseToPickResponse(pickStr, matchStr), MatchResult = MatchConverter.ToMatchResultResponse(rawMatchResultStr), BetResult = betResult, Odds = odds, Discipline = discipline }; previousDate = extDate; newBets.Add(newBet); if (fromDate != null && extDate < fromDate) { break; } } if (fromDate != null && newBets.Last().Date < fromDate) { newBets.Remove(newBets.Last()); break; } } OnInformationSending("Wczytano zakłady"); Tipster = tipster; Bets = newBets; return(this); }
private static ExtendedTime ParseDate(string strDate, ExtendedTime previousDate, TimeZoneKind serverTimezone, ref int year) { var date = DateTime.ParseExact($"{strDate.RemoveHTMLSymbols().Trim()} 2000", "d. MMM HH:mm yyyy", new CultureInfo("en-GB")); var extDate = new DateTime(date.Month > previousDate.Rfc1123.Month ? --year : year, date.Month, date.Day, date.Hour, date.Minute, date.Second) .ToExtendedTime(serverTimezone) .ToUTC(); return(extDate); }
/// <summary> /// Constructs a TimeZoneTag. /// </summary> /// <param name="offset">Offset from UTC.</param> /// <param name="kind">The <see cref="TimeZoneKind"/>.</param> /// <remarks>If <paramref name="kind"/> is <see cref="TimeZoneKind.ForceUtc"/> /// or <see cref="TimeZoneKind.ForceLocal"/> then <paramref name="offsetMinutes"/> /// must be zero. Other values will throw an exception.</remarks> /// <remarks>If <paramref name="kind"/> is other than <see cref="TimeZoneKind.Normal"/> /// then <paramref name="offset"/> is forced to zero. /// </remarks> public TimeZoneTag(TimeSpan offset, TimeZoneKind kind = TimeZoneKind.Normal) { m_offset = (kind == TimeZoneKind.Normal) ? (int)(offset.Ticks / c_ticksPerMinute) : 0; Kind = kind; }
/// <summary> /// Constructs a TimeZoneTag. /// </summary> /// <param name="offsetTicks">Offset from UTC in ticks.</param> /// <param name="kind">The <see cref="TimeZoneKind"/>.</param> /// <remarks>If <paramref name="kind"/> is other than <see cref="TimeZoneKind.Normal"/> /// then <paramref name="offsetTicks"/> is forced to zero. /// </remarks> public TimeZoneTag(long offsetTicks, TimeZoneKind kind = TimeZoneKind.Normal) { m_offset = (kind == TimeZoneKind.Normal) ? (int)(offsetTicks / c_ticksPerMinute) : 0; Kind = kind; }
/// <summary> /// Constructs a TimeZoneTag. /// </summary> /// <param name="offsetMinutes">Offset from UTC in minutes.</param> /// <param name="kind">The <see cref="TimeZoneKind"/>.</param> /// <remarks>If <paramref name="kind"/> is other than <see cref="TimeZoneKind.Normal"/> /// then <paramref name="offsetMinutes"/> is forced to zero. /// </remarks> public TimeZoneTag(int offsetMinutes, TimeZoneKind kind = TimeZoneKind.Normal) { m_offset = (kind == TimeZoneKind.Normal) ? offsetMinutes : 0; Kind = kind; }
protected AgilityClient(string address, TimeZoneKind timeZone) : base(address, timeZone) { _arm = new AgilityRestManager(); }