Compare commits

...

38 Commits

Author SHA1 Message Date
73a177d45c Add test project :/ 2024-02-15 22:42:10 +00:00
7dd570c4a0 Update NuGet packages. 2024-02-15 22:39:03 +00:00
27270a2000 Forgot one... 2024-02-15 22:34:54 +00:00
31b48d795a Added exception handling. 2024-02-15 22:32:57 +00:00
fc86c91b01 Euromillions was looking at lotto table rather than euro one. 2024-02-15 19:23:27 +00:00
e2ec108b0d Restructure LotteryTableRow 2024-02-13 14:27:29 +00:00
03aab077d6 Add itemgroups. 2024-02-13 14:22:12 +00:00
298cfa53d9 Data model for game information 2024-02-13 14:20:38 +00:00
2e296f6d96 Generate the regular expression implementation at compile-time. 2024-02-13 14:12:10 +00:00
ae3e70313c Reoved potential null 2024-02-13 14:09:52 +00:00
6f396c2090 Added Try/Catch and additional error handling. 2024-02-13 14:01:43 +00:00
5537b9abc4 Revert "Declaring the logger as nullable."
This reverts commit afa83fbbb9.
2024-02-13 13:47:11 +00:00
afa83fbbb9 Declaring the logger as nullable. 2024-02-13 13:45:19 +00:00
79575df472 Updated context to include euromillions. 2024-02-13 13:23:34 +00:00
517658bf74 Added commit method for Euromillions 2024-02-13 13:22:44 +00:00
c257d7ff8c Euromillions data model 2024-02-13 13:22:17 +00:00
34918e6c38 Euromillions Millionaire code model. 2024-02-13 13:21:56 +00:00
d3e651ef89 Core custom NullResultException 2024-02-13 13:21:33 +00:00
62ff7a04de Added some try/catch and exception blocks 2024-02-13 13:20:50 +00:00
465b8e05e7 Minor clean up of blank lines. 2024-02-13 13:20:26 +00:00
d6fc1bf314 Added Try/catch and error handling to Lotto Draw Machine more to be done. 2024-02-13 13:20:05 +00:00
0c8706788a Added Try/catch to Lotto Draw Balls. More to be done... 2024-02-13 13:19:01 +00:00
b61980a30d Add Initial Logic for EuroMillions Processing. 2024-02-13 13:18:32 +00:00
388b1ec23f Add Logic for EuroMillions Draw Information. 2024-02-13 13:18:14 +00:00
ea987c52a4 Add Logic for EuroMillions Draw Status. 2024-02-13 13:17:59 +00:00
7f658be963 Add Logic for EuroMillions DrawNumber 2024-02-13 13:17:49 +00:00
e265958434 Add Logic for EuroMillions Draw Machine. 2024-02-13 13:17:33 +00:00
0ab60324fd Add Logic for EuroMillions Draw Date. 2024-02-13 13:17:18 +00:00
c68c2cf8db Add Initial Logic for EuroMillions Draw Code. 2024-02-13 13:17:00 +00:00
4017e1eeb1 Add Logic for EuroMillions Draw Balls. 2024-02-13 13:16:41 +00:00
df616fd42c Small refactor for readability. 2024-02-10 22:36:20 +00:00
Ross Healy
3fd0218db3 Remove comment, can't be made private or internal until I restructure. 2024-02-10 21:29:06 +00:00
Ross Healy
ad24dacac6 Now going to be disposed of in program.cs 2024-02-10 21:27:04 +00:00
Ross Healy
113a4bb19d Removed duplicacte processing of rollover. 2024-02-10 18:41:01 +00:00
Ross Healy
21923291b4 removed unused using. 2024-02-08 02:45:59 +00:00
Ross Healy
fdbe498237 Foreach statement implicitly converts object to system.text.RegularExpression.matchadding an explicit cast to make the intent cleaner as it may fail at runtime. 2024-02-08 02:42:54 +00:00
Ross Healy
ed42745ff4 New & collection expression can be simplified. 2024-02-08 02:40:17 +00:00
Ross Healy
ea3f91e28d Use generated Regex attribute to generate the expression implementation at compile time. 2024-02-08 02:39:07 +00:00
27 changed files with 2019 additions and 280 deletions

View File

@@ -0,0 +1,7 @@
namespace lottery_co_uk_scraper.core.Exceptions
{
public class NullResultException(string message) : Exception(message)
{
}
}

View File

@@ -0,0 +1,14 @@
using Microsoft.EntityFrameworkCore;
namespace lottery_co_uk_scraper.core.Models.EuroMillions
{
[Index(nameof(DrawNumber), nameof(RaffleCode), IsUnique = true)]
public class EurosRaffleResult
{
public int Id { get; set; }
public int DrawNumber { get; set; }
public string RaffleCode { get; set; }
}
}

View File

