Exemple #1
0
        /// <summary>
        /// 全ページのアイテム情報を取得する
        /// </summary>
        /// <param name="saleInformation"></param>
        /// https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html?ItemSearch.html
        bool ItemSearchAll(SaleInformation saleInformation)
        {
            int  page   = 0;
            bool result = false;

            do
            {
                Task.Delay(requestWaitTimerMSec).Wait();
                page++;
                result = ItemSearch(saleInformation, page);
                if (result == false)
                {
                    break;
                }

                // 残りページなし
                if ((saleInformation.TotalResults - page * 10) <= 0)
                {
                    break;
                }

                // AWS の仕様上、10ページまでしか取得できない
            } while (page < 10);

            return(result);
        }
Exemple #2
0
        /// <summary>
        /// セールページをスクレイピングしてセール期間を判別
        /// </summary>
        /// <param name="saleInformation"></param>
        /// <returns></returns>
        public (string startDate, string endDate) ExtractSalePeriod(SaleInformation saleInformation, Stream stream)
        {
            // 指定したサイトのHTMLをストリームで取得する

            // AngleSharp.Parser.Html.HtmlParserオブジェクトにHTMLをパースさせる
            var parser = new HtmlParser();
            var doc    = parser.Parse(stream);

            // ページによって h3 の場合も h4 の場合もある
            foreach (var tag in new[] { "h3", "h4" })
            {
                var elements = doc.QuerySelectorAll(tag);

                foreach (var element in elements)
                {
                    // 例:期間限定:8/18(金)~8/31(木)
                    var result = Regex.Match(element.InnerHtml, @"期間限定:(?<StartDate>.*?)(.*)~(?<EndDate>.*?)(.*)");

                    if (result.Success == true)
                    {
                        return(result.Groups["StartDate"].Value, result.Groups["EndDate"].Value);
                    }
                }
            }

            return(null, null);
        }
Exemple #3
0
        public void InsertTest()
        {
            using (var context = new KindleDbContext(fixture.DataSource))
            {
                var saleInformation = new SaleInformation
                {
                    Url   = "http://blogs.msdn.com/dotnet",
                    Items = new List <ItemDetail>
                    {
                        new ItemDetail {
                            Title = "Intro to C#"
                        },
                        new ItemDetail {
                            Title = "Intro to VB.NET"
                        },
                        new ItemDetail {
                            Title = "Intro to F#"
                        }
                    }
                };

                context.SaleInformations.Add(saleInformation);
                context.SaveChanges();
            }
        }
Exemple #4
0
        public void SetSalePeriodTest(int nowYear, int nowMonth, int nowDay, string startDate, string endDate, int count, int total, string expectedStartDate, string expectedEndDate)
        {
            var saleInformation = new SaleInformation();

            DateTime now = new DateTime(nowYear, nowMonth, nowDay);

            saleInformation.SetSalePeriod(now, startDate, endDate, count, total);
            Assert.Equal(expectedStartDate, saleInformation.StartDate.ToString("yyyy/MM/dd"));
            Assert.Equal(expectedEndDate, saleInformation.EndDate.ToString("yyyy/MM/dd"));
        }
Exemple #5
0
        /// <summary>
        /// セール期間を判別してセットする
        /// </summary>
        /// <param name="saleInformation"></param>
        /// <param name="count">現在何件目のセール情報</param>
        /// <param name="total">セール情報のトータル</param>
        void CheckSalePeriod(SaleInformation saleInformation, int count, int total)
        {
            if (saleInformation.Error == true)
            {
                return;
            }

            // タイトルから終了日を判別
            saleInformation.SetSalePeriod(DateTime.Now, null, ExtractEndDate(saleInformation.Name), count, total);
            if (saleInformation.EndDate != null)
            {
                if (saleInformation.EndDate < DateTime.Now)
                {
                    saleInformation.SaleFinished = true;
                }
                else
                {
                    saleInformation.SaleStarted = true;
                }
                return;
            }

            // セールページをスクレイピングしてセール期間を判別
            using (var stream = client.GetStreamAsync(GetAssociateLinkByBrowseNode(saleInformation.NodeId)).Result)
            {
                (var startDate, var endDate) = ExtractSalePeriod(saleInformation, stream);
                saleInformation.SetSalePeriod(DateTime.Now, startDate, endDate, count, total);
            }

            if (saleInformation.StartDate != null && saleInformation.EndDate != null)
            {
                if (saleInformation.EndDate < DateTime.Now)
                {
                    saleInformation.SaleFinished = true;
                }
                else if (saleInformation.StartDate < DateTime.Now)
                {
                    saleInformation.SaleStarted  = true;
                    saleInformation.SaleFinished = false;
                }
                return;
            }

            // ここまできたら、セールページは存在するが、タイトルからもセールページからもセール期間が判別できないので、
            // 何も処理しない
        }
