好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

c#批量抓取免费代理并且验证有效性的实战教程

前言

之前看到某公司的官网的文章的浏览量刷新一次网页就会增加一次,给人的感觉不太好,一个公司的官网给人如此直白的漏洞,我批量发起请求的时候发现页面打开都报错,100多人的公司的官网文章刷新一次你给我看这个,这公司以前来过我们学校宣传招人+在园子里搜招聘的时候发现居然以前招xamarin,挺好奇的,所以就关注过。好吧不说这些了,只是扯扯蛋而已,回归主题,我想说的是csdn的文章可以通过设置代理ip刷新文章的浏览量,所以首先要做的就是这篇文章的主题[使用c#验证代理ip有效性]。

当然代理ip来源肯定是免费,所以嘛效率一般,从一些免费的代理ip的网页抓取的代理ip并不一定都是有用的,所以需要我们对我们抓取的代理ip进行验证,代理ip的有效时间也是有限,从10几秒到1个小时不限,大多数时间非常短,所以比如说,我们1分钟需要100个代理ip,那就1分钟获取一次,每次获取100个(这里是理想状态下的,抓取的代理ip都是有效的),原则上来说抓取下来后应该立即马上被使用。

当然这篇文章比较基础,一直觉得爬虫比较有趣,其实我在爬虫方面也是个小白,只是做一个简单的记录,如果有什么错误的地方,希望能提出建议。针对下面几个问题,我们就可以完成如何验证代理ip有效性的检测了。

1.从哪些网页上可以抓取免费的代理ip?

http://www.xicidaili.com

http://www.ip3366.net

http://www.66ip.cn

百度一下[免费代理ip]挺多的。

2.代理ip稳定吗?有什么作用?

这种免费的代理ip时效性和有效性都不强,上面这三个免费的代理网站,时效性大概在十几秒到1个小时不等,一般需要自己处理验证后使用,提高命中率。可适用于隐藏网页ip(有些网站还不准使用代理ip,比如豆瓣,其实挺尴尬的,内容这么贵吗),一般常用于空间留言、刷网站流量、网赚任务、批量注册账号等,只要没有其他限制,需要频繁更换ip都可以使用。

3.ping通ip就是有效的吗?如何验证代理是否有效

好吧,这有点废话,进行端口测试才是最有效的,能ping通并不代表代理有效,不能平通也不一定代理不可用。可以使用httpwebrequest,也可以使用scoket,当然httpwebrequest比socket连接代理ip、port要慢。

4.一次提取多少代理合适?

代理ip时效性不强、并且有效性也不高,所以只能从一些代理ip的网站上批量定时去获取,有的代理在一分钟内使用是有限制的,所以说限制比较多。

5.http代理和https代理有什么区别?

需要访问https的网站就需要使用https代理了,比如百度,需要访问http的代理,可以使用http。这个并不是100%的。

检测代理ip有效性步骤如下:

1.使用httpwebrequest、httpwebresponse请求代理ip的网页,获取包含代理的网页内容

2.使用htmlagilitypack或者正则表达式对抓取的内容进行截取,保存到代理集合

3.拿到代理集合,多线程发起http请求,比如访问百度,是否成功,成功则存到redis里面。

效果图如下:

使用httpwebrequest发起请求

request.cs如下,主要就是两个方法,一个方法是验证代理ip是否有效,设置httpwebrequest的proxy属性,请求百度,看到有些文章大多数会获取响应的内容,如果内容符合请求的网址则证明代理哟有效,实际上根据httpstatuscode 200就可以判断是否验证有效。

【注意】 建的是控制台程序,使用了异步,所以还是建.net core吧,c#语言的版本7.1。 c#如何在控制台程序中使用异步

?

public class request

  {

  /// <summary>

  /// 验证代理ip有效性

  /// </summary>

  /// <param name="proxyip">代理ip</param>

  /// <param name="proxyport">代理ip 端口</param>

  /// <param name="timeout">详情超时</param>

  /// <param name="url">请求的地址</param>

  /// <param name="success">成功的回调</param>

  /// <param name="fail">失败的回调</param>

  /// <returns></returns>

  public static async system.threading.tasks.task getasync( string proxyip, int proxyport, int timeout, string url, action success, action< string > fail)

  {

   system.gc.collect();

   httpwebrequest request = null ;

   httpwebresponse response = null ;

   try

   {

   request = (httpwebrequest)webrequest.create(url);

   //httpwebrequest request = httpwebrequest.createhttp(url);

   request.timeout =timeout;

   request.keepalive = false ;

   request.proxy = new webproxy(proxyip,proxyport);

   response = await request.getresponseasync() as httpwebresponse;

   if (response.statuscode == httpstatuscode.ok)

   {

    success();

   }

   else

   {

    fail(response.statuscode+ ":" +response.statusdescription);

   }

   }

   catch (exception ex)

   {

   fail( "请求异常" +ex.message.tostring());

   }

   finally

   {

   if (request != null )

   {

    request.abort();

    request = null ;

   }

   if (response != null )

   {

    response.close();

   }

   }

  }

 

  /// <summary>

  /// 发起http请求

  /// </summary>

  /// <param name="url"></param>

  /// <param name="success">成功的回调</param>

  /// <param name="fail">失败的回调</param>

  public static void get ( string url,action< string > success,action< string > fail)

  {

   streamreader reader = null ;

   stream stream = null ;

   webrequest request = null ;

   httpwebresponse response = null ;

   try

   {

   request = webrequest.create(url);

   request.timeout = 2000;

   response = (httpwebresponse)request.getresponse();

   if (response.statuscode == httpstatuscode.ok)

   {

    stream = response.getresponsestream();

    reader = new streamreader(stream);

    string result = reader.readtoend();

    success(result);

   }

   else

   {

    fail(response.statuscode+ ":" +response.statusdescription);

   }

   }

   catch (exception ex)

   {

   fail(ex.tostring());

   }

   finally

   {

   if (reader != null )

    reader.close();

   if (stream != null )

    stream.close();

   if (response!= null )

    response.close();

   if (request!= null )

    request.abort();

   }

  }

  }

抓取免费代理,并检查是否有效

proxyiphelper.cs 中主要有四个方法,检查ip是否可用checkproxyipasync、抓取xicidaili.com的代理getxicidailiproxy、抓取ip3366.net的代理getip3366proxy、抓取66ip.cn的代理getip3366proxy。如果想多抓取几个网站可以多写几个。

?

public class proxyiphelper

  {

   private static string address_xicidaili = "http://www.xicidaili.com/wn/{0}" ;

   private static string address_66ip = "http://www.66ip.cn/nmtq.php?getnum=20&isp=0&anonymoustype=0&start=&ports=&export=&ipaddress=&area=1&proxytype=1&api=66ip" ;

   private static string address_ip3366 = "http://www.ip3366.net/?stype=1&page={0}" ;

   /// <summary>

   /// 检查代理ip是否可用

   /// </summary>

   /// <param name="ipaddress">ip</param>

   /// <param name="success">成功的回调</param>

   /// <param name="fail">失败的回调</param>

   /// <returns></returns>

   public static async task checkproxyipasync( string ipaddress, action success, action< string > fail)

   {

    int index = ipaddress.indexof( ":" );

    string proxyip = ipaddress.substring(0, index);

    int proxyport = int .parse(ipaddress.substring(index + 1));

    await request.getasync(proxyip, proxyport, 3000, "https://www.baidu.com/" , () =>

    {

     success();

    }, (error) =>

    {

     fail(error);

    });

   }

   /// <summary>

   /// 从xicidaili.com网页上去获取代理ip,可以分页

   /// </summary>

   /// <param name="page"></param>

   /// <returns></returns>

   public static list< string > getxicidailiproxy( int page)

   {

    list< string > list = new list< string >();

    for ( int p = 1; p <= page; p++)

    {

     string url = string .format(address_xicidaili, p);

     request. get (url,(doctext)=> {

      if (! string .isnullorwhitespace(doctext))

      {

       htmldocument doc = new htmldocument();

       doc.loadhtml(doctext);

       var trnodes = doc.documentnode.selectnodes( "//table[@id='ip_list']" )[0].selectnodes( "./tr" );

       if (trnodes != null && trnodes.count > 0)

       {

        for ( int i = 1; i < trnodes.count; i++)

        {

         var tds = trnodes[i].selectnodes( "./td" );

         string ipaddress = tds[1].innertext + ":" + int .parse(tds[2].innertext); ;

         list.add(ipaddress);

        }

       }

      }

     },(error)=> {

      console.writeline(error);

     });

    }

    return list;

    }

   /// <summary>

   /// 从ip3366.net网页上去获取代理ip,可以分页

   /// </summary>

   /// <param name="page"></param>

   /// <returns></returns>

   public static list< string > getip3366proxy( int page)

   {

    list< string > list = new list< string >();

    for ( int p = 1; p <= page; p++)

    {

     string url = string .format(address_ip3366, p);

     request. get (url, (doctext) => {

      if (! string .isnullorwhitespace(doctext))

      {

       htmldocument doc = new htmldocument();

       doc.loadhtml(doctext);

       var trnodes1 = doc.documentnode.selectnodes( "//table" )[0];

       var trnodes2 = doc.documentnode.selectnodes( "//table" )[0].selectsinglenode( "//tbody" );

       var trnodes = doc.documentnode.selectnodes( "//table" )[0].selectsinglenode( "//tbody" ).selectnodes( "./tr" );

       if (trnodes != null && trnodes.count > 0)

       {

        for ( int i = 1; i < trnodes.count; i++)

        {

         var tds = trnodes[i].selectnodes( "./td" );

         if (tds[3].innerhtml == "https" )

         {

          string ipaddress = tds[0].innertext + ":" + int .parse(tds[1].innertext); ;

          list.add(ipaddress);

         }

        }

       }

      }

     }, (error) => {

      console.writeline(error);

     });

    }

    return list;

    }

   /// <summary>

   /// 从66ip.cn中去获取,不需要分页

   /// </summary>

   /// <returns></returns>

   public static list< string > get66ipproxy()

   {

    list< string > list = new list< string >();

    request. get (address_66ip,

    (doctext)=> {

     int count = 0;

     if ( string .isnullorwhitespace(doctext) == false )

     {

      string regex = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\:\\d{1,5}" ;

      match mstr = regex.match(doctext, regex);

      while (mstr.success && count < 20)

      {

       string tempip = mstr.groups[0].value;

       list.add(tempip);

       mstr = mstr.nextmatch();

       count++;

      }

     }

    },

    (error)=> {

     console.writeline(error);

    });

    return list;

   }

  }

使用timer定时抓取,并检查,成功则保存到redis

c#有三种定时器,这里定时器是使用system.threading命名空间, 这个timer会开启新的线程,抓取三个网页定义了三个timer对象。每一次抓取都会保存上一次抓取的集合,检查前,会进行对比,取出新的集合也就是没有重复的那部分。有效性的ip比较低,这里没有做统计,如果代码再优化一下,可以做一下统计,看看程序的主入口吧,最终的实现如下:

?

class program

  {

   static bool timer_ip3366_iscompleted = true ;

   static bool timer_xicidaili_iscompleted = true ;

   static bool timer_66ip_iscompleted = true ;

   static timer timer_ip3366, timer_xicidaili, timer_66ip;

   private static list< string > lastlistip3366,lastlist66ip,lastlistxicidaili; //保存上一次抓取的代理,与下一次进行对比,取新的集合进行检查筛选

   static async task main( string [] args)

   {

    system.net.servicepointmanager.defaultconnectionlimit = 2000;

    console.writeline( "hellow proxyip" );

    console.readline();

    lastlist66ip = new list< string >();

    lastlistip3366 = new list< string >();

    lastlistxicidaili = new list< string >();

    timer_ip3366 = new timer(async (state) =>

    {

     await timerip3366async();

    }, "processing timer_ip3366 event" , 0,1000*30);

    timer_xicidaili = new timer(async (state) =>

    {

     await timerxicidailiasync();

    }, "processing timer_xicidaili event" , 0, 1000 * 60);

    timer_66ip = new timer(async (state) =>

    {

     await timer66ipasync();

    }, "processing timer_66ip event" , 0, 1000*30);

   

    console.readline();

   }

 

 

 

   private static async task timer66ipasync()

   {

    if (timer_66ip_iscompleted)

    {

     timer_66ip_iscompleted = false ;

     list< string > checklist = new list< string >();

     var listproxyip = proxyiphelper.get66ipproxy();

 

     if (listproxyip.count > 0)

     {

      console.foregroundcolor = consolecolor.darkcyan;

      console.writeline( "66ip.cn 抓取到" + listproxyip.count + "条记录,正在对比........." );

      listproxyip. foreach (f =>

      {

       if (!lastlist66ip.contains(f))

       {

        checklist.add(f);

       }

      });

      lastlist66ip = listproxyip;

      if (checklist.count > 0)

      {

       console.foregroundcolor = consolecolor.darkcyan;

       console.writeline( "66ip.cn 需要检查" + checklist.count + "条记录,正在进行检测是否有效.........." );

       for ( int i = 0; i < checklist.count; i++)

       {

        string ipaddress = checklist[i];

        await proxyiphelper.checkproxyipasync(ipaddress, () =>

        {

         bool insertsuccess = redishelper.insertset(ipaddress);

         console.foregroundcolor = consolecolor.white;

         console.writeline( "66ip.cn" );

         if (insertsuccess)

         {

          console.writeline( "success" + ipaddress + "任务编号:" + i + "当前任务线程:" + thread.currentthread.managedthreadid);

         }

         console.writeline( "重复插入" + ipaddress + "任务编号:" + i + "当前任务线程:" + thread.currentthread.managedthreadid);

        }, (error) =>

        {

         console.foregroundcolor = consolecolor.green;

         console.writeline( "66ip.cn" );

         console.writeline( "error:" + ipaddress + error + "任务编号:" + i + "当前任务线程:" + thread.currentthread.managedthreadid);

        });

       }

       timer_66ip_iscompleted = true ;

       console.foregroundcolor = consolecolor.darkcyan;

       console.writeline( "66ip.cn" + checklist.count + "条记录,已经检测完成,正在进行下一次检查" );

      }

      else

      {

       timer_66ip_iscompleted = true ;

       console.foregroundcolor = consolecolor.darkcyan;

       console.writeline( "66ip.cn没有需要检查的代理ip" );

      }

     }

     else

     {

      timer_66ip_iscompleted = true ;

      console.foregroundcolor = consolecolor.darkcyan;

      console.writeline( "66ip.cn没有获取到代理ip" );

     }

    }

   }

 

   private static async task timerxicidailiasync()

   {

    if (timer_xicidaili_iscompleted)

    {

     //取出需要检查的ip地址,第一次100条则checklist就是100条记录,

     //第二次的100条中只有10是和上一次的不重复,则第二次只需要检查这10条记录

     timer_xicidaili_iscompleted = false ;

     list< string > checklist = new list< string >();

     var listproxyip = proxyiphelper.getxicidailiproxy(1);

     if (listproxyip.count > 0)

     {

      console.writeline( "xicidaili.com 抓取到" + listproxyip.count + "条记录,正在对比............" );

      listproxyip. foreach (f =>

      {

       if (!lastlistxicidaili.contains(f))

       {

        checklist.add(f);

       }

      });

      lastlistxicidaili = listproxyip;

      if (checklist.count > 0)

      {

       console.foregroundcolor = consolecolor.darkcyan;

       console.writeline( "xicidaili.com 需要检查" + checklist.count + "条记录,正在进行检测是否有效.........." );

       for ( int i = 0; i < checklist.count; i++)

       {

        string ipaddress = checklist[i];

        await proxyiphelper.checkproxyipasync(ipaddress, () =>

        {

         bool insertsuccess = redishelper.insertset(ipaddress);

         console.foregroundcolor = consolecolor.white;

         console.writeline( "xicidaili.com" );

         if (insertsuccess)

         {

          console.writeline( "success" + ipaddress + "任务编号:" + i + "当前任务线程:" + thread.currentthread.managedthreadid);

         }

         else

          console.writeline( "重复插入" + ipaddress + "任务编号:" + i + "当前任务线程:" + thread.currentthread.managedthreadid);

        }, (error) =>

        {

         console.writeline( "xicidaili.com" );

         console.foregroundcolor = consolecolor.red;

         console.writeline( "error:" + ipaddress + error + "任务编号:" + i + "当前任务线程:" + thread.currentthread.managedthreadid);

        });

       }

       timer_xicidaili_iscompleted = true ;

       console.foregroundcolor = consolecolor.darkcyan;

       console.writeline( "xicidaili.com" + checklist.count + "条记录,已经检测完成,正在进行下一次检查" );

      }

      else

      {

       timer_xicidaili_iscompleted = true ;

       console.foregroundcolor = consolecolor.darkcyan;

       console.writeline( "xicidaili.com没有需要检查的代理ip" );

      }

     }

     else

     {

      timer_xicidaili_iscompleted = true ;

      console.foregroundcolor = consolecolor.darkcyan;

      console.writeline( "xicidaili.com没有获取到代理ip" );

     }

    }

   }

   private static async task timerip3366async()

   {

    if (timer_ip3366_iscompleted)

    {

     timer_ip3366_iscompleted = false ;

     list< string > checklist = new list< string >();

     var listproxyip = proxyiphelper.getip3366proxy(4);

     if (listproxyip.count > 0)

     {

      console.foregroundcolor = consolecolor.darkcyan;

      console.writeline( "ip3366.net 抓取到" + listproxyip.count + "条记录,正在进行检测是否有效.........." );

      listproxyip. foreach (f =>

      {

       if (!lastlistip3366.contains(f))

       {

        checklist.add(f);

       }

      });

      lastlistip3366 = listproxyip;

      if (checklist.count != 0)

      {

       console.foregroundcolor = consolecolor.darkcyan;

       console.writeline( "ip3366.net 需要检查" + checklist.count + "条记录,正在进行检测是否有效.........." );

       for ( int i = 0; i < checklist.count; i++)

       {

        string ipaddress = checklist[i];

        await proxyiphelper.checkproxyipasync(ipaddress, () =>

        {

         bool insertsuccess = redishelper.insertset(ipaddress);

         console.foregroundcolor = consolecolor.white;

         console.writeline( "ip3366.net" );

         if (insertsuccess)

         {

          console.writeline( "success" + ipaddress + "任务编号:" + i + "当前任务线程:" + thread.currentthread.managedthreadid);

         }

         else

         {

          console.foregroundcolor = consolecolor.red;

          console.writeline( "重复插入" + ipaddress + "任务编号:" + i + "当前任务线程:" + thread.currentthread.managedthreadid);

         }

        }, (error) =>

        {

         console.foregroundcolor = consolecolor.yellow;

         console.writeline( "ip3366.net" );

         console.writeline( "error " + ipaddress + "任务编号:" + i + "当前任务线程:" + thread.currentthread.managedthreadid);

        });

       }

       timer_ip3366_iscompleted = true ;

       console.writeline( "ip3366.net" + checklist.count + "条记录,已经检测完成,正在进行下一次检查" );

      }

      else

      {

       timer_ip3366_iscompleted = true ;

       console.foregroundcolor = consolecolor.darkcyan;

       console.writeline( "ip3366.net没有需要检查的代理ip" );

      }

     }

     else

     {

      timer_ip3366_iscompleted = true ;

      console.foregroundcolor = consolecolor.darkcyan;

      console.writeline( "ip3366.net没有获取到代理ip" );

     }

 

    }

   }

  }

redis第三库使用的stackoverflow的 stackexchange.redis,代理ip不能重复储存,所以采用的数据结构是set。存的值非常简单就一个ip加上port,也可以存入更多相关信息,感觉没必要。即使有这些其他的信息,也很难发挥作用。redishelper.cs如下

?

public class redishelper

  {

   private static readonly object locker = new object ();

   private static connectionmultiplexer _redis;

   private const string connecttionstring = "127.0.0.1:6379,defaultdatabase=3" ;

   public const string redis_set_ket_success = "set_success_ip" ;

   private static connectionmultiplexer manager

   {

    get

    {

     if (_redis == null )

     {

      lock (locker)

      {

       if (_redis != null ) return _redis;

       _redis = getmanager();

       return _redis;

      }

     }

     return _redis;

    }

   }

   private static connectionmultiplexer getmanager( string connectionstring = null )

   {

    if ( string .isnullorempty(connectionstring))

    {

     connectionstring = connecttionstring;

    }

    return connectionmultiplexer.connect(connectionstring);

   }

   public static bool insertset( string value)

   {

    var db = manager.getdatabase();

    return db.setadd(redis_set_ket_success,value);

   }

  }

总结

明天补上刷服务器之家页浏览量的文章吧,代码还不够好,ip的有效性还不高,对多线程的使用还不是很熟练

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:https://www.cnblogs.com/zhangmumu/p/9269762.html

dy("nrwz");

查看更多关于c#批量抓取免费代理并且验证有效性的实战教程的详细内容...

  阅读:49次