2.HtmlAgilityPack 爬取优酷电影名进阶(所有分类+多线程)

简介: 上一章节中我们实现了对优酷单页面的爬取,简单进行回顾一下,使用HtmlAgilityPack库,对爬虫的爬取一共分为三步爬虫步骤加载页面解析数据保存数据继第一篇文档后的爬虫进阶,本文章主要是对上一篇的进阶。

上一章节中我们实现了对优酷单页面的爬取,简单进行回顾一下,使用HtmlAgilityPack库,对爬虫的爬取一共分为三步

  • 爬虫步骤
    • 加载页面
    • 解析数据
    • 保存数据

继第一篇文档后的爬虫进阶,本文章主要是对上一篇的进阶。实现的功能主要为:
1、爬取电影类别列表
2、循环每个类别的电影信息,对每个类别的信息分页爬取
3、爬取的数据保存到数据库中

一、爬取电影类别列表

img_d36aa022b02e6c530cda7bc4266eb961.png
电影类别页.png

使用Chrome浏览器,F12,找到当前位置,得到当前位置的Xpath。我们需要的数据是电影的类别编码和电影类别名称。

规则分析:
XPATH路径为 "//*[@id='filterPanel']/div/ul/li/a")
类别编码为A标签Href路径的内容,我们对其进行截取
类别名称为A标签InnerTest,我们对其进行截取

代码示例

     //加载web内容
         private static readonly string _url = "http://list.youku.com/category/video/c_0.html";

        /// <summary>
        ///     得到所有的类别
        /// </summary>
        public static List<VideoType> GetVideoTypes()
        {
            //加载web内容
            var web = new HtmlWeb();
            var doc = web.Load(_url);

            //内容解析-获得所有的类别
            var allTypes = doc.DocumentNode.SelectNodes("//*[@id='filterPanel']/div/ul/li/a").ToList();

            //类别列表中去掉【全部】这个选项
            var typeResults = allTypes.Where((u, i) => { return i > 0; }).ToList();

            var reList = new List<VideoType>();
            foreach (var node in typeResults)
            {
                var href = node.Attributes["href"].Value;
                reList.Add(new VideoType
                {
                    Code = href.Substring(href.LastIndexOf("/") + 1, href.LastIndexOf(".") - href.LastIndexOf("/") - 1),
                    Name = node.InnerText
                });
            }

            return reList;
        }

二、爬取每个类别的总分页数

code 为电影类别编码
页面规则 $"http://list.youku.com/category/show/{code}.html"
根据页面规则进行爬取:

        /// <summary>
        ///     得到当前类别的总页数
        /// </summary>
        public static int GetPageCountByCode(string code)
        {
            var web = new HtmlWeb();
            var doc = web.Load($"http://list.youku.com/category/show/{code}.html");

            //分页列表
            var pageList = doc.DocumentNode.CssSelect(".yk-pages li").ToList();
            //得到倒数第二项
            var lastsecond = pageList[pageList.Count - 2];
            return Convert.ToInt32(lastsecond.InnerText);
        }

三、按照页码得到每个电影类别的内容

根据分页规则分析出分页后的地址为
code 为编码 pageIndex为第几页
页面规则:http://list.youku.com/category/show/{code}s_1_d_1_p{pageIndex}.html
根据页面规则进行爬取:

    /// <summary>
        ///     得到当前类别的内容
        /// </summary>
        public static List<VideoContent> GetContentsByCode(string code, int pageIndex)
        {
            var web = new HtmlWeb();
            var doc = web.Load($"http://list.youku.com/category/show/{code}_s_1_d_1_p_{pageIndex}.html");

            var returnLi = new List<VideoContent>();
            var contents = doc.DocumentNode.CssSelect(".yk-col4").ToList();

            foreach (var node in contents)
                returnLi.Add(new VideoContent
                {
                    PageIndex = pageIndex.ToString(),
                    Code = code,
                    Title = node.CssSelect(".info-list .title a").FirstOrDefault()?.InnerText,
                    Hits = node.CssSelect(".info-list li").LastOrDefault()?.InnerText,
                    Href = node.CssSelect(".info-list .title a").FirstOrDefault()?.Attributes["href"].Value,
                    ImgHref = node.CssSelect(".p-thumb img").FirstOrDefault()?.Attributes["Src"].Value
                });

            return returnLi;
        }

四、测试爬取的结果


        /// <summary>
        ///     打印得到的内容
        /// </summary>
        public static void PrintContent()
        {
            var count = 0;
            foreach (var node in GetVideoTypes())
            {
                var resultLi = new List<VideoContent>();
                //得到当前类别总分页数
                var pageCount = GetPageCountByCode(node.Code);
                //遍历分页得到内容
                for (var i = 1; i <= pageCount; i++) resultLi.AddRange(GetContentsByCode(node.Code, i));
                Console.WriteLine($"编码{node.Code} \t 页数{pageCount} \t 总个数{resultLi.Count}");
                count += resultLi.Count;
            }

            Console.WriteLine($"总个数为{count}");
        }

代码下载地址:

https://github.com/happlyfox/FoxCrawler/tree/master/%E5%AD%A6%E4%B9%A0%E7%A4%BA%E4%BE%8B/YouKuCrawler/YouKuCrawlerAsync
目录
相关文章
java 并发多线程 锁的分类概念介绍 多线程下篇(二)
java 并发多线程 锁的分类概念介绍 多线程下篇(二) 接下来对锁的概念再次进行深入的介绍 之前反复的提到锁,通常的理解就是,锁---互斥---同步---阻塞 其实这是常用的独占锁(排它锁)的概念,也是一种简单粗暴的解决方案 抗战电影中,经常出现为了阻止日本人炸桥?炸路?的场景,这只是阻止日本人.
1581 0
|
数据采集
4.爬虫框架Clawler 爬取优酷电影名 分页+多线程
代码下载地址: https://github.com/happlyfox/FoxCrawler/tree/master/%E5%AD%A6%E4%B9%A0%E7%A4%BA%E4%BE%8B/YouKuCrawler/YouKuDotnetSpide...
1032 0
|
1天前
|
设计模式 消息中间件 安全
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
8 0
|
1天前
|
Java 数据库
【Java多线程】对线程池的理解并模拟实现线程池
【Java多线程】对线程池的理解并模拟实现线程池
10 1
|
1天前
|
Java
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
9 1
|
1天前
|
存储 缓存 安全
【Java多线程】线程安全问题与解决方案
【Java多线程】线程安全问题与解决方案
8 1
|
1天前
|
Java 调度
【Java多线程】线程中几个常见的属性以及状态
【Java多线程】线程中几个常见的属性以及状态
7 0
|
1天前
|
Java 调度
【Java多线程】对进程与线程的理解
【Java多线程】对进程与线程的理解
9 1
|
3天前
|
存储 安全 Java
【探索Linux】P.21(多线程 | 线程同步 | 条件变量 | 线程安全)
【探索Linux】P.21(多线程 | 线程同步 | 条件变量 | 线程安全)
9 0
|
3天前
|
算法 安全 Linux
【探索Linux】P.20(多线程 | 线程互斥 | 互斥锁 | 死锁 | 资源饥饿)
【探索Linux】P.20(多线程 | 线程互斥 | 互斥锁 | 死锁 | 资源饥饿)
10 0