Exemple #6
0
        public void GetSalePeriodTest()
        {
            var saleInformation = new SaleInformation();

            saleInformation.SaleStarted  = false;
            saleInformation.SaleFinished = false;
            Assert.Equal("不明", saleInformation.GetSalePeriod());

            saleInformation.SaleStarted = true;
            saleInformation.EndDate     = DateTime.Parse("2017/08/31");
            Assert.Equal("8/31まで", saleInformation.GetSalePeriod());

            saleInformation.StartDate = DateTime.Parse("2017/08/01");
            Assert.Equal("8/1~8/31", saleInformation.GetSalePeriod());

            saleInformation.SaleFinished = true;
            Assert.Equal("終了", saleInformation.GetSalePeriod());
        }
Exemple #7
0
        /// <summary>
        /// 投稿済みの記事を更新する
        /// </summary>
        void UpdateArticle(SaleInformation saleInformation)
        {
            try
            {
                var postInformation = blogger.UpdatePost(CreateArticle(saleInformation), new PostInformation()
                {
                    Url = saleInformation.Url, PostId = saleInformation.PostId
                });
                saleInformation.Url    = postInformation.Url;
                saleInformation.PostId = postInformation.PostId;

                logger?.LogInformation($"{saleInformation.Url}\n{saleInformation.PostId}");
            }
            catch (Exception e)
            {
                logger?.LogError("記事の更新失敗\n" + e.Message);
                throw;
            }
        }
Exemple #8
0
        /// <summary>
        /// ブログに投稿する
        /// </summary>
        void PostToBlog(SaleInformation saleInformation)
        {
            if (saleInformation.Error == true)
            {
                return;
            }

            try
            {
                var postInformation = blogger.InsertPost(CreateArticle(saleInformation));
                saleInformation.Url    = postInformation.Url;
                saleInformation.PostId = postInformation.PostId;

                logger?.LogInformation($"投稿完了\n{saleInformation.Url}\n{saleInformation.PostId}");
            }
            catch (Exception e)
            {
                logger?.LogError("投稿失敗\n" + e.Message);
                throw;
            }
        }
Exemple #9
0
        /// <summary>
        /// 記事の内容を作成する
        /// </summary>
        /// <param name="saleInformation"></param>
        /// <returns></returns>
        Article CreateArticle(SaleInformation saleInformation)
        {
            var article = new Article()
            {
                title = saleInformation.Name
            };

            // 既に終了済みだったらタイトルに記載する
            if (saleInformation.SaleFinished == true)
            {
                article.title = "【終了】" + article.title;
            }

            // タイトルからラベルを抽出
            article.labels = ExtractLabels(article.title);

            article.content += $@"<p>
            対象は{saleInformation.TotalResults}冊。<br>
            Amazon のセールページは<a class='amazon' href='{GetAssociateLinkByBrowseNode(saleInformation.NodeId)}' target='_blank'>こちら</a>。
            </p>";

            article.content += @"<!--more-->";

            // Bootstrap のグリッドシステムを使って配置する
            // スマホでは2列で、タブレット以上では4列で表示する
            int colMax = 4;

            article.content += "\n<div class=\"container-fluid\">\n";
            int count = 0;

            foreach (var item in saleInformation.Items)
            {
                // 4列ごとに row で括る
                if (count % colMax == 0)
                {
                    article.content += "<div class=\"row flex\">\n";
                }
                article.content += $@"
                <div class=""col-xs-6 col-sm-3 col-md-3 col-lg-3"">
                <a class='amazon' href='{item.DetailPageUrl}' target='_blank'><img src='{item.MediumImageUrl}' /></a><br>
                <a class='amazon' href='{item.DetailPageUrl}' target='_blank'>{item.Title}</a>
                </div>";
                article.content += "\n";
                if (count % colMax == colMax - 1)
                {
                    article.content += "</div>\n";
                }
                count++;
            }
            // アイテム数が4の倍数でない場合、最後の row が閉じられていないのでここで閉じる
            if (count % colMax != 0)
            {
                article.content += "</div>\n";
            }
            article.content += "</div>\n";

            if (saleInformation.TotalResults > 100)
            {
                article.content += $@"<p><a class='amazon' href='{GetAssociateLinkByBrowseNode(saleInformation.NodeId)}' target='_blank'>もっと見る</a></p>";
            }

            return(article);
        }
