diff --git a/Rehau.Sku.Assist-AddIn-packed.xll b/Rehau.Sku.Assist-AddIn-packed.xll deleted file mode 100644 index aea355f..0000000 Binary files a/Rehau.Sku.Assist-AddIn-packed.xll and /dev/null differ diff --git a/Rehau.Sku.Assist.csproj b/Rehau.Sku.Assist.csproj index 6667639..cc83173 100644 --- a/Rehau.Sku.Assist.csproj +++ b/Rehau.Sku.Assist.csproj @@ -85,6 +85,7 @@ + diff --git a/Source/Assistant/HttpClientUtil.cs b/Source/Assistant/HttpClientUtil.cs new file mode 100644 index 0000000..f9c144b --- /dev/null +++ b/Source/Assistant/HttpClientUtil.cs @@ -0,0 +1,74 @@ +using AngleSharp; +using AngleSharp.Dom; +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using System.Text; + +namespace Rehau.Sku.Assist +{ + static class HttpClientUtil + { + private static HttpClient _httpClient = AddIn.httpClient; + + public async static Task GetContentByUriAsync(Uri uri) + { + ServicePointManager.SecurityProtocol = + SecurityProtocolType.Tls12 | + SecurityProtocolType.Tls11 | + SecurityProtocolType.Tls; + + return await _httpClient.GetStringAsync(uri); + } + + public async static Task ContentToDocAsync(Task content) + { + IConfiguration config = Configuration.Default; + IBrowsingContext context = BrowsingContext.New(config); + + return await context.OpenAsync(req => req.Content(content.Result)); + } + + public static Uri ConvertToUri(this string request, ResponseOrder order) + { + UriBuilder baseUri = new UriBuilder("https", "shop-rehau.ru"); + + baseUri.Path = "/catalogsearch/result/index/"; + string cleanedRequest = request._CleanRequest(); + + switch (order) + { + case ResponseOrder.Relevance: + baseUri.Query = "dir=asc&order=relevance&q=" + cleanedRequest; + break; + case ResponseOrder.Name: + baseUri.Query = "dir=asc&order=name&q=" + cleanedRequest; + break; + case ResponseOrder.Price: + baseUri.Query = "dir=asc&order=price&q=" + cleanedRequest; + break; + case ResponseOrder.Series: + baseUri.Query = "dir=asc&order=sch_product_series&q=" + cleanedRequest; + break; + case ResponseOrder.NoSettings: + baseUri.Query = "q=" + cleanedRequest; + break; + default: + throw new ArgumentException(); + } + + return baseUri.Uri; + } + + private static string _CleanRequest(this string input) + { + return new StringBuilder(input) + .Replace("+", " plus ") + .Replace("РХ", "") + .Replace("º", " ") + .Replace(".", " ") + .ToString(); + } + } +} \ No newline at end of file diff --git a/Source/Assistant/IProduct.cs b/Source/Assistant/IProduct.cs index aca3ff5..de0eccf 100644 --- a/Source/Assistant/IProduct.cs +++ b/Source/Assistant/IProduct.cs @@ -1,9 +1,11 @@ -namespace Rehau.Sku.Assist +using System; + +namespace Rehau.Sku.Assist { interface IProduct { string Sku { get; } string Name { get; } - string Uri { get; } + Uri Uri { get; } } } diff --git a/Source/Assistant/Product.cs b/Source/Assistant/Product.cs index 17a7065..22905af 100644 --- a/Source/Assistant/Product.cs +++ b/Source/Assistant/Product.cs @@ -1,11 +1,12 @@ -namespace Rehau.Sku.Assist +using System; + +namespace Rehau.Sku.Assist { public class Product : IProduct { public string Sku { get; } public string Name { get; } - - public string Uri => throw new System.NotImplementedException(); + public Uri Uri { get; } public Product(string sku, string name) { @@ -13,6 +14,13 @@ Name = name; } + public Product(string sku, string name, string uri) + { + Sku = sku; + Name = name; + Uri = new Uri(uri); + } + public override string ToString() { return $"{this.Name} ({this.Sku})"; diff --git a/Source/Assistant/SkuAssist.cs b/Source/Assistant/SkuAssist.cs index 152dbbb..121bc88 100644 --- a/Source/Assistant/SkuAssist.cs +++ b/Source/Assistant/SkuAssist.cs @@ -1,80 +1,62 @@ -using AngleSharp; -using AngleSharp.Dom; +using AngleSharp.Dom; +using AngleSharp.Html.Dom; using System; using System.Linq; -using System.Net; -using System.Net.Http; using System.Threading.Tasks; +using System.Text.RegularExpressions; namespace Rehau.Sku.Assist { + public enum ResponseOrder + { + NoSettings, + Relevance, + Name, + Price, + Series + } + static class SkuAssist { - private static HttpClient _httpClient; - private enum ResponseOrder + public static async Task GetProduct(string request) { - NoSettings, - Relevance, - Name, - Price, - Series - } - private static void _EnsureHttpClientRunning() - { - if (_httpClient == null) - _httpClient = new HttpClient(); + Uri uri = request.ConvertToUri(ResponseOrder.NoSettings); + + Task contentTask = Task.Run(() => HttpClientUtil.GetContentByUriAsync(uri)); + Task documentTask = await contentTask.ContinueWith(content => HttpClientUtil.ContentToDocAsync(content)); + + IProduct product = await documentTask.ContinueWith(doc => SkuAssist.GetFirstProduct(doc.Result)); + return product; } - public async static Task GetContent(string request) + public static IProduct GetFirstProduct(IDocument doc) { - Uri uri = _ConvertToUri(request, ResponseOrder.NoSettings); - _EnsureHttpClientRunning(); - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; - - return await _httpClient.GetStringAsync(uri); - } - - public async static Task GetDocument(Task source) - { - IConfiguration config = Configuration.Default; - IBrowsingContext context = BrowsingContext.New(config); - - return await context.OpenAsync(req => req.Content(source.Result)); - } - - public static IProduct GetProductFromDocument(IDocument document) - { - return document + return doc .All .Where(e => e.ClassName == "product-item__desc-top") - .Select(e => new Product(e.Children[0].TextContent, e.Children[1].TextContent.Trim(new[] { '\n', ' ' }))) + .Where(e => Regex.IsMatch(e.Children[0].TextContent, @"\d{11}", RegexOptions.None)) + .Select(e => + new Product(e.Children[0].TextContent, + e.Children[1].TextContent.Trim(new[] { '\n', ' ' }))) .FirstOrDefault(); } - private static Uri _ConvertToUri(this string request, ResponseOrder order) + public static Uri GetFirstResultLink(IDocument doc) { - string cleanedRequest = request._CleanRequest(); - switch (order) - { - case ResponseOrder.Relevance: - return new Uri("https://shop-rehau.ru/catalogsearch/result/index/?dir=asc&order=relevance&q=" + cleanedRequest); - case ResponseOrder.Name: - return new Uri("https://shop-rehau.ru/catalogsearch/result/index/?dir=asc&order=name&q=" + cleanedRequest); - case ResponseOrder.Price: - return new Uri("https://shop-rehau.ru/catalogsearch/result/index/?dir=asc&order=price&q=" + cleanedRequest); - case ResponseOrder.Series: - return new Uri("https://shop-rehau.ru/catalogsearch/result/index/?dir=asc&order=sch_product_series&q=" + cleanedRequest); - case ResponseOrder.NoSettings: - return new Uri("https://shop-rehau.ru/catalogsearch/result/?q=" + cleanedRequest); - default: - throw new ArgumentException(); - } + var link = new Uri(doc + .Links + .Where(e => e.ClassName == "product-item__title-link js-name") + .Select(l => ((IHtmlAnchorElement)l).Href) + .FirstOrDefault()); + return link; } - private static string _CleanRequest(this string input) + + public static string GetFistResultImageLink(IDocument doc) { - return input.Replace("+", " plus "); + var imageSource = doc.Images + .Where(x => x.ClassName == "product-item__image") + .FirstOrDefault(); + return imageSource != null ? imageSource.Source : "Нет ссылки"; } } -} - - +} \ No newline at end of file diff --git a/Source/ExcelDNA/AddIn.cs b/Source/ExcelDNA/AddIn.cs index dd99667..0505e5b 100644 --- a/Source/ExcelDNA/AddIn.cs +++ b/Source/ExcelDNA/AddIn.cs @@ -1,13 +1,17 @@ using ExcelDna.Integration; using ExcelDna.Registration; +using System.Net.Http; namespace Rehau.Sku.Assist { public class AddIn : IExcelAddIn { + public static HttpClient httpClient; + public void AutoOpen() { RegisterFunctions(); + httpClient = new HttpClient(); } public void AutoClose() diff --git a/Source/ExcelDNA/Functions.cs b/Source/ExcelDNA/Functions.cs index a282e3e..db882c5 100644 --- a/Source/ExcelDNA/Functions.cs +++ b/Source/ExcelDNA/Functions.cs @@ -1,19 +1,36 @@ -using AngleSharp.Dom; -using ExcelDna.Integration; -using System.Net.Http; +using ExcelDna.Integration; using System.Threading.Tasks; +using System.Runtime.Caching; namespace Rehau.Sku.Assist { public class Functions { [ExcelFunction] - public static async Task RAUNAME(string request) + public static object RAUNAME(string request) { - Task contentTask = Task.Run(() => SkuAssist.GetContent(request)); - Task documentTask = await contentTask.ContinueWith(content => SkuAssist.GetDocument(content)); - IProduct product = await documentTask.ContinueWith(doc => SkuAssist.GetProductFromDocument(doc.Result)); - return product != null ? product.ToString() : "Не найдено"; + if (MemoryCache.Default.Contains(request)) + return MemoryCache.Default[request].ToString(); + + else + { + object result = ExcelAsyncUtil.Run("Rauname", new[] { request }, + delegate + { + Task product = Task.Run(() => SkuAssist.GetProduct(request)); + return product.Result; + }); + + if (Equals(result, ExcelError.ExcelErrorNA)) + { + return "Загрузка..."; + } + else + { + MemoryCache.Default.Add(request, result, System.DateTime.Now.AddMinutes(10)); + return result == null ? "Не найдено" : result.ToString(); + } + } } } } \ No newline at end of file diff --git a/Tests/SkuAssistTests.cs b/Tests/SkuAssistTests.cs index fc47c41..d70ac1c 100644 --- a/Tests/SkuAssistTests.cs +++ b/Tests/SkuAssistTests.cs @@ -2,14 +2,14 @@ namespace Rehau.Sku.Assist.Tests { - [TestFixture] - public class SkuAssistTests - { - [Test] - public async void BaseTest() - { - var result = await Functions.RAUNAME("160001"); - Assert.AreEqual("Надвижная гильза REHAU RAUTITAN РХ (11600011001)", result); - } - } + //[TestFixture] + //public class SkuAssistTests + //{ + // [Test] + // public async void BaseTest() + // { + // var result = await Functions.RAUNAME("160001"); + // Assert.AreEqual("Надвижная гильза REHAU RAUTITAN РХ (11600011001)", result); + // } + //} }