// Create Product with latest data public async Task <Product> Create(string ASIN, string cacheFolderPath) { // 商品ページのドキュメント AngleSharp.Dom.IDocument document = await Tools.GetDocument(ASIN); // 商品名 string productName = document.QuerySelector("#productTitle").TextContent.Trim(); // 元値 var referencePriceNode = document.QuerySelector("#priceblock_ourprice"); int?referencePrice = null; if (referencePriceNode != null) { referencePrice = referencePriceNode.TextContent.PriceToValue(); } // 商品画像 string imgFilePath = cacheFolderPath + ASIN + ".jpg"; await Tools.DownloadProductImage(ASIN, imgFilePath, document); // 新しいProductインスタンスを作成する Product product = new Product(ASIN, productName, referencePrice); // 未設定のデータを設定する product = await Update(product, document); return(product); }
public string ExtractTitle(AngleSharp.Dom.IDocument doc, bool isMobile) { AngleSharp.Dom.IElement cell; cell = isMobile ? doc.QuerySelector(Constants.Wikipedia.ArticleTitle.TITLE_MOBILE) : doc.QuerySelector(Constants.Wikipedia.ArticleTitle.TITLE_DESKTOP); return(cell != null ? cell.TextContent : string.Empty); }
/// <summary> /// Определяет текущуюю страницу из параметра внутри DocumentElement.BaseUrl.Query /// Получает ссылку на следующую страницу из пагинатора /// </summary> /// <param name="document"></param> /// <returns>Возвращает ссылку на следующую страницу. String.Empty если страница последняя или единственная.</returns> private static string GetNextPageUrl(AngleSharp.Dom.IDocument document) { string nextPageUrl = ""; if (document?.BaseUrl?.Query == null) { return(nextPageUrl); } var nextPageButton = document.QuerySelector("span[data-marker='pagination-button/next']"); //проверяем наличие кнопки "След." на странице if (nextPageButton == null) { return(nextPageUrl); } //т.к. в самой кнопке "След." url не хранится нужно лезть скрытый пагинатор с ссылками //сначала проверяем текущий query в url на наличие параметра текущей страницы, если нет по умолчанию 1 ushort currentPageId = ushort.TryParse( HttpUtility.ParseQueryString(document.DocumentElement.BaseUrl.Query).Get("p"), out currentPageId) ? currentPageId : (ushort)1; //находим в скрытом пагинаторе ссылку на следующую страницу var pageButton = document.QuerySelectorAll("a.pagination-page").Where(e => e.InnerHtml == $"{currentPageId + 1}").FirstOrDefault(); if (pageButton != null) { nextPageUrl = document.Origin + pageButton.GetAttribute("href"); } return(nextPageUrl); }
public async static Task <bool> DownloadProductImage(string ASIN, string imageFilePath, AngleSharp.Dom.IDocument document = null, CookieContainer cookies = null) { if (document == null) { if (cookies != null) { document = await GetDocument(ASIN); } else { return(false); } } if (File.Exists(imageFilePath) == false) { string imageDataBase64 = document.QuerySelector("#landingImage").GetAttribute("src").Trim(); imageDataBase64 = imageDataBase64.Remove(0, imageDataBase64.IndexOf("base64") + 7); Byte[] imageDataBytes = Convert.FromBase64String(imageDataBase64); using (var fileStream = new FileStream(imageFilePath, FileMode.Create)) { fileStream.Write(imageDataBytes, 0, imageDataBytes.Length); fileStream.Flush(); } return(true); } return(false); }
// 商品ページのHTMLから商品の更新可能性のある情報を取得、更新する public async Task <Product> Update(Product product, AngleSharp.Dom.IDocument document = null) { // 新品/中古品のクエリを読み出す New/Used int newStockCount = 0; int?newStockPrice = null; int usedStockCount = 0; int?usedStockPrice = null; // ドキュメントが指定されていない場合、新しいドキュメントを取りに行く if (document == null) { document = await Tools.GetDocument(product.ASIN); } var stockNodes = document.QuerySelectorAll("#olp_feature_div > div > span:not(.a-color-base)"); if (stockNodes.Length != 0) { foreach (var stockNode in stockNodes) { // 新品のクエリだけを読み出し、在庫と最低価格を抜き出す(存在しない場合有り) if (stockNode.QuerySelector("a").TextContent.IndexOf("新品の出品:") > -1) { var newStock = stockNode; newStockCount = Convert.ToInt32(newStock.QuerySelector("a").TextContent.Trim().Replace("新品の出品:", "")); newStockPrice = newStock.QuerySelector("span.a-color-price").TextContent.PriceToValue(); } // 中古品のクエリだけを読み出し、在庫と最低価格を抜き出す(存在しない場合有り) if (stockNode.QuerySelector("a").TextContent.IndexOf("中古品の出品:") > -1) { var usedStock = stockNode; usedStockCount = Convert.ToInt32(usedStock.QuerySelector("a").TextContent.Trim().Replace("中古品の出品:", "")); usedStockPrice = usedStock.QuerySelector("span.a-color-price").TextContent.PriceToValue(); } } } else { stockNodes = document.QuerySelectorAll("#olp_feature_div > div > a"); if (stockNodes.Length != 0) { // 取得エラー (在庫表記がおかしい) newStockCount = -1; newStockPrice = null; usedStockCount = -1; usedStockPrice = null; } else { // 新品/中古品表記が無い = 在庫が無い newStockCount = 0; newStockPrice = null; usedStockCount = 0; usedStockPrice = null; } } // 現在価格を抜き出す var amazonPriceNode = document.QuerySelector("#priceblock_ourprice"); int?amazonPrice = null; if (amazonPriceNode != null) { amazonPrice = amazonPriceNode.TextContent.PriceToValue(); } // 割引価格を抜き出す(存在しない場合有り) var priceSavingNode = document.QuerySelector(".priceBlockSavingsString"); int?priceSaving = null; if (priceSavingNode != null) { string _priceSaving = priceSavingNode.TextContent.Trim(); // 割引価格から値のみ抜き出す Match match = Regex.Match(_priceSaving, @"¥\d{1,3}(,\d{1,3})*\b"); priceSaving = match.Value.Substring(1).PriceToValue(); } // Amazonからの出品が使用可能かどうか調べる string merchantText = document.QuerySelector("#merchant-info").TextContent; // 総合ランキング var rankInfo = document.QuerySelector("#SalesRank > .value").FirstChild; string ranking = rankInfo.TextContent.Trim(); ranking = ranking.Remove(ranking.Length - 1, 1); // 商品在庫状態 string status = document.QuerySelector("#availability > span").TextContent.Trim(); // Amazon出品 > 新品 > 中古の順で表示する価格を決定する int?price = amazonPrice; if (amazonPrice == null) { if (newStockPrice == null) { price = usedStockPrice; } else { price = newStockPrice; } } product.Price = price; product.PriceHistory[DateTime.Now] = price; product.PriceSaving = priceSaving; product.SetStockInfo(newStockPrice, newStockCount, usedStockPrice, usedStockCount); product.MerchantStatus = this.Status(merchantText); product.Ranking = ranking; product.Status = status; return(product); }
public async Task Stats(int story_id = 0) { string fullQueryLink = royalroadl_domain + "fiction/" + story_id; var embed = new EmbedBuilder(); StringBuilder error_message = new StringBuilder(); AngleSharp.Dom.IDocument document = null; try { var config = Configuration.Default.WithDefaultLoader(); document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: searching the site"); } var existElem = document.QuerySelector("div.col-md-12.page-404"); if (existElem != null) { embed.WithErrorColor().WithDescription($"The story with the ID \"{story_id}\" does not exist."); } else { // title var titleElem = document.QuerySelector("h2.font-white"); string titleText = ""; try { titleText = titleElem.Text(); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: title"); } // author var authorElem = document.QuerySelector("h4.font-white"); string authorText = ""; try { authorText = authorElem.Text(); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: author"); } // cover art var imageElem = document.QuerySelector("img.img-offset"); string imageUrl = ""; try { imageUrl = ((IHtmlImageElement)imageElem).Source; } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: image"); } var display = new StringBuilder(); display.AppendLine($"**{titleText}** {authorText}\n"); // stats base var div_stats_elems = document.QuerySelectorAll("div.stats-content > div.col-sm-6"); // score var score_parser = new HtmlParser(); var score_p_elem = score_parser.Parse(div_stats_elems[0].InnerHtml); var score_elems = score_p_elem.QuerySelectorAll("span.star"); display.AppendLine("**Scores**"); try { foreach (var score_elm in score_elems) { var s_title = score_elm.GetAttribute("data-original-title"); var s_stars = score_elm.GetAttribute("data-content"); display.AppendLine($"`{s_title}:` {s_stars} 🌟"); } } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: scores"); } display.AppendLine(""); // count var count_parser = new HtmlParser(); var count_p_elem = score_parser.Parse(div_stats_elems[1].InnerHtml); var count_elems = count_p_elem.QuerySelectorAll("li.bold.uppercase"); display.AppendLine("**Count**"); try { for (var i = 0; i < count_elems.Count();) { var str = $"`{count_elems[i++].Text()}`"; str += $" {count_elems[i++].Text()}"; display.AppendLine(str); } } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: stats"); } embed.WithOkColor().WithTitle(titleText); embed.WithDescription(display.ToString()); embed.WithUrl(fullQueryLink); embed.WithImageUrl(imageUrl); } try { await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: sending story message"); } if (!string.IsNullOrWhiteSpace(error_message.ToString().Trim())) { await Context.Channel.EmbedAsync(new EmbedBuilder().WithErrorColor().WithTitle("Error").WithDescription(error_message.ToString())).ConfigureAwait(false); } }
public async Task Story(int story_id = 0) { string fullQueryLink = royalroadl_domain + "fiction/" + story_id; var embed = new EmbedBuilder(); StringBuilder error_message = new StringBuilder(); AngleSharp.Dom.IDocument document = null; try { var config = Configuration.Default.WithDefaultLoader(); document = await BrowsingContext.New(config).OpenAsync(fullQueryLink); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: searching the site"); } var existElem = document.QuerySelector("div.col-md-12.page-404"); if (existElem != null) { embed.WithErrorColor().WithDescription($"The story with the ID \"{story_id}\" does not exist."); } else { // title var titleElem = document.QuerySelector("h2.font-white"); string titleText = ""; try { titleText = titleElem.Text(); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: title"); } // author var authorElem = document.QuerySelector("h4.font-white"); string authorText = ""; try { authorText = authorElem.Text(); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: author"); } // description/synopsis var descElem = document.QuerySelector("div.hidden-content"); string descText = ""; try { descText = descElem.InnerHtml.Replace("<hr>", "----------------").Replace("<br>", "\n"); descText = Regex.Replace(descText, "<.*?>", string.Empty); //await Context.Channel.EmbedAsync(new EmbedBuilder().WithDescription(descText)).ConfigureAwait(false); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: description"); } // cover art var imageElem = document.QuerySelector("img.img-offset"); string imageUrl = ""; try { imageUrl = ((IHtmlImageElement)imageElem).Source; } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: image"); } // tags var tagsElem = document.QuerySelector("span.tags"); List <string> tagsList = null; try { string tagsText = Regex.Replace(tagsElem.InnerHtml, "<.*?>", string.Empty); tagsList = tagsText.Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList(); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: tags"); } /* * StringBuilder sb = new StringBuilder(); * for (var i = 0; i < tagsList.Count; i++) * { * if (!string.IsNullOrWhiteSpace(tagsList[i])) * sb.AppendLine(tagsList[i] + " " + tagsList.Count); * } * await Context.Channel.SendConfirmAsync($"{sb}").ConfigureAwait(false); */ embed.WithOkColor().WithTitle(titleText); string title = $"**{titleText}** {authorText}\n\n"; string description = "**Description**\n"; string desc = descText.Trim(); if (desc.Length > 0) { description += desc + "\n\n"; } else { description += "*No description given*\n\n"; } string tags = "**Tags**\n"; string tags_line = ""; foreach (var item in tagsList) { if (!string.IsNullOrWhiteSpace(item)) { tags_line += item + ", "; } } if (tags_line.Length > 0) { tags_line = tags_line.Substring(0, tags_line.Length - 2); tags += tags_line + "\n\n"; } else { tags += "*No tags declared*\n\n"; } embed.WithDescription(title + description + tags); embed.WithUrl(fullQueryLink); embed.WithImageUrl(imageUrl); } try { await Context.Channel.EmbedAsync(embed).ConfigureAwait(false); } catch (Exception ex) { error_message.AppendLine($"Message: {ex.Message}\nSource: sending story message"); } if (!string.IsNullOrWhiteSpace(error_message.ToString().Trim())) { await Context.Channel.EmbedAsync(new EmbedBuilder().WithErrorColor().WithTitle("Error").WithDescription(error_message.ToString())).ConfigureAwait(false); } }