@@ -0,0 +1,147 @@
using lottery_co_uk_scraper.core.Models.EuroMillions;
using Microsoft.EntityFrameworkCore;
namespace lottery_co_uk_scraper.core.Models
{
[Index(nameof(DrawNumber), IsUnique = true)]
public class EurosResult
{
public int Id { get; set; }
public DateOnly DrawDate { get; set; }
public int DrawNumber { get; set; }
public bool Rollover { get; set; }
public EurosRaffleResult MillionaireMakerCode { get; set; }
public int BallSetUsed { get; set; }
public int MachineUsed { get; set; }
public int DrawnBall1 { get; set; }
public int DrawnBall2 { get; set; }
public int DrawnBall3 { get; set; }
public int DrawnBall4 { get; set; }
public int DrawnBall5 { get; set; }
public int LuckyStar1 { get; set; }
public int LuckyStar2 { get; set; }
public int TotalMatched2 { get; set; }
public int TotalMatched2UK { get; set; }
public int Matched2PrizeUK { get; set; }
public int Matched2PrizeFundUK { get; set; }
public int TotalMatched2Plus1Star { get; set; }
public int TotalMatched2Plus1StarUK { get; set; }
public int Matched2Plus1StarPrizeUK { get; set; }
public int Matched2Plus1StarPrizeFundUK { get; set; }
public int TotalMatched1Plus2Stars { get; set; }
public int TotalMatched1Plus2StarsUK { get; set; }
public int Matched1Plus2StarsPrizeUK { get; set; }
public int Matched1Plus2StarsPrizeFundUK { get; set; }
public int TotalMatched2Plus2Stars { get; set; }
public int TotalMatched2Plus2StarsUK { get; set; }
public int Matched2Plus2StarsPrizeUK { get; set; }
public int Matched2Plus2StarsPrizeFundUK { get; set; }
public int TotalMatched3 { get; set; }
public int TotalMatched3UK { get; set; }
public int Matched3PrizeUK { get; set; }
public int Matched3PrizeFundUK { get; set; }
public int TotalMatched3Plus1Star { get; set; }
public int TotalMatched3Plus1StarUK { get; set; }
public int Matched3Plus1StarPrizeUK { get; set; }
public int Matched3Plus1StarPrizeFundUK { get; set; }
public int TotalMatched3Plus2Stars { get; set; }
public int TotalMatched3Plus2StarsUK { get; set; }
public int Matched3Plus2StarsPrizeUK { get; set; }
public int Matched3Plus2StarsPrizeFundUK { get; set; }
public int TotalMatched4 { get; set; }
public int TotalMatched4UK { get; set; }
public int Matched4PrizeUK { get; set; }
public int Matched4PrizeFundUK { get; set; }
public int TotalMatched4Plus1Star { get; set; }
public int TotalMatched4Plus1StarUK { get; set; }
public int Matched4Plus1StarPrizeUK { get; set; }
public int Matched4Plus1StarPrizeFundUK { get; set; }
public int TotalMatched4Plus2Stars { get; set; }
public int TotalMatched4Plus2StarsUK { get; set; }
public int Matched4Plus2StarsPrizeUK { get; set; }
public int Matched4Plus2StarsPrizeFundUK { get; set; }
public int TotalMatched5 { get; set; }
public int TotalMatched5UK { get; set; }
public int Matched5PrizeUK { get; set; }
public int Matched5PrizeFundUK { get; set; }
public int TotalMatched5Plus1Star { get; set; }
public int TotalMatched5Plus1StarUK { get; set; }
public int Matched5Plus1StarPrizeUK { get; set; }
public int Matched5Plus1StarPrizeFundUK { get; set; }
public int TotalMatched5Plus2Stars { get; set; }
public int TotalMatched5Plus2StarsUK { get; set; }
public int Matched5Plus2StarsPrizeUK { get; set; }
public int Matched5Plus2StarsPrizeFundUK { get; set; }
public int TotalWinners { get; set; }
public int TotalWinnersUK { get; set; }
public int TotalPrizeFundUK { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
namespace lottery_co_uk_scraper.core.Models
{
internal class GameInformation
{
public int Id { get; set; }
public string GameName { get; set; }
public DayOfWeek DrawDay { get; set; }
public TimeOnly DrawClosing { get; set; }
public TimeOnly DrawOpening { get; set; }
public TimeOnly DrawTime { get; set; }
}
}

View File

@@ -8,7 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.2" />
</ItemGroup>
</Project>

View File

@@ -1,5 +1,5 @@
using lottery_co_uk_scraper.core.Models;
using Microsoft.EntityFrameworkCore;
using lottery_co_uk_scraper.core.Models.EuroMillions;
namespace lottery_co_uk_scraper.data
{
@@ -13,5 +13,23 @@ namespace lottery_co_uk_scraper.data
dbContext.LottoResults.Add(lottoResults);
dbContext.SaveChanges();
}
public static void SaveModelToDatabase(EurosResult eurosResults)
{
using var dbContext = new LotteryContext();
dbContext.Database.EnsureCreated();
dbContext.EurosResults.Add(eurosResults);
dbContext.SaveChanges();
}
public static void SaveModelToDatabase(EurosRaffleResult eurosRaffleResults)
{
using var dbContext = new LotteryContext();
dbContext.Database.EnsureCreated();
dbContext.EurosRaffleResults.Add(eurosRaffleResults);
dbContext.SaveChanges();
}
}
}

View File

@@ -1,10 +1,15 @@
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.core.Models.EuroMillions;
using Microsoft.EntityFrameworkCore;
namespace lottery_co_uk_scraper.data
{
public class LotteryContext : DbContext
{
public DbSet<EurosResult> EurosResults { get; set; }
public DbSet<EurosRaffleResult> EurosRaffleResults { get; set; }
public DbSet<LottoResult> LottoResults { get; set; }
public LotteryContext()

View File

@@ -8,9 +8,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.1">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@@ -5,9 +5,11 @@ VisualStudioVersion = 17.9.34321.82
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "lottery-co-uk-scraper", "lottery-co-uk-scraper\lottery-co-uk-scraper.csproj", "{D6F6C01A-F51A-4ED7-AC9F-67C7BF9AAB79}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lottery-co-uk-scraper.data", "lottery-co-uk-scraper.data\lottery-co-uk-scraper.data.csproj", "{57463DA3-7350-4A10-853C-6C766F96A039}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "lottery-co-uk-scraper.data", "lottery-co-uk-scraper.data\lottery-co-uk-scraper.data.csproj", "{57463DA3-7350-4A10-853C-6C766F96A039}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lottery-co-uk-scraper.core", "lottery-co-uk-scraper.core\lottery-co-uk-scraper.core.csproj", "{8CA5863C-1FBF-443A-A6A1-B49795C86520}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "lottery-co-uk-scraper.core", "lottery-co-uk-scraper.core\lottery-co-uk-scraper.core.csproj", "{8CA5863C-1FBF-443A-A6A1-B49795C86520}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "lottery-co-uk-scraper.tests", "lottery-co-uk-scraper.tests\lottery-co-uk-scraper.tests.csproj", "{ADB3EC10-84F1-4928-9431-35A91816AA77}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -27,6 +29,10 @@ Global
{8CA5863C-1FBF-443A-A6A1-B49795C86520}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8CA5863C-1FBF-443A-A6A1-B49795C86520}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8CA5863C-1FBF-443A-A6A1-B49795C86520}.Release|Any CPU.Build.0 = Release|Any CPU
{ADB3EC10-84F1-4928-9431-35A91816AA77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADB3EC10-84F1-4928-9431-35A91816AA77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADB3EC10-84F1-4928-9431-35A91816AA77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ADB3EC10-84F1-4928-9431-35A91816AA77}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>lottery_co_uk_scraper.tests</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.5.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,251 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
using Microsoft.Extensions.Logging;
using static lottery_co_uk_scraper.EuroMillions.DrawWinnerInformation; /// So this table should not exist here.
namespace lottery_co_uk_scraper.EuroMillions
{
internal class DrawBalls
{
private static readonly ILogger<DrawBalls> _logger;
private static HtmlNode GetNodeById(HtmlNode containerNode, string nodeId)
{
try
{
return containerNode.DescendantsAndSelf()
.FirstOrDefault(x => x.Attributes["id"] != null && x.Attributes["id"].Value == nodeId)
?? throw new InvalidOperationException($"Node with ID '{nodeId}' not found.");
}
catch
{
throw new InvalidOperationException($"Node with ID '{nodeId}' not found.");
}
}
public static int ProcessBallSetUsed(HtmlDocument doc, EurosResult eurosResult)
{
try
{
var ballSetUsedString = doc.DocumentNode.Descendants("td")
.Where(x => x.InnerHtml.Contains("<strong>Ball Set Used:</strong>"))
.Select(x => x.InnerText.Split(':')[1].Trim())
.FirstOrDefault();
if (int.TryParse(ballSetUsedString, out int ballSetUsed))
{
AssignBallSetToModelProperty(EurosTableRow.BallSetUsed, ballSetUsed, eurosResult);
return ballSetUsed;
}
else
{
_logger.LogInformation("Failed to parse Euro Millions Ball Set Used.");
throw new Exception("Failed to parse Euro Millions Ball Set Used.");
}
}
catch
{
throw new Exception("Failed to parse Euro Millions Ball Set Used.");
}
}
public static void AssignBallSetToModelProperty(string containerNode, int ballSetUsed, EurosResult eurosResult)
{
try
{
if (containerNode == EurosTableRow.BallSetUsed)
{
PropertyManager.SetProperty(nameof(eurosResult.BallSetUsed), eurosResult, ballSetUsed);
}
}
catch
{
_logger.LogError("Failed to parse {containerNode}", containerNode);
throw new Exception($"Failed to parse {containerNode}");
}
}
public static void ProcessMainBalls(HtmlDocument doc, EurosResult eurosResult)
{
try
{
var ballsDrawn = GetNodeById(doc.DocumentNode, EurosTableRow.BallsDrawn);
List<int>? euroBalls = ballsDrawn != null
? ExtractBalls(ballsDrawn, "euromillions-ball")
: null;
if (euroBalls != null)
{
AssignDrawBallsToModelProperty(EurosTableRow.BallsDrawn, euroBalls, eurosResult);
}
else
{
_logger.LogError("EuroMillions Draw Balls were null!");
throw new Exception("EuroMillions Draw Balls were null!");
}
}
catch (Exception ex)
{
_logger.LogError("There was a problem processing the EuroMillions Draw Balls. {Message}", ex.Message);
throw new Exception($"There was a problem processing the EuroMillions Draw Balls. {ex}");
}
}
private static List<int> ExtractBalls(HtmlNode ballsNode, string className)
{
try
{
return ballsNode.Descendants("span")
.Where(x => x.Attributes["class"] != null && x.Attributes["class"].Value.Contains(className))
.Select(x =>
{
if (int.TryParse(x.InnerText, out int ball))
{
return ball;
}
_logger.LogError("Failed to parse {className} value: {x.InnerText}", className, x.InnerText);
throw new Exception($"Failed to parse {className} value: {x.InnerText}");
})
.ToList();
}
catch
{
throw new Exception($"Failed to parse {className}");
}
}
public static void AssignDrawBallsToModelProperty(string containerNode, object ballInformation, EurosResult eurosResult)
{
try
{
if (containerNode == EurosTableRow.BallsDrawn)
{
if (ballInformation is List<int> balls && balls.Count >= 5)
{
for (int i = 0; i < 5; i++)
{
string propertyName = $"DrawnBall{i + 1}";
PropertyManager.SetProperty(propertyName, eurosResult, balls[i]);
}
}
else
{
_logger.LogError("Invalid drawn balls information.");
throw new Exception("Invalid drawn balls information.");
}
}
else
{
_logger.LogError("Unhandled containerNode: {containerNode}", containerNode);
throw new Exception($"Unhandled containerNode: {containerNode}");
}
}
catch
{
throw new Exception($"Unhandled containerNode: {containerNode}");
}
}
public static void ProcessLuckyStars(HtmlDocument doc, EurosResult eurosResult)
{
try
{
var ballsDrawn = GetNodeById(doc.DocumentNode, EurosTableRow.BallsDrawn);
List<int>? luckyStars = ballsDrawn != null
? ExtractLuckyStar(ballsDrawn, "euromillions-lucky-star")
: null;
if (luckyStars != null)
{
AssignLuckyStarToModelProperty(EurosTableRow.BallsDrawn, luckyStars, eurosResult);
}
else
{
_logger.LogError("Lucky Stars appear to be null.");
throw new Exception("Lucky Stars appear to be null.");
}
}
catch (Exception ex)
{
_logger.LogError("There was a problem processing the EuroMillions Lucky Stars. {Message}", ex.Message);
throw new Exception($"There was a problem processing the EuroMillions Lucky Stars. {ex}");
}
}
private static List<int>ExtractLuckyStar(HtmlNode ballsNode, string ballClass)
{
try
{
return ballsNode.Descendants("span")
.Where(x => x.HasClass(ballClass))
.Select(x =>
{
if (int.TryParse(x.InnerText, out int ball))
{
return ball;
}
_logger.LogError("Failed to parse {className} value: {x.InnerText}", ballClass, x.InnerText);
throw new Exception($"Failed to parse {ballClass} value: {x.InnerText}");
})
.ToList();
}
catch
{
_logger.LogError("There was a problem processing the EuroMillions Lucky Stars.");
throw new Exception($"There was a problem processing the EuroMillions Lucky Stars.");
}
}
public static void AssignLuckyStarToModelProperty(string containerNode, object ballInformation, EurosResult eurosResult)
{
try
{
if (containerNode == EurosTableRow.BallsDrawn)
{
if (ballInformation is List<int> balls && balls.Count >= 2)
{
for (int i = 0; i < 2; i++)
{
string propertyName = $"LuckyStar{i + 1}";
PropertyManager.SetProperty(propertyName, eurosResult, balls[i]);
}
}
else
{
_logger.LogError("Invalid Lucky Star balls information.");
throw new Exception("Invalid Lucky Star balls information.");
}
}
else
{
_logger.LogError("Unhandled containerNode: {containerNode}", containerNode);
throw new Exception($"Unhandled containerNode: {containerNode}");
}
}
catch
{
throw new Exception($"Unhandled containerNode: {containerNode}");
}
}
}
}

View File

@@ -0,0 +1,43 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
namespace lottery_co_uk_scraper.EuroMillions
{
internal class DrawCode
{
public static List<string> ProcessMillionaireMaker(HtmlDocument doc, EurosResult eurosResult)
{
try
{
var raffleNumbers = new List<string>();
foreach (var span in doc.DocumentNode.Descendants("span"))
{
var classAttribute = span.GetAttributeValue("class", "");
if (classAttribute.Contains("millionaire") && classAttribute.Contains("raffle"))
{
raffleNumbers.Add(span.InnerText.Trim());
}
}
AssignMillionaireMakerToModelProperty(nameof(eurosResult.MillionaireMakerCode), raffleNumbers, eurosResult);
return raffleNumbers;
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
throw new Exception("Failed to Process Millionaire Maker Code.");
}
public static void AssignMillionaireMakerToModelProperty(string propertyName, List<string> raffleNumbers, EurosResult eurosResult)
{
PropertyManager.SetProperty(propertyName, eurosResult, raffleNumbers);
}
}
}

View File

@@ -0,0 +1,57 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
namespace lottery_co_uk_scraper.EuroMillions
{
internal class DrawDate
{
public static void ProcessDrawDateFromMeta(HtmlDocument doc, EurosResult eurosResult)
{
try
{
var title = doc.DocumentNode.Descendants("title")
.FirstOrDefault();
if (title != null)
{
var titleText = title.InnerText;
var date = TextRemoval.ParseDateString(titleText);
string formattedDate = date.ToString("dd/MM/yyyy");
AssignDrawDateToModelProperty(nameof(eurosResult.DrawDate), formattedDate, eurosResult);
}
else
{
// ToDo: Logger - Title not found
}
}
catch (Exception ex)
{
// ToDo: Logger
Console.WriteLine(ex.Message);
}
}
public static void AssignDrawDateToModelProperty(string propertyName, string formattedDate, EurosResult eurosResult)
{
try
{
if (DateOnly.TryParse(formattedDate, out DateOnly value))
{
PropertyManager.SetProperty(propertyName, eurosResult, value);
}
else
{
// ToDo: Failed to parse {propertyName}
}
}
catch (Exception ex)
{
// ToDo: Logger
Console.WriteLine(ex.Message);
}
}
}
}

View File

@@ -0,0 +1,42 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
namespace lottery_co_uk_scraper.EuroMillions
{
internal class DrawMachine
{
public static string ProcessMachineUsed(HtmlDocument doc, EurosResult eurosResult)
{
try
{
var machineName = doc.DocumentNode.Descendants("td")
.Where(x => x.InnerHtml.Contains("<strong>Ball Machine Used:</strong>"))
.Select(x => x.InnerText.Split(':')[1].Trim())
.FirstOrDefault();
if (machineName != null)
{
AssignDrawMachineToModelProperty(nameof(eurosResult.MachineUsed), machineName, eurosResult);
return machineName;
}
else
{
// ToDo: _logger.LogError
throw new Exception("machineName is null");
}
}
catch (Exception ex)
{
// ToDo: Logger
return ex.Message;
}
}
public static void AssignDrawMachineToModelProperty(string propertyName, string machineName, EurosResult eurosResult)
{
PropertyManager.SetProperty(propertyName, eurosResult, machineName);
}
}
}

View File

@@ -0,0 +1,59 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
using System.Text.RegularExpressions;
namespace lottery_co_uk_scraper.EuroMillions
{
internal partial class DrawNumber
{
[GeneratedRegex(@"euromillions draw (\d+)")]
private static partial Regex MyRegex();
public static int ProcessDrawNumberFromMeta(HtmlDocument doc, EurosResult eurosResult)
{
var metaKeywords = doc.DocumentNode.Descendants("meta")
.FirstOrDefault(x => x.GetAttributeValue("name", "") == "keywords");
if (metaKeywords != null)
{
var keywordsText = metaKeywords.GetAttributeValue("content", "");
var drawNumberMatch = MyRegex().Match(keywordsText);
if (drawNumberMatch.Success)
{
if (int.TryParse(drawNumberMatch.Groups[1].Value, out int drawNumber))
{
Console.WriteLine("Draw Number: " + drawNumber);
AssignDrawNumberToModelProperty(drawNumber, eurosResult);
return drawNumber;
}
else
{
Console.WriteLine("Failed to parse draw number.");
return 0;
}
}
else
{
Console.WriteLine("Draw Number not found.");
return 0;
}
}
else
{
Console.WriteLine("Meta keywords not found.");
return 0;
}
}
public static void AssignDrawNumberToModelProperty(int drawNumber, EurosResult eurosResult)
{
PropertyManager.SetProperty(nameof(eurosResult.DrawNumber), eurosResult, drawNumber);
}
}
}

View File

@@ -0,0 +1,49 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
namespace lottery_co_uk_scraper.EuroMillions
{
internal class DrawStatus
{
public static bool ProcessRollover(HtmlDocument doc, EurosResult eurosResult)
{
try
{
var rolloverElement = doc.DocumentNode.Descendants("span")
.FirstOrDefault(x => x.InnerText.Trim() == "Rollover");
bool rollover = rolloverElement != null;
if (rollover)
{
AssignDrawStatusToModelProperty(rollover, eurosResult);
Console.WriteLine("Rollover: " + rollover);
return true;
}
else
{
return false;
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
public static void AssignDrawStatusToModelProperty(bool status, EurosResult eurosResult)
{
try
{
PropertyManager.SetProperty(nameof(eurosResult.Rollover), eurosResult, status);
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
}
}

View File

@@ -0,0 +1,734 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
using lottery_co_uk_scraper.core.Exceptions;
using System.Globalization;
using System.Text.RegularExpressions;
namespace lottery_co_uk_scraper.EuroMillions
{
internal partial class DrawWinnerInformation
{
[GeneratedRegex(@"(\d+)")]
private static partial Regex MyRegex();
internal class EurosTableRow()
{
internal const string BallSetUsed = "ballSetUsed";
internal const string BallsDrawn = "ballsDrawn";
internal const string Match1Plus2Stars = "Match 1 and 2 Stars";
internal const string Match2 = "Match 2";
internal const string Match2Plus1Star = "Match 2 and 1 Star";
internal const string Match2Plus2Stars = "Match 2 and 2 Star";
internal const string Match3 = "Match 3";
internal const string Match3Plus1Star = "Match 3 and 1 Star";
internal const string Match3Plus2Stars = "Match 3 and 2 Star";
internal const string Match4 = "Match 4";
internal const string Match4Plus1Star = "Match 4 and 1 Star";
internal const string Match4Plus2Stars = "Match 4 and 2 Star";
internal const string Match5 = "Match 5";
internal const string Match5Plus1Star = "Match 5 and 1 Star";
internal const string Match5Plus2Stars = "Match 5 and 2 Star";
internal const string Total = "Totals";
internal const string Winners = "UK Winners";
internal const string PrizePerWinner = "Prize Per Winner";
internal const string PrizeFundAmountUK = "UK Prize Fund";
internal const string TotalWinners = "Total Winners";
}
public static void ProcessWinnersTable(HtmlDocument doc, EurosResult eurosResult)
{
try
{
var table = doc.DocumentNode.Descendants("table")
.FirstOrDefault(x => x.Attributes["class"] != null && x.Attributes["class"].Value.Contains("euromillions mobFormat"));
if (table != null)
{
ProcessTableSection(table, EurosTableRow.Match1Plus2Stars, eurosResult);
ProcessTableSection(table, EurosTableRow.Match2, eurosResult);
ProcessTableSection(table, EurosTableRow.Match2Plus1Star, eurosResult);
ProcessTableSection(table, EurosTableRow.Match2Plus2Stars, eurosResult);
ProcessTableSection(table, EurosTableRow.Match3, eurosResult);
ProcessTableSection(table, EurosTableRow.Match3Plus1Star, eurosResult);
ProcessTableSection(table, EurosTableRow.Match3Plus2Stars, eurosResult);
ProcessTableSection(table, EurosTableRow.Match4, eurosResult);
ProcessTableSection(table, EurosTableRow.Match4Plus1Star, eurosResult);
ProcessTableSection(table, EurosTableRow.Match4Plus2Stars, eurosResult);
ProcessTableSection(table, EurosTableRow.Match5, eurosResult);
ProcessTableSection(table, EurosTableRow.Match5Plus1Star, eurosResult);
ProcessTableSection(table, EurosTableRow.Match5Plus2Stars, eurosResult);
ProcessTableSection(table, EurosTableRow.Winners, eurosResult);
ProcessTableSection(table, EurosTableRow.PrizePerWinner, eurosResult);
ProcessTableSection(table, EurosTableRow.PrizeFundAmountUK, eurosResult);
ProcessTableSection(table, EurosTableRow.TotalWinners, eurosResult);
}
}
catch (Exception ex)
{
// ToDo: Catch Exception
Console.WriteLine(ex.Message);
}
}
public static void ProcessTableSection(HtmlNode table, string sectionTitle, EurosResult eurosResult)
{
try
{
var sectionRow = GetSectionRowByTitle(table, sectionTitle);
if (sectionRow != null)
{
var ukWinnersNode = GetNodeByDataTitle(sectionRow, EurosTableRow.Winners);
var prizePerWinnerNode = GetNodeByDataTitle(sectionRow, EurosTableRow.PrizePerWinner);
var prizeFundUKNode = GetNodeByDataTitle(sectionRow, EurosTableRow.PrizeFundAmountUK);
var totalWinnersNode = GetNodeByDataTitle(sectionRow, EurosTableRow.TotalWinners);
if (ukWinnersNode != null && prizePerWinnerNode != null && prizeFundUKNode != null)
{
ProcessUKWinners(sectionTitle, ukWinnersNode, eurosResult);
ProcessWinnerPrizeAmount(sectionTitle, prizePerWinnerNode, eurosResult);
ProcessPrizeFundAmountUK(sectionTitle, prizeFundUKNode, eurosResult);
ProcessTotalWinners(sectionTitle, totalWinnersNode, eurosResult);
}
else
{
// ToDo:Logger - Missing winners, prize per winner, or prize fund nodes in the table.
}
}
else
{
// ToDo: Logger - Section title '{sectionTitle}' not found in the table.
}
}
catch (Exception ex)
{
// ToDo: Logger - Exception
Console.WriteLine(ex.Message);
}
}
private static HtmlNode GetSectionRowByTitle(HtmlNode table, string sectionTitle)
{
try
{
var sectionRow = table.Descendants("tr")
.FirstOrDefault(x => x.Descendants("td").Any(y => y.InnerText.Contains(sectionTitle, StringComparison.OrdinalIgnoreCase)));
if (sectionRow != null)
{
return sectionRow;
}
else
{
throw new NullResultException("Machine name is null.");
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
private static HtmlNode GetNodeByDataTitle(HtmlNode sectionRow, string dataTitle)
{
try
{
return sectionRow.Descendants("td")
.FirstOrDefault(x => x.Attributes["data-title"] != null && x.Attributes["data-title"].Value == dataTitle)
?? throw new InvalidOperationException($"Section row with title '{dataTitle}' not found.");
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
throw new Exception("Failed to get node by data title.");
}
public static void ProcessUKWinners(string sectionTitle, HtmlNode winnersNode, EurosResult eurosResult)
{
try
{
if (int.TryParse(winnersNode.InnerText.Trim().Replace(",", ""), NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out int winners))
{
string columnTitle = winnersNode.Attributes["data-title"].Value;
ParseWinnerCount(sectionTitle, columnTitle, winners, eurosResult);
}
else
{
// ToDo: Logger - Failed to parse {sectionTitle} winners.
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
private static void ParseWinnerCount(string sectionTitle, string columnTitle, int winners, EurosResult eurosResult)
{
try
{
AssignValueToModelProperty(sectionTitle, EurosTableRow.Match2, columnTitle, winners, eurosResult);
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
public static void ProcessWinnerPrizeAmount(string sectionTitle, HtmlNode prizePerWinnerNode, EurosResult eurosResult)
{
try
{
string prizeText = prizePerWinnerNode.InnerText.Trim().Replace("&pound;", "").Replace(",", "");
string columnTitle = prizePerWinnerNode.Attributes["data-title"].Value;
int prizePerWinner;
if (prizeText == "Free Ticket")
{
prizePerWinner = 999999999;
}
else if (int.TryParse(prizeText, NumberStyles.Currency, CultureInfo.InvariantCulture, out int parsedPrize))
{
prizePerWinner = parsedPrize;
}
else
{
// ToDo: Logger - Failed to parse prize per winner ({sectionTitle}).
return;
}
ParseWinnerPrizeAmount(sectionTitle, columnTitle, prizePerWinner, eurosResult);
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
public static void ParseWinnerPrizeAmount(string sectionTitle, string columnTitle, int prizePerWinner, EurosResult eurosResult)
{
try
{
AssignValueToModelProperty(sectionTitle, EurosTableRow.Match2, columnTitle, prizePerWinner, eurosResult);
}
catch
{
// ToDo: Logger
Console.WriteLine("Nothing to match");
}
}
public static void ProcessPrizeFundAmountUK(string sectionTitle, HtmlNode prizeFundNode, EurosResult eurosResult)
{
try
{
string prizeFundText = prizeFundNode.InnerText.Trim().Replace("&pound;", "").Replace(",", "");
string columnTitle = prizeFundNode.Attributes["data-title"].Value;
int prizeFund;
if (prizeFundText == "-")
{
prizeFund = 999999999;
}
else if (int.TryParse(prizeFundText, NumberStyles.Currency, CultureInfo.InvariantCulture, out int parsedPrizeFund))
{
prizeFund = parsedPrizeFund;
}
else
{
// ToDo: Logger
return;
}
ParsePrizeFundAmountUK(sectionTitle, columnTitle, prizeFund, eurosResult);
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
public static void ParsePrizeFundAmountUK(string sectionTitle, string columnTitle, int prizeFundNode, EurosResult eurosResult)
{
try
{
AssignValueToModelProperty(sectionTitle, EurosTableRow.Match2, columnTitle, prizeFundNode, eurosResult);
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
public static void ProcessTotalWinners(string sectionTitle, HtmlNode totalWinnersNode, EurosResult eurosResult)
{
try
{
if (int.TryParse(totalWinnersNode.InnerText.Trim().Replace(",", ""), NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out int totalWinners))
{
string columnTitle = totalWinnersNode.Attributes["data-title"].Value;
ParseTotalWinners(sectionTitle, columnTitle, totalWinners, eurosResult);
}
else
{
// ToDo: Logger - Failed to parse {sectionTitle} winners.
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
public static void ParseTotalWinners(string sectionTitle, string columnTitle, int totalWinnersNode, EurosResult eurosResult)
{
try
{
AssignValueToModelProperty(sectionTitle, EurosTableRow.Match2, columnTitle, totalWinnersNode, eurosResult);
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
public static void AssignValueToModelProperty(string sectionTitle, string propertyName, string columnTitle, int value, EurosResult eurosResult)
{
switch (sectionTitle)
{
#region Match 1 Plus 2 Stars
case EurosTableRow.Match1Plus2Stars:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched1Plus2StarsUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched1Plus2StarsPrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched1Plus2StarsPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched1Plus2Stars), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
#endregion
#region Match 2, Match 2 Plus 1 Star & Match 2 Plus 2 Stars
case EurosTableRow.Match2:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched2UK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched2PrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched2PrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched2), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
case EurosTableRow.Match2Plus1Star:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched2Plus1StarUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched2Plus1StarPrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched2Plus1StarPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched2Plus1Star), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
case EurosTableRow.Match2Plus2Stars:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched2Plus2StarsUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched2Plus2StarsPrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched2Plus2StarsPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched2Plus2Stars), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
#endregion
#region Match 3, Match 3 Plus 1 Star & Match 3 Plus 2 Stars
case EurosTableRow.Match3:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched3UK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched3PrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched3PrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched3), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
case EurosTableRow.Match3Plus1Star:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched3Plus1StarUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched3Plus1StarPrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched3Plus1StarPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched3Plus1Star), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
case EurosTableRow.Match3Plus2Stars:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched3Plus2StarsUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched3Plus2StarsPrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched3Plus2StarsPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched3Plus2Stars), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
#endregion
#region Match 4, Match 4 Plus 1 Star & Match 4 Plus 2 Stars
case EurosTableRow.Match4:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched4UK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched4PrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched4PrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched4), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
case EurosTableRow.Match4Plus1Star:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched4Plus1StarUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched4Plus1StarPrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched4Plus1StarPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched4Plus1Star), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
case EurosTableRow.Match4Plus2Stars:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched4Plus2StarsUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched4Plus2StarsPrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched4Plus2StarsPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched4Plus2Stars), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
#endregion
#region Match 5, Match 5 Plus 1 Star & Match 5 Plus 2 Stars
case EurosTableRow.Match5:
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched5UK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched5PrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched5PrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched5), eurosResult, value);
}
break;
case EurosTableRow.Match5Plus1Star:
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched5Plus1StarUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched5Plus1StarPrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched5Plus1StarPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched5Plus1Star), eurosResult, value);
}
break;
case EurosTableRow.Match5Plus2Stars:
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched5Plus2StarsUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched5Plus2StarsPrizeUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.Matched5Plus2StarsPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.TotalWinners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalMatched5Plus2Stars), eurosResult, value);
}
break;
#endregion
#region Totals
case EurosTableRow.Total:
try
{
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalWinnersUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.PrizeFundAmountUK)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalPrizeFundUK), eurosResult, value);
}
if (columnTitle == EurosTableRow.Winners)
{
PropertyManager.SetProperty(nameof(eurosResult.TotalWinners), eurosResult, value);
}
}
catch (Exception ex)
{
// ToDo: Logger
throw new Exception(ex.Message);
}
break;
#endregion
}
}
}
}

View File

@@ -0,0 +1,43 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.data;
namespace lottery_co_uk_scraper.EuroMillions
{
internal class Euros
{
public static async Task GetEuroMillionsData(string url, HttpClient client)
{
try
{
string html = await client.GetStringAsync(url);
var eurosResult = new EurosResult();
var doc = new HtmlDocument();
doc.LoadHtml(html);
DrawBalls.ProcessBallSetUsed(doc, eurosResult);
DrawDate.ProcessDrawDateFromMeta(doc, eurosResult); // Not working.
DrawNumber.ProcessDrawNumberFromMeta(doc, eurosResult);
DrawCode.ProcessMillionaireMaker(doc, eurosResult); // Not working.
DrawStatus.ProcessRollover(doc, eurosResult);
DrawBalls.ProcessMainBalls(doc, eurosResult);
DrawBalls.ProcessLuckyStars(doc, eurosResult);
DrawMachine.ProcessMachineUsed(doc, eurosResult);
DrawWinnerInformation.ProcessWinnersTable(doc, eurosResult);
CommitToDatabase.SaveModelToDatabase(eurosResult);
}
catch (HttpRequestException ex)
{
// ToDo: Logger HTTP request error: {ex.Message}
Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
// ToDo: Logger - An error occurred: {ex.Message}
Console.WriteLine(ex.Message);
}
}
}
}

View File

@@ -1,140 +1,245 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
using static lottery_co_uk_scraper.NationalLottery.Lotto;
using Microsoft.Extensions.Logging;
using static lottery_co_uk_scraper.NationalLottery.DrawWinnerInformation;
namespace lottery_co_uk_scraper.NationalLottery
{
internal class DrawBalls
{
private static readonly ILogger<DrawBalls> _logger;
private static HtmlNode GetNodeById(HtmlNode containerNode, string nodeId)
{
try
{
return containerNode.DescendantsAndSelf()
.FirstOrDefault(x => x.Attributes["id"] != null && x.Attributes["id"].Value == nodeId)
?? throw new InvalidOperationException($"Node with ID '{nodeId}' not found.");
}
catch
{
throw new InvalidOperationException($"Node with ID '{nodeId}' not found.");
}
}
public static int ProcessBallSetUsed(HtmlDocument doc, LottoResult lottoResult)
{
var ballSetUsedString = doc.DocumentNode.Descendants("td")
.Where(x => x.InnerHtml.Contains("<strong>Ball Set Used:</strong>"))
.Select(x => x.InnerText.Split(':')[1].Trim())
.FirstOrDefault();
if (int.TryParse(ballSetUsedString, out int ballSetUsed))
try
{
Console.WriteLine("Ball set used: " + ballSetUsed);
var ballSetUsedString = doc.DocumentNode.Descendants("td")
.Where(x => x.InnerHtml.Contains("<strong>Ball Set Used:</strong>"))
.Select(x => x.InnerText.Split(':')[1].Trim())
.FirstOrDefault();
AssignBallSetToModelProperty(LotteryTableRow.BallSetUsed, ballSetUsed, lottoResult);
if (int.TryParse(ballSetUsedString, out int ballSetUsed))
{
Console.WriteLine("Ball set used: " + ballSetUsed);
return ballSetUsed;
AssignBallSetToModelProperty(LotteryTableRow.BallSetUsed, ballSetUsed, lottoResult);
return ballSetUsed;
}
else
{
_logger.LogInformation("Failed to parse Lotto Ball Set Used.");
throw new Exception("Failed to parse Lotto Ball Set Used.");
}
}
else
catch
{
Console.WriteLine("Failed to parse Ball Set Used.");
throw new Exception("Failed to parse Lotto Ball Set Used.");
}
}
return 0; // or throw an exception
public static void AssignBallSetToModelProperty(string containerNode, int ballSetUsed, LottoResult lottoResult)
{
try
{
if (containerNode == LotteryTableRow.BallSetUsed)
{
PropertyManager.SetProperty(nameof(lottoResult.BallSetUsed), lottoResult, ballSetUsed);
}
}
catch
{
_logger.LogError("Failed to parse {containerNode}", containerNode);
throw new Exception($"Failed to parse {containerNode}");
}
}
public static void ProcessMainBalls(HtmlDocument doc, LottoResult lottoResult)
{
try
{
var ballsDrawn = GetNodeById(doc.DocumentNode, LotteryTableRow.BallsDrawn);
List<int>? lottoBalls = ballsDrawn != null
? ExtractBalls(ballsDrawn, "lotto-ball")
: null;
if (lottoBalls != null)
{
AssignDrawBallsToModelProperty(LotteryTableRow.BallsDrawn, lottoBalls, lottoResult);
}
else
{
_logger.LogError("Lotto Draw Balls were null!");
throw new Exception("Lotto Draw Balls were null!");
}
}
catch (Exception ex)
{
_logger.LogError("There was a problem processing the Lotto Draw Balls. {Message}", ex.Message);
throw new Exception($"There was a problem processing the Lotto Draw Balls. {ex}");
}
}
private static List<int> ExtractBalls(HtmlNode ballsNode, string className)
{
return ballsNode.Descendants("span")
.Where(x => x.Attributes["class"] != null && x.Attributes["class"].Value.Contains(className))
.Select(x =>
{
if (int.TryParse(x.InnerText, out int ball))
try
{
return ballsNode.Descendants("span")
.Where(x => x.Attributes["class"] != null && x.Attributes["class"].Value.Contains(className))
.Select(x =>
{
return ball;
}
if (int.TryParse(x.InnerText, out int ball))
{
return ball;
}
Console.WriteLine($"Failed to parse {className} value: {x.InnerText}");
_logger.LogError("Failed to parse {className} value: {x.InnerText}", className, x.InnerText);
return 0;
})
.ToList();
}
public static void ProcessMainBalls(HtmlDocument doc, LottoResult lottoResult)
{
var ballsDrawn = GetNodeById(doc.DocumentNode, LotteryTableRow.BallsDrawn);
List<int>? lottoBalls = ballsDrawn != null
? ExtractBalls(ballsDrawn, "lotto-ball")
: null;
AssignDrawBallsToModelProperty(LotteryTableRow.BallsDrawn, lottoBalls, lottoResult);
}
private static HtmlNode GetNodeById(HtmlNode containerNode, string nodeId)
{
return containerNode.DescendantsAndSelf()
.FirstOrDefault(x => x.Attributes["id"] != null && x.Attributes["id"].Value == nodeId)
?? throw new InvalidOperationException($"Node with ID '{nodeId}' not found.");
}
public static void AssignBallSetToModelProperty(string containerNode, int ballSetUsed, LottoResult lottoResult)
{
if (containerNode == LotteryTableRow.BallSetUsed)
{
PropertyManager.SetProperty(nameof(lottoResult.BallSetUsed), lottoResult, ballSetUsed);
throw new Exception($"Failed to parse {className} value: {x.InnerText}");
})
.ToList();
}
}
public static void ProcessBonusBalls(HtmlDocument doc, LottoResult lottoResult)
{
var ballsDrawn = GetNodeById(doc.DocumentNode, LotteryTableRow.BallsDrawn);
int? lottoBonusBall = ballsDrawn != null
? ExtractBonusBall(ballsDrawn, "lotto-bonus-ball")
: (int?)null;
AssignBonusBallToModelProperty(LotteryTableRow.BallsDrawn, lottoBonusBall, lottoResult);
}
private static int? ExtractBonusBall(HtmlNode ballsDrawn, string ballClass)
{
var bonusBallNode = ballsDrawn.Descendants("span")
.FirstOrDefault(x => x.HasClass(ballClass));
if (bonusBallNode != null && int.TryParse(bonusBallNode.InnerText, out int bonusBall))
catch
{
Console.WriteLine("Bonus Ball: " + bonusBall);
return bonusBall;
}
Console.WriteLine("Failed to extract Bonus Ball.");
return null;
}
public static void AssignBonusBallToModelProperty(string containerNode, int? ballInformation, LottoResult lottoResult)
{
if (containerNode == LotteryTableRow.BallsDrawn)
{
if (ballInformation.HasValue)
{
PropertyManager.SetProperty(nameof(lottoResult.DrawnBonusBall), lottoResult, ballInformation.Value);
}
else
{
Console.WriteLine("Invalid Bonus Ball information.");
}
throw new Exception($"Failed to parse {className}");
}
}
public static void AssignDrawBallsToModelProperty(string containerNode, object ballInformation, LottoResult lottoResult)
{
if (containerNode == LotteryTableRow.BallsDrawn)
try
{
if (ballInformation is List<int> balls && balls.Count >= 6)
if (containerNode == LotteryTableRow.BallsDrawn)
{
for (int i = 0; i < 6; i++)
if (ballInformation is List<int> balls && balls.Count >= 6)
{
string propertyName = $"DrawnBall{i + 1}";
PropertyManager.SetProperty(propertyName, lottoResult, balls[i]);
for (int i = 0; i < 6; i++)
{
string propertyName = $"DrawnBall{i + 1}";
PropertyManager.SetProperty(propertyName, lottoResult, balls[i]);
}
}
else
{
_logger.LogError("Invalid drawn balls information.");
throw new Exception("Invalid drawn balls information.");
}
}
else
{
Console.WriteLine("Invalid drawn balls information.");
_logger.LogError("Unhandled containerNode: {containerNode}", containerNode);
throw new Exception($"Unhandled containerNode: {containerNode}");
}
}
else
catch
{
Console.WriteLine($"Unhandled containerNode: {containerNode}");
throw new Exception($"Unhandled containerNode: {containerNode}");
}
}
public static void ProcessBonusBalls(HtmlDocument doc, LottoResult lottoResult)
{
try
{
var ballsDrawn = GetNodeById(doc.DocumentNode, LotteryTableRow.BallsDrawn);
int? lottoBonusBall = ballsDrawn != null
? ExtractBonusBall(ballsDrawn, "lotto-bonus-ball")
: (int?)null;
if (lottoBonusBall != null)
{
AssignBonusBallToModelProperty(LotteryTableRow.BallsDrawn, lottoBonusBall, lottoResult);
}
else
{
_logger.LogError("Bonus Ball appears to be null.");
throw new Exception("Bonus Ball appears to be null.");
}
}
catch (Exception ex)
{
_logger.LogError("There was a problem processing the EuroMillions Lucky Stars. {Message}", ex.Message);
throw new Exception($"There was a problem processing the EuroMillions Lucky Stars. {ex}");
}
}
private static int? ExtractBonusBall(HtmlNode ballsDrawn, string ballClass)
{
try
{
var bonusBallNode = ballsDrawn.Descendants("span")
.FirstOrDefault(x => x.HasClass(ballClass));
if (bonusBallNode != null && int.TryParse(bonusBallNode.InnerText, out int bonusBall))
{
return bonusBall;
}
_logger.LogError("Failed to parse {className}", ballClass);
throw new Exception($"Failed to parse {ballClass}");
}
catch
{
_logger.LogError("There was a problem processing the Lotto Bonus Ball.");
throw new Exception($"There was a problem processing the Lotto Bonus Ball.");
}
}
public static void AssignBonusBallToModelProperty(string containerNode, int? ballInformation, LottoResult lottoResult)
{
try
{
if (containerNode == LotteryTableRow.BallsDrawn)
{
if (ballInformation.HasValue)
{
PropertyManager.SetProperty(nameof(lottoResult.DrawnBonusBall), lottoResult, ballInformation.Value);
}
else
{
_logger.LogError("Invalid bonus ball information.");
throw new Exception("Invalid bonus ball information.");
}
}
else
{
_logger.LogError("Unhandled containerNode: {containerNode}", containerNode);
throw new Exception($"Unhandled containerNode: {containerNode}");
}
}
catch
{
throw new Exception($"Unhandled containerNode: {containerNode}");
}
}
}

View File

@@ -1,7 +1,6 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
using System.Globalization;
namespace lottery_co_uk_scraper.NationalLottery
{

View File

@@ -1,4 +1,5 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Exceptions;
using lottery_co_uk_scraper.core.Models;
using lottery_co_uk_scraper.Utilities;
@@ -8,20 +9,39 @@ namespace lottery_co_uk_scraper.NationalLottery
{
public static string ProcessMachineUsed(HtmlDocument doc, LottoResult lottoResult)
{
var machineName = doc.DocumentNode.Descendants("td")
.Where(x => x.InnerHtml.Contains("<strong>Ball Machine Used:</strong>"))
.Select(x => x.InnerText.Split(':')[1].Trim())
.FirstOrDefault();
try
{
var machineName = doc.DocumentNode.Descendants("td")
.Where(x => x.InnerHtml.Contains("<strong>Ball Machine Used:</strong>"))
.Select(x => x.InnerText.Split(':')[1].Trim())
.FirstOrDefault();
AssignDrawMachineToModelProperty("MachineName", machineName, lottoResult);
Console.WriteLine("Machine Name: " + machineName);
// should there be a try parse and error exception stuff here like in ballSetUsed
return machineName;
if (machineName != null)
{
AssignDrawMachineToModelProperty(nameof(lottoResult.MachineUsed), machineName, lottoResult);
return machineName;
}
else
{
throw new NullResultException(nameof(lottoResult.MachineUsed) + " is null.");
}
}
catch (NullResultException nullEx)
{
return nullEx.Message;
}
catch (Exception ex)
{
// ToDo: _logger.LogErrorMessage();
return ex.Message;
}
}
public static void AssignDrawMachineToModelProperty(string propertyName, string machineName, LottoResult lottoResult)
{
PropertyManager.SetProperty(nameof(lottoResult.MachineUsed), lottoResult, machineName);
PropertyManager.SetProperty(propertyName, lottoResult, machineName);
}
}
}

View File

@@ -10,7 +10,6 @@ namespace lottery_co_uk_scraper.NationalLottery
{
var rolloverElement = doc.DocumentNode.Descendants("span")
.FirstOrDefault(x => x.InnerText.Trim() == "Rollover");
bool rollover = rolloverElement != null;
if (rollover)
@@ -30,7 +29,6 @@ namespace lottery_co_uk_scraper.NationalLottery
{
var rolldownElement = doc.DocumentNode.Descendants("span")
.FirstOrDefault(x => x.InnerText.Trim() == "Rolldown");
bool rolldown = rolldownElement != null;
if (rolldown)

View File

@@ -1,64 +1,100 @@
using HtmlAgilityPack;
using lottery_co_uk_scraper.core.Models;
using static lottery_co_uk_scraper.NationalLottery.Lotto;
using System.Globalization;
using lottery_co_uk_scraper.Utilities;
using System.Text.RegularExpressions;
namespace lottery_co_uk_scraper.NationalLottery
{
internal class DrawWinnerInformation
internal partial class DrawWinnerInformation
{
[GeneratedRegex(@"(\d+)")]
private static partial Regex MyRegex();
internal static class LotteryTableRow
{
internal const string Match2 = "Match 2";
internal const string Match3 = "Match 3";
internal const string Match4 = "Match 4";
internal const string Match5 = "Match 5";
internal const string Match5Bonus = "Match 5 plus Bonus";
internal const string Match6 = "Match 6";
internal const string Total = "Totals";
internal const string Winners = "Winners";
internal const string PrizePerWinner = "Prize Per Winner";
internal const string PrizeFundAmount = "Prize Fund Amount";
internal const string BallSetUsed = "ballSetUsed";
internal const string BallsDrawn = "ballsDrawn";
}
public static void ProcessTableSection(HtmlNode table, string sectionTitle, LottoResult lottoResult)
{
var sectionRow = GetSectionRowByTitle(table, sectionTitle);
if (sectionRow != null)
try
{
var winnersNode = GetNodeByDataTitle(sectionRow, LotteryTableRow.Winners);
var prizePerWinnerNode = GetNodeByDataTitle(sectionRow, LotteryTableRow.PrizePerWinner);
var prizeFundNode = GetNodeByDataTitle(sectionRow, LotteryTableRow.PrizeFundAmount);
var rolldown = lottoResult.Rolldown;
var sectionRow = GetSectionRowByTitle(table, sectionTitle);
if (winnersNode != null && prizePerWinnerNode != null && prizeFundNode != null)
if (sectionRow != null)
{
ProcessWinners(sectionTitle, winnersNode, lottoResult);
ProcessPrizeFundAmount(sectionTitle, prizeFundNode, lottoResult);
var winnersNode = GetNodeByDataTitle(sectionRow, LotteryTableRow.Winners);
var prizePerWinnerNode = GetNodeByDataTitle(sectionRow, LotteryTableRow.PrizePerWinner);
var prizeFundNode = GetNodeByDataTitle(sectionRow, LotteryTableRow.PrizeFundAmount);
var rolldown = lottoResult.Rolldown;
if (rolldown == false)
if (winnersNode != null && prizePerWinnerNode != null && prizeFundNode != null)
{
ProcessWinnerPrizeAmount(sectionTitle, prizePerWinnerNode, lottoResult);
ProcessWinners(sectionTitle, winnersNode, lottoResult);
ProcessPrizeFundAmount(sectionTitle, prizeFundNode, lottoResult);
if (rolldown == false)
{
ProcessWinnerPrizeAmount(sectionTitle, prizePerWinnerNode, lottoResult);
}
else
{
ProcessRolldownWinnerPrizeAmount(sectionTitle, prizePerWinnerNode, lottoResult);
}
}
else
{
ProcessRolldownWinnerPrizeAmount(sectionTitle, prizePerWinnerNode, lottoResult);
Console.WriteLine("Missing winners, prize per winner, or prize fund nodes in the table.");
}
}
else
{
Console.WriteLine("Missing winners, prize per winner, or prize fund nodes in the table.");
Console.WriteLine($"Section title '{sectionTitle}' not found in the table.");
}
}
else
catch (Exception ex)
{
Console.WriteLine($"Section title '{sectionTitle}' not found in the table.");
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
}
private static HtmlNode GetSectionRowByTitle(HtmlNode table, string sectionTitle)
{
var sectionRow = table.Descendants("tr")
.FirstOrDefault(x =>
x.Descendants("td").Any(y => y.InnerText.Contains(sectionTitle, StringComparison.OrdinalIgnoreCase))
);
try
{
var sectionRow = table.Descendants("tr")
.FirstOrDefault(x => x.Descendants("td").Any(y => y.InnerText.Contains(sectionTitle, StringComparison.OrdinalIgnoreCase)));
if (sectionRow != null)
{
return sectionRow;
if (sectionRow != null)
{
return sectionRow;
}
else
{
// ToDo: _logger.LogError
throw new Exception("sectionRow is null.");
}
}
else
catch (Exception ex)
{
return null;
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
throw new Exception("Failed to get section by row title.");
}
private static HtmlNode GetNodeByDataTitle(HtmlNode sectionRow, string dataTitle)
@@ -70,26 +106,37 @@ namespace lottery_co_uk_scraper.NationalLottery
public static void ProcessWinnersTable(HtmlDocument doc, LottoResult lottoResult)
{
var table = doc.DocumentNode.Descendants("table")
.FirstOrDefault(x => x.Attributes["class"] != null && x.Attributes["class"].Value.Contains("lotto mobFormat"));
if (table != null)
try
{
HtmlNode match2Section = GetSectionRowByTitle(table, LotteryTableRow.Match2);
if (match2Section != null)
var table = doc.DocumentNode.Descendants("table")
.FirstOrDefault(x => x.Attributes["class"] != null && x.Attributes["class"].Value.Contains("lotto mobFormat"));
if (table != null)
{
ProcessTableSection(table, LotteryTableRow.Match2, lottoResult);
HtmlNode match2Section = GetSectionRowByTitle(table, LotteryTableRow.Match2);
if (match2Section != null)
{
ProcessTableSection(table, LotteryTableRow.Match2, lottoResult);
}
else
{
// ToDo: I don't need this write line, log the information about it being a draw with no match twos.
//_logger.LogInformation("");
Console.WriteLine("Section row with title 'Match 2' not found. Continuing without processing Match 2.");
}
ProcessTableSection(table, LotteryTableRow.Match3, lottoResult);
ProcessTableSection(table, LotteryTableRow.Match4, lottoResult);
ProcessTableSection(table, LotteryTableRow.Match5, lottoResult);
ProcessTableSection(table, LotteryTableRow.Match5Bonus, lottoResult);
ProcessTableSection(table, LotteryTableRow.Match6, lottoResult);
ProcessTableSection(table, LotteryTableRow.Total, lottoResult);
}
else
{
Console.WriteLine("Section row with title 'Match 2' not found. Continuing without processing Match 2.");
}
ProcessTableSection(table, LotteryTableRow.Match3, lottoResult);
ProcessTableSection(table, LotteryTableRow.Match4, lottoResult);
ProcessTableSection(table, LotteryTableRow.Match5, lottoResult);
ProcessTableSection(table, LotteryTableRow.Match5Bonus, lottoResult);
ProcessTableSection(table, LotteryTableRow.Match6, lottoResult);
ProcessTableSection(table, LotteryTableRow.Total, lottoResult);
}
catch (Exception ex)
{
//_logger.LogError("");
throw new Exception(ex.Message);
}
}
@@ -97,126 +144,196 @@ namespace lottery_co_uk_scraper.NationalLottery
{
switch (sectionTitle)
{
#region Match 2
case LotteryTableRow.Match2:
if (columnTitle == LotteryTableRow.Winners)
try
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched2), lottoResult, value);
if (columnTitle == LotteryTableRow.Winners)
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched2), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched2Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched2PrizeFund), lottoResult, value);
}
}
catch(Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched2Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched2PrizeFund), lottoResult, value);
}
break;
break;
#endregion
#region Match 3
case LotteryTableRow.Match3:
if (columnTitle == LotteryTableRow.Winners)
try
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched3), lottoResult, value);
if (columnTitle == LotteryTableRow.Winners)
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched3), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched3Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched3PrizeFund), lottoResult, value);
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched3Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched3PrizeFund), lottoResult, value);
}
break;
break;
#endregion
#region Match 4
case LotteryTableRow.Match4:
if (columnTitle == LotteryTableRow.Winners)
try
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched4), lottoResult, value);
if (columnTitle == LotteryTableRow.Winners)
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched4), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched4Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched4PrizeFund), lottoResult, value);
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched4Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched4PrizeFund), lottoResult, value);
}
break;
break;
#endregion
#region Match 5
case LotteryTableRow.Match5:
if (columnTitle == LotteryTableRow.Winners)
try
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched5), lottoResult, value);
if (columnTitle == LotteryTableRow.Winners)
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched5), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched5Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched5PrizeFund), lottoResult, value);
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched5Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched5PrizeFund), lottoResult, value);
}
break;
break;
#endregion
#region Match 5 + Bonus
case LotteryTableRow.Match5Bonus:
if (columnTitle == LotteryTableRow.Winners)
try
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched5PlusBonus), lottoResult, value);
if (columnTitle == LotteryTableRow.Winners)
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched5PlusBonus), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched5PlusBonusPrize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched5PlusBonusPrizeFund), lottoResult, value);
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched5PlusBonusPrize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched5PlusBonusPrizeFund), lottoResult, value);
}
break;
break;
#endregion
#region Match 6
case LotteryTableRow.Match6:
if (columnTitle == LotteryTableRow.Winners)
try
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched6), lottoResult, value);
if (columnTitle == LotteryTableRow.Winners)
{
PropertyManager.SetProperty(nameof(lottoResult.TotalMatched6), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched6Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched6PrizeFund), lottoResult, value);
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
if (columnTitle == LotteryTableRow.PrizePerWinner)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched6Prize), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.Matched6PrizeFund), lottoResult, value);
}
break;
break;
#endregion
#region Totals
case LotteryTableRow.Total:
if (columnTitle == LotteryTableRow.Winners)
try
{
PropertyManager.SetProperty(nameof(lottoResult.TotalWinners), lottoResult, value);
if (columnTitle == LotteryTableRow.Winners)
{
PropertyManager.SetProperty(nameof(lottoResult.TotalWinners), lottoResult, value);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.TotalPrizeFund), lottoResult, value);
}
}
catch (Exception ex)
{
// ToDo: _logger.LogError
throw new Exception(ex.Message);
}
if (columnTitle == LotteryTableRow.PrizeFundAmount)
{
PropertyManager.SetProperty(nameof(lottoResult.TotalPrizeFund), lottoResult, value);
}
break;
break;
#endregion
}
}
@@ -419,7 +536,7 @@ namespace lottery_co_uk_scraper.NationalLottery
var textNodes = htmlDoc.DocumentNode.DescendantsAndSelf().Where(n => n.NodeType == HtmlNodeType.Text);
var numericValues = textNodes.SelectMany(n => Regex.Matches(n.InnerHtml, @"(\d+)").Cast<Match>())
var numericValues = textNodes.SelectMany(n => MyRegex().Matches(n.InnerHtml).Cast<Match>())
.Select(match => int.Parse(match.Groups[1].Value))
.ToList();
@@ -449,7 +566,6 @@ namespace lottery_co_uk_scraper.NationalLottery
string columnTitle = prizePerWinnerNode.Attributes["data-title"].Value;
// Now you can use regularPrizePerWinner and rolldownPrizePerWinner as needed
Console.WriteLine($"Prize per winner ({sectionTitle}): {regularPrizePerWinner}");
Console.WriteLine($"Rolldown Prize per winner ({sectionTitle}): {rolldownPrizePerWinner}");

