C#实战分享--爬虫的基础原理及实现

关注我,持续分享逻辑思维&管理思维; 可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导;
有意找工作的同学,请参考博主的原创:《面试官心得--面试前应该如何准备》,《面试官心得--面试时如何进行自我介绍》《做好面试准备,迎接2024金三银四》。
推荐热榜内容:《架构实战--以海量存储系统讲解热门话题:分布式概念

-------------------------------------正文----------------------------------------

网终爬虫基本原理可以概括为以下几个步骤:

  • 建立待爬取的URL队列。爬虫首先需要确定要抓取的网页集合,这些URL形成一个队列。
  • 下载和解析网页。爬虫从队列中取出一个URL,并下载此URL。然后对该URL对应的网页进行解析。
  • 解析网页内容。爬虫下载网页后,需要解析这些内容,提取出有用的信息,如文本、图像和其他数据。
  • 管理和调度任务。爬虫可能需要管理多个任务,包括URL队列、线程池和排重机制,以确保高效和稳定的运行。
  • 保存数据。爬虫提取的信息需要被保存到适当的存储位置,如数据库、文件系统或其他数据存储服务。

博主曾经运营过一个段子网,当时写了个网络爬虫,抓取网上的段子到自己的网站数据库,以便我的段子网可以直接浏览这些内容。为便于观看,及便于让大家理解,以下代码我节选主要的内容,并在这次分享的过程中,加入了一些注释,以便大家理解。

应粉丝要求,增加了一篇文章,欢迎大家阅读:《网络爬虫和网站主的攻防--常见网站的反爬机制及应对​​​​​​​》

一、根据上面的步骤,我们先建立URL队列,一般有3个队列(待抓取,已抓取,坏链)

using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using xu_common.log;

namespace data_collection.spider_core
{
    class UrlSet
    {
        public UrlSet()
        {
            // 定义三个队列,准备抓取的URL集合,已经抓取的URL集合,错误的URL集合
            // 这里需要注意,因为我是定向抓取,这里URL不会太多。如果是全网抓取,URL太多,要防止内存泄露
            _going_to_parse = new ArrayList(); 
            _already_parse = new ArrayList();
            _error_link = new ArrayList();
        }

        private static UrlSet __instance = null;
        public static UrlSet instance
        {
            get
            {
                if (__instance == null)
                {
                    __instance = new UrlSet();
                }
                return __instance;
            }            
        }

        private ArrayList _going_to_parse = null;
        private ArrayList _already_parse = null;
        private ArrayList _error_link = null;

        // 判断URL是否抓取过,并根据参数add是否true来判断这个URL是否入库
        private bool is_url_parsed(string url, bool add)
        {
            bool rv;
            lock (_already_parse.SyncRoot)
            {
                rv = _already_parse.Contains(url);
                if (!rv && add)
                    _already_parse.Add(url);
            }
            return rv;
        }

        // 判断URL是否抓取过
        private bool is_url_parsed(string url)
        {
            return is_url_parsed(url, false);
        }

        // 判断URL是否在待抓取列表,并根据参数add是否true来判断这个URL是否加入待抓取
        private bool is_url_going_to_parse(string url, bool add)
        {
            bool rv;
            lock (_going_to_parse.SyncRoot)
            {
                rv = _going_to_parse.Contains(url);
                if (!rv && add)
                    _going_to_parse.Add(url);
            }
            return rv;
        }
        // 判断URL是否在待抓取列表
        private bool is_url_going_to_parse(string url)
        {
            return is_url_going_to_parse(url, false);
        }

        // 判断URL是否在错误URL列表,并根据add来确定是否要加入此列表
        private bool is_url_error_lnk(string url, bool add)
        {
            bool rv;
            lock (_error_link.SyncRoot)
            {
                rv = _error_link.Contains(url);
                if (!rv && add)
                    _already_parse.Add(url);
            }
            return rv;
        }
        private bool is_url_error_lnk(string url)
        {
            return is_url_error_lnk(url, false);
        }

        /// 
        /// 把一个Url加到待解析列表中.
        /// 如果已经解析过,返回-1; 
        /// 如果是坏链,返回-2
        /// 如果已经在待解析列表中,返回1.
        /// 否则加入待解析列表,并且返回0
        /// 
        /// 
        /// >=0:OK, <0:ERROR
        public int add_going_parse_url(string url)
        {
            lock (_going_to_parse.SyncRoot)
            {
                if (is_url_parsed(url))
                {
                    return -1;
                }
                if (is_url_error_lnk(url))
                {
                    return -2;
                }
                if (is_url_going_to_parse(url, true))
                    return 1;

                //_going_to_parse.Add(url);
                return 0;
            }
        }

        /// 
        /// 添加一个已经抓取过的链接,如果此链接在待抓取或者坏链中,删除
        /// 如果已经在抓取过列表中,返回-1,否则返回0
        /// 
        /// 
        /// 0:OK,-1:ERROR
        public int add_parsed_url(string url)
        {
            // already parse, not use to parse again.
            if (is_url_going_to_parse(url))
            {
                _going_to_parse.Remove(url);
            }
            if (is_url_error_lnk(url))
            {
                _error_link.Remove(url);
                //return -1;
            }
            if (is_url_parsed(url, true))
            {
                return -1;
            }
            //_already_parse.Add(url);
            return 0;
        }

        /// 
        /// 添加一个错误的链接.如果该链接在待抓取列表中,删除(说明不应该抓取)
        /// 
        /// 
        /// 0:OK; -1:ERROR
        public int add_error_url(string url)
        {
            if (is_url_going_to_parse(url))
            {
                _going_to_parse.Remove(url);
            }
            /*
            if (is_url_parsed(url))
            {
                return -2;//都已经解析过了,还加进这里去干嘛? never go to here,因为解析过的话,不可能再拿来解析,然后到这里的
            }
             * */
          

你可能感兴趣的:(C#实战分享--爬虫的基础原理及实现)