From 1cf48674ad1fdead44a3ad84296f5b8cf394bfc0 Mon Sep 17 00:00:00 2001 From: Viacheslav Titov Date: Thu, 4 Apr 2019 21:22:53 +0300 Subject: [PATCH 1/2] Basic Item Build crawler for OP.GG --- .../Data/Providers/OpGGProvider.cs | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/Legendary Rune Maker/Data/Providers/OpGGProvider.cs b/Legendary Rune Maker/Data/Providers/OpGGProvider.cs index 4750cad..7c416b3 100644 --- a/Legendary Rune Maker/Data/Providers/OpGGProvider.cs +++ b/Legendary Rune Maker/Data/Providers/OpGGProvider.cs @@ -21,11 +21,14 @@ internal class OpGGProvider : Provider }; public override string Name => "OP.GG"; - public override Options ProviderOptions => Options.RunePages | Options.SkillOrder; + public override Options ProviderOptions => Options.ItemSets | Options.RunePages | Options.SkillOrder; private static string GetRoleUrl(int championId, Position position) => $"https://op.gg/champion/{Riot.GetChampion(championId).Key}/statistics/{PositionToName[position]}"; + private static string GetItemUrl(int championId, Position position) + => $"https://op.gg/champion/{Riot.GetChampion(championId).Key}/statistics{(string.IsNullOrEmpty(PositionToName[position]) ? "" : $"/{PositionToName[position]}")}/item"; + public override async Task GetPossibleRoles(int championId) { return PositionToName.Keys.Except(new []{ Position.Fill }).ToArray(); @@ -83,5 +86,70 @@ public override async Task GetSkillOrder(int championId, Position positi return $"({string.Join(">", tips)}) {new string(slong)}"; } + + public override async Task GetItemSet(int championId, Position position) + { + var test = GetItemUrl(championId, position); + var doc = new HtmlDocument(); + doc.LoadHtml(await WebCache.String(GetItemUrl(championId, position), soft: true)); + + var contentTables = doc.DocumentNode.Descendants("table") + .Where(o => o.HasClass("champion-stats__table")).ToList(); + + var starterItem = GetRows("Starter Items"); + var coreItems = GetRows("Core Build"); + var bootsItem = GetRows("Boots"); + + var blocks = new List(); + AddBlockEntry(starterItem, "Starter Items"); + AddBlockEntry(coreItems, "Core Build"); + AddBlockEntry(bootsItem, "Boots"); + + return new ItemSet + { + Champion = championId, + Name = this.Name + ": " + position, + Position = position, + Blocks = blocks.ToArray() + }; + + List GetRows(string tableHeader) + { + var table = contentTables.FirstOrDefault(d1 => d1.Descendants("th").Any(d2 => d2.InnerText.Contains(tableHeader))); + return table?.Descendants("tr").Where(tr => tr.ChildNodes.Any(td => td.HasClass("champion-stats__table__cell"))).ToList(); + } + + void AddBlockEntry(List nodes, string blockName) + { + foreach (var node in nodes) + { + var items = new List(); + var itemCounter = 0; + node.Descendants("img").ToList().ForEach(n => + { + if (n.ParentNode.HasClass("champion-stats__list__item")) + { + itemCounter++; + if (int.TryParse(Regex.Match(n.Attributes["src"].Value, "/item/(\\d+).png").Groups[1].Value, out var item)) + { + items.Add(item); + } + } + }); + if (items.Count != itemCounter) + continue; + + var pickRate = node.Descendants("td").FirstOrDefault(td => td.HasClass("champion-stats__table__cell--pickrate"))?.InnerText ?? ""; + pickRate = Regex.Replace(pickRate, @"[^\w|\.|%]", ""); + var matches = Regex.Match(pickRate, @"(\d{1,2}\.\d{2})%(\d+)"); + var winRate = node.Descendants("td").FirstOrDefault(td => td.HasClass("champion-stats__table__cell--winrate"))?.InnerText; + blocks.Add(new ItemSet.SetBlock + { + Name = $"{blockName} | PickRate {matches?.Groups[1].Value}% | PickCount {matches?.Groups[2].Value} | WinRate {winRate}", + Items = items.ToArray() + }); + } + } + } } } From b15935e40ae27b9c266a9bf5ecf0e5d92526e3a4 Mon Sep 17 00:00:00 2001 From: Viacheslav Titov Date: Fri, 5 Apr 2019 03:21:17 +0300 Subject: [PATCH 2/2] Fill role -> popular role --- .../Data/Providers/OpGGProvider.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Legendary Rune Maker/Data/Providers/OpGGProvider.cs b/Legendary Rune Maker/Data/Providers/OpGGProvider.cs index 7c416b3..cc102b4 100644 --- a/Legendary Rune Maker/Data/Providers/OpGGProvider.cs +++ b/Legendary Rune Maker/Data/Providers/OpGGProvider.cs @@ -87,19 +87,33 @@ public override async Task GetSkillOrder(int championId, Position positi return $"({string.Join(">", tips)}) {new string(slong)}"; } + public async Task GetPopularPosition(int championId) + { + var doc = new HtmlDocument(); + doc.LoadHtml(await WebCache.String(GetItemUrl(championId, Position.Fill), soft: true)); + var popularPositionNode = doc.DocumentNode.Descendants("link") + .FirstOrDefault(l => l.Attributes["rel"]?.Value == "canonical") + .Attributes["href"]?.Value; + var popularPosition = Regex.Match(popularPositionNode, @"/statistics/(\w+)"); + return PositionToName.FirstOrDefault(p => p.Value.Equals(popularPosition.Groups[1].Value, StringComparison.CurrentCultureIgnoreCase)).Key; + } + public override async Task GetItemSet(int championId, Position position) { - var test = GetItemUrl(championId, position); + if (position == Position.Fill) + { + position = await GetPopularPosition(championId); + } + var doc = new HtmlDocument(); doc.LoadHtml(await WebCache.String(GetItemUrl(championId, position), soft: true)); - var contentTables = doc.DocumentNode.Descendants("table") .Where(o => o.HasClass("champion-stats__table")).ToList(); var starterItem = GetRows("Starter Items"); var coreItems = GetRows("Core Build"); var bootsItem = GetRows("Boots"); - + var blocks = new List(); AddBlockEntry(starterItem, "Starter Items"); AddBlockEntry(coreItems, "Core Build");