2、苏宁百万级商品爬取 思路讲解 类别页数爬取

通过上述章节内容,我们得到了类别的数据,现在我们需要对每个类别进行商品的爬取。点击移动电源,进行商品总页数抓取,这个模块相对简单,正好适合用来练手。
我们可以从“列表页.png”的图片中看到,当前移动电源的页数为右上角所显示 1/100,即100页.
xpath的获取如第三张图所示,结果为
//*[@id="second-filter"]/div[2]/div/span

2、苏宁百万级商品爬取 思路讲解 类别页数爬取
类别.png

2、苏宁百万级商品爬取 思路讲解 类别页数爬取
列表页.png
2、苏宁百万级商品爬取 思路讲解 类别页数爬取
xpath.png

分析出了如果获取页数,我们现在要考虑的问题是,如果更新所有的类别。
其实思路非常简单,从数据库中取出对应的等级为3的类别(最底层类别),对这些类别进行循环,参数就是当前行的url,然后执行网页爬取代码,得到页数,更新数据。


2、苏宁百万级商品爬取 思路讲解 类别页数爬取
数据库类别数据.png

根据Sql语句,得到等级为3的类别一共有4197个。这个时候就存在问题了,如果同步执行(循环一个一个执行),那么我的效率就很低,为了验证自己的写法。我以50个类别为例做了一个小demo测试性能。

     //获取符合条件的列表
     var urlList = _categoryService.GetListByLevel(3).Select(u => u.Url).ToList();

CategoryPageAnalysis.GetData(string url) 方法为获取类别个数方法

同步

循环执行,耗时18233毫秒

            var dics = new Dictionary<string, int>();
            foreach (var url in urlList)
            {
                dics.Add(url, CategoryPageAnalysis.GetData(url));
            }

异步方法

6163毫秒 3倍的效率差
异步方法体的说明如下:
首先因为存在4197个类别,需要对这些类别进行分类。
4197/2000 约等于20. 即开20个线程,每个线程执行200条数据

            int pageNum = 200;
            int pageCount = urlList.Count % pageNum == 0 ? urlList.Count / pageNum : urlList.Count / pageNum + 1;
            var pageListCollection = new List<List<string>>();
            for (int i = 0; i < pageCount; i++)
            {
                var pageList = urlList.Skip(i * pageNum).Take(pageNum).ToList();
                pageListCollection.Add(pageList);
            }
            Console.WriteLine(pageCount);

            //异步 6163毫秒 3倍的效率差
            int pageIndex = 1;
            List<Task> taskList = new List<Task>();
            foreach (var pageList in pageListCollection)
            {
                try
                {
                    Task task = Task.Factory.StartNew(() =>
                    {
                        var dics = new Dictionary<string, int>();
                        foreach (var url in pageList)
                        {
                            dics.Add(url, CategoryPageAnalysis.GetData(url));
                        }

                        lock (lock_obj)
                        {
                            _categoryService.BatchUpdatePage(dics);
                        }
                    });
                    taskList.Add(task);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"button3_Click 异步{ex.Message}");
                }
            }

存在的问题:

这种方法是为了单独解决这个问题而使用的,很笨拙,因为如果只有200个类别,多线程的意义就没有办法体现出来,这一点在之后的编码中我进行了修改。

上一篇:【案例学习】芬兰铁路的 Docker 使用实践分享


下一篇:4.爬虫框架Clawler 爬取优酷电影名 分页+多线程