View File

@@ -11,7 +11,6 @@ namespace lottery_co_uk_scraper.NationalLottery
try
{
string html = await client.GetStringAsync(url);
var doc = new HtmlDocument();
doc.LoadHtml(html);
@@ -26,7 +25,6 @@ namespace lottery_co_uk_scraper.NationalLottery
DrawBalls.ProcessBonusBalls(doc, lottoResult);
DrawMachine.ProcessMachineUsed(doc, lottoResult);
DrawWinnerInformation.ProcessWinnersTable(doc, lottoResult);
DrawStatus.ProcessRollover(doc, lottoResult);
CommitToDatabase.SaveModelToDatabase(lottoResult);
}
@@ -38,27 +36,6 @@ namespace lottery_co_uk_scraper.NationalLottery
{
Console.WriteLine($"An error occurred: {ex.Message}");
}
finally
{
//client.Dispose();
}
}
public static class LotteryTableRow
{
// ToDo: do away with this or put it somewhere more logical?
public const string Match2 = "Match 2";
public const string Match3 = "Match 3";
public const string Match4 = "Match 4";
public const string Match5 = "Match 5";
public const string Match5Bonus = "Match 5 plus Bonus";
public const string Match6 = "Match 6";
public const string Total = "Totals";
public const string Winners = "Winners";
public const string PrizePerWinner = "Prize Per Winner";
public const string PrizeFundAmount = "Prize Fund Amount";
public const string BallSetUsed = "ballSetUsed";
public const string BallsDrawn= "ballsDrawn";
}
}
}