Exemple #10
0
        /// <summary>
        /// 指定したページのアイテム情報を取得する
        /// </summary>
        /// <param name="saleInformation"></param>
        /// https://images-na.ssl-images-amazon.com/images/G/09/associates/paapi/dg/index.html?ItemSearch.html
        bool ItemSearch(SaleInformation saleInformation, int page)
        {
            IDictionary <string, string> request = new Dictionary <string, String>
            {
                ["Service"]       = service,
                ["Version"]       = apiVersion,
                ["Operation"]     = "ItemSearch",
                ["SearchIndex"]   = "KindleStore",
                ["ResponseGroup"] = "Medium",
                ["BrowseNode"]    = saleInformation.NodeId,
                ["ItemPage"]      = page.ToString()
            };

            logger?.LogInformation($"商品情報取得開始({page}ページ目)");

            // リクエストを送信して xml を取得
            var result = GetXml(request);

            XmlDocument doc = new XmlDocument();

            doc.Load(result);

            XmlNamespaceManager xmlNsManager = new XmlNamespaceManager(doc.NameTable);

            xmlNsManager.AddNamespace("ns", ns);

            // エラー情報の取得
            try
            {
                var error = doc.SelectSingleNode("ns:ItemSearchResponse/ns:Items/ns:Request/ns:Errors/ns:Error/ns:Code", xmlNsManager).InnerText;
                logger?.LogWarning("エラー情報あり:" + error);
                saleInformation.Error = true;
            }
            catch (Exception)
            {
                //Console.WriteLine("エラー情報なし:" + e.Message);
                saleInformation.Error = false;
            }

            try
            {
                var totalResults = doc.SelectSingleNode("ns:ItemSearchResponse/ns:Items/ns:TotalResults", xmlNsManager).InnerText;
                saleInformation.TotalResults = int.Parse(totalResults);
            }
            catch (Exception e)
            {
                logger?.LogError("TotalResults取得不可:" + e.Message);
            }

            // 商品情報を取得
            try
            {
                XmlNodeList nodeList = doc.SelectNodes("ns:ItemSearchResponse/ns:Items/ns:Item", xmlNsManager);

                foreach (XmlNode node in nodeList)
                {
                    try
                    {
                        saleInformation.Items.Add(new ItemDetail()
                        {
                            Title           = node.SelectSingleNode("ns:ItemAttributes/ns:Title", xmlNsManager)?.InnerText,
                            PublicationDate = node.SelectSingleNode("ns:ItemAttributes/ns:PublicationDate", xmlNsManager)?.InnerText,
                            Content         = node.SelectSingleNode("ns:EditorialReviews/ns:EditorialReview/ns:Content", xmlNsManager)?.InnerText,
                            Asin            = node.SelectSingleNode("ns:ASIN", xmlNsManager)?.InnerText,
                            DetailPageUrl   = node.SelectSingleNode("ns:DetailPageURL", xmlNsManager)?.InnerText,
                            MediumImageUrl  = node.SelectSingleNode("ns:MediumImage/ns:URL", xmlNsManager)?.InnerText,
                            LargeImageUrl   = node.SelectSingleNode("ns:LargeImage/ns:URL", xmlNsManager)?.InnerText
                        });
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }
                }
            }
            catch (Exception e)
            {
                logger?.LogError("nodeListなし:" + e.Message);
            }

            logger?.LogInformation($"商品情報取得完了({page}ページ目、{saleInformation.Items.Count()}/{saleInformation.TotalResults}件)");

            return(true);
        }