// 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);
 }
示例#3
0
        /// <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);
        }
示例#6
0
        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);
            }
        }
示例#7
0
        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);
            }
        }