View File

@@ -21,7 +21,7 @@ namespace lottery_co_uk_scraper
foreach (string extractedUrl in extractedUrls)
{
await Lotto.GetLottoNumbers(extractedUrl, client);
//await Lotto.GetLottoNumbers(extractedUrl, client);
}
}
}

View File

@@ -4,31 +4,32 @@ namespace lottery_co_uk_scraper.Utilities
{
internal partial class URLExtractor
{
[GeneratedRegex(@"<a\s+href=""([^""]+)""")]
private static partial Regex MyRegex();
public static async Task<List<string>> ExtractUrlsAsync(string url)
{
List<string> urls = new List<string>();
List<string> urls = [];
using (HttpClient client = new HttpClient())
using (HttpClient client = new())
{
string content = await client.GetStringAsync(url);
MatchCollection matches = MyRegex().Matches(content);
foreach (Match match in matches)
foreach (Match match in matches.Cast<Match>())
{
string capturedUrl = match.Groups[1].Value;
if (capturedUrl.StartsWith(""))
if (capturedUrl.StartsWith("") || capturedUrl.StartsWith(""))
{
string modifiedUrl = "" + capturedUrl;
urls.Add(modifiedUrl);
}
}
}
urls.Reverse();
return urls;
}
[GeneratedRegex(@"<a\s+href=""([^""]+)""")]
private static partial Regex MyRegex();
}
}

View File

@@ -9,8 +9,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.58" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
<PackageReference Include="HtmlAgilityPack" Version="1.11.59" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
@@ -21,4 +21,11 @@
<ProjectReference Include="..\lottery-co-uk-scraper.data\lottery-co-uk-scraper.data.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="EuroMillions\" />
<Folder Include="NationalLottery\" />
<Folder Include="SetForLife\" />
<Folder Include="Thunderball\" />
</ItemGroup>
</Project>