记一次企业级爬虫系统升级改造(六):基于Redis实现免费的IP代理池
前言:
首先表示抱歉,春节后一直较忙,未及时更新该系列文章。
近期,由于监控的站源越来越多,就偶有站源做了反爬机制,造成我们的SupportYun系统小爬虫服务时常被封IP,不能进行数据采集。
这时候,前面有园友提到的IP代理就该上场表演了。
IP代理池设计:
博主查阅与调研了多方资料,最终决定先通过爬取网络上各大IP代理网站免费代理的方式,来建立自己的IP代理池。
最终爬取了五家较为优质的IP代理站点:
1.西刺代理
2.快代理
3.逼格代理
4.proxy360
5.66免费代理
IP代理池方案设计如下:

简单点说就是把在采集的站源里面已知具有反爬机制的站源打上标签,修改所有的爬虫服务,遇到有此标签的站源先从IP代理池随机获取可用的代理IP再进行数据爬取。
安装Redis:
首先,我们需要一台服务器来部署我们的Redis服务(先不考虑集群什么的)。
博主一向不喜欢弹个小黑框,不停敲命令行进行操作的各种方式。个人认为,GUI是推动计算机快速发展的重要因素之一(非喜勿喷)。
翻阅了资料,找到了简易的redis安装客户端(windows版本,安装简单到爆),地址如下:
http://download.csdn.net/detail/cb511612371/9784687
在博客园找到一篇介绍redis配置文件的博文,贴出来供大家参考:http://www.cnblogs.com/kreo/p/4423362.html
话说博主就简单的修改了一下内存限制,设置了允许外网连接,设置了一个密码,也没多改其他东西。
注意,配置文件在安装完成后的目录下,名称是:Redis.window-server.conf
熟悉一点都知道,redis的c#驱动ServiceStack.Redis,NuGet就可以直接安装。比较坑的是4.0版本后商业化了,限制每小时6000次,要么下载3.9版本,要么考虑其他的驱动,例如:StackExchange。
博主使用的是ServiceStack V3.9版本,附上下载地址:http://download.csdn.net/detail/cb511612371/9784626
下面附上博主基于ServiceStack写的RedisManageService,由于业务简单,只使用到了几个API,大家凑合着看。
/// <summary>
/// 基于ServiceStack的redis操作管理服务
/// 当前用到set存储
/// </summary>
public class RedisManageService
{
private static readonly string redisAddress = ConfigurationManager.AppSettings["RedisAddress"];
private static readonly string redisPassword = "myRedisPassword"; /// <summary>
/// 获取某set集合 随机一条数据
/// </summary>
/// <param name="setName"></param>
/// <returns></returns>
public static string GetRandomItemFromSet(RedisSetNameEnum setName)
{
using (RedisClient client = new RedisClient(redisAddress, , redisPassword))
{
var result = client.GetRandomItemFromSet(setName.ToString());
if (result == null)
{
throw new Exception("redis set集合"+setName.ToString()+"已无数据!");
}
return result;
}
} /// <summary>
/// 从某set集合 删除指定数据
/// </summary>
/// <param name="setName"></param>
/// <param name="value"></param>
/// <returns></returns>
public static void RemoveItemFromSet(RedisSetNameEnum setName, string value)
{
using (RedisClient client = new RedisClient(redisAddress, , redisPassword))
{
client.RemoveItemFromSet(setName.ToString(), value);
}
} /// <summary>
/// 添加一条数据到某set集合
/// </summary>
/// <param name="setName"></param>
/// <param name="value"></param>
public static void AddItemToSet(RedisSetNameEnum setName, string value)
{
using (RedisClient client = new RedisClient(redisAddress, , redisPassword))
{
client.AddItemToSet(setName.ToString(), value);
}
} /// <summary>
/// 添加一个列表到某set集合
/// </summary>
/// <param name="setName"></param>
/// <param name="values"></param>
public static void AddItemListToSet(RedisSetNameEnum setName, List<string> values)
{
using (RedisClient client = new RedisClient(redisAddress, , redisPassword))
{
client.AddRangeToSet(setName.ToString(), values);
}
} /// <summary>
/// 判断某值是否已存在某set集合中
/// </summary>
/// <param name="setName"></param>
/// <param name="value"></param>
/// <returns></returns>
public static bool JudgeItemInSet(RedisSetNameEnum setName, string value)
{
using (RedisClient client = new RedisClient(redisAddress, , redisPassword))
{
return client.Sets[setName.ToString()].Any(t => t == value);
}
} /// <summary>
/// 获取某set数据总数
/// </summary>
/// <param name="setName"></param>
/// <returns></returns>
public static long GetSetCount(RedisSetNameEnum setName)
{
using (RedisClient client = new RedisClient(redisAddress, , redisPassword))
{
return client.GetSetCount(setName.ToString());
}
}
}
免费代理IP抓取服务实现:
我们首先设计一个最简单的IpProxy对象:
/// <summary>
/// Ip代理对象
/// </summary>
public class IpProxy
{
/// <summary>
/// IP地址
/// </summary>
public string Address { get; set; } /// <summary>
/// 端口
/// </summary>
public int Port { get; set; }
}
然后实现一个基于Redis的Ip代理池操作服务:
/// <summary>
/// 基于Redis的代理池管理服务
/// </summary>
public class PoolManageService
{
/// <summary>
/// 从代理池随机获取一条代理
/// </summary>
/// <returns></returns>
public static string GetProxy()
{
string result = string.Empty; try
{
result = RedisManageService.GetRandomItemFromSet(RedisSetNameEnum.ProxyPool);
if (result != null)
{
if (
!HttpHelper.IsAvailable(result.Split(new[] { ':' })[],
int.Parse(result.Split(new[] { ':' })[])))
{
DeleteProxy(result);
return GetProxy();
}
}
}
catch (Exception e)
{
LogUtils.ErrorLog(new Exception("从代理池获取代理数据出错", e));
}
return result;
} /// <summary>
/// 从代理池删除一条代理
/// </summary>
/// <param name="value"></param>
public static void DeleteProxy(string value)
{
try
{
RedisManageService.RemoveItemFromSet(RedisSetNameEnum.ProxyPool, value);
}
catch (Exception e)
{
LogUtils.ErrorLog(new Exception("从代理池删除代理数据出错", e));
}
} /// <summary>
/// 添加一条代理到代理池
/// </summary>
/// <param name="proxy"></param>
public static void Add(IpProxy proxy)
{
try
{
if (HttpHelper.IsAvailable(proxy.Address, proxy.Port))
{
RedisManageService.AddItemToSet(RedisSetNameEnum.ProxyPool, proxy.Address + ":" + proxy.Port.ToString());
}
}
catch (Exception e)
{
LogUtils.ErrorLog(new Exception("添加一条代理数据到代理池出错", e));
}
}
}
提供简易的三个方法:添加代理IP、删除代理IP、随机获取一条代理IP
我们还需要一个爬虫服务,来爬取我们需要的免费代理IP数据:
/// <summary>
/// IP池 抓取蜘蛛
/// TODO:代理池站点变化较快,时常关注日志监控
/// </summary>
public class IpPoolSpider
{
public void Initial()
{
ThreadPool.QueueUserWorkItem(Downloadproxy360);
ThreadPool.QueueUserWorkItem(DownloadproxyBiGe);
ThreadPool.QueueUserWorkItem(Downloadproxy66);
ThreadPool.QueueUserWorkItem(Downloadxicidaili);
} // 下载西刺代理的html页面
public void Downloadxicidaili(object DATA)
{
try
{
List<string> list = new List<string>()
{
"http://www.xicidaili.com/nt/",
"http://www.xicidaili.com/nn/",
"http://www.xicidaili.com/wn/",
"http://www.xicidaili.com/wt/" };
foreach (var utlitem in list)
{
for (int i = ; i < ; i++)
{
string url = utlitem + i.ToString();
var ipProxy = PoolManageService.GetProxy();
if (string.IsNullOrEmpty(ipProxy))
{
LogUtils.ErrorLog(new Exception("Ip代理池暂无可用代理IP"));
return;
}
var ip = ipProxy;
WebProxy webproxy;
if (ipProxy.Contains(":"))
{
ip = ipProxy.Split(new[] { ':' })[];
var port = int.Parse(ipProxy.Split(new[] { ':' })[]);
webproxy = new WebProxy(ip, port);
}
else
{
webproxy = new WebProxy(ip);
}
string html = HttpHelper.DownloadHtml(url, webproxy);
if (string.IsNullOrEmpty(html))
{
LogUtils.ErrorLog(new Exception("代理地址:" + url + " 访问失败"));
continue;
} HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
HtmlNode node = doc.DocumentNode;
string xpathstring = "//tr[@class='odd']";
HtmlNodeCollection collection = node.SelectNodes(xpathstring);
foreach (var item in collection)
{
var proxy = new IpProxy();
string xpath = "td[2]";
proxy.Address = item.SelectSingleNode(xpath).InnerHtml;
xpath = "td[3]";
proxy.Port = int.Parse(item.SelectSingleNode(xpath).InnerHtml);
Task.Run(() =>
{
PoolManageService.Add(proxy);
});
}
}
}
}
catch (Exception e)
{
LogUtils.ErrorLog(new Exception("下载西刺代理IP池出现故障", e));
}
} // 下载快代理
public void Downkuaidaili(object DATA)
{
try
{
string url = "http://www.kuaidaili.com/proxylist/";
for (int i = ; i < ; i++)
{
string html = HttpHelper.DownloadHtml(url + i.ToString() + "/", null);
string xpath = "//tbody/tr";
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
HtmlNode node = doc.DocumentNode;
HtmlNodeCollection collection = node.SelectNodes(xpath);
foreach (var item in collection)
{
var proxy = new IpProxy();
proxy.Address = item.FirstChild.InnerHtml;
xpath = "td[2]";
proxy.Port = int.Parse(item.SelectSingleNode(xpath).InnerHtml);
Task.Run(() =>
{
PoolManageService.Add(proxy);
});
}
}
}
catch (Exception e)
{
LogUtils.ErrorLog(new Exception("下载快代理IP池出现故障", e));
}
} // 下载proxy360
public void Downloadproxy360(object DATA)
{
try
{
string url = "http://www.proxy360.cn/default.aspx";
string html = HttpHelper.DownloadHtml(url, null);
if (string.IsNullOrEmpty(html))
{
LogUtils.ErrorLog(new Exception("代理地址:" + url + " 访问失败"));
return;
}
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
string xpathstring = "//div[@class='proxylistitem']";
HtmlNode node = doc.DocumentNode;
HtmlNodeCollection collection = node.SelectNodes(xpathstring); foreach (var item in collection)
{
var proxy = new IpProxy();
var childnode = item.ChildNodes[];
xpathstring = "span[1]";
proxy.Address = childnode.SelectSingleNode(xpathstring).InnerHtml.Trim();
xpathstring = "span[2]";
proxy.Port = int.Parse(childnode.SelectSingleNode(xpathstring).InnerHtml);
Task.Run(() =>
{
PoolManageService.Add(proxy);
});
}
}
catch (Exception e)
{
LogUtils.ErrorLog(new Exception("下载proxy360IP池出现故障", e));
}
} // 下载逼格代理
public void DownloadproxyBiGe(object DATA)
{
try
{
List<string> list = new List<string>()
{
"http://www.bigdaili.com/dailiip/1/{0}.html",
"http://www.bigdaili.com/dailiip/2/{0}.html",
"http://www.bigdaili.com/dailiip/3/{0}.html",
"http://www.bigdaili.com/dailiip/4/{0}.html"
};
foreach (var utlitem in list)
{
for (int i = ; i < ; i++)
{
string url = String.Format(utlitem, i);
string html = HttpHelper.DownloadHtml(url, null);
if (string.IsNullOrEmpty(html))
{
LogUtils.ErrorLog(new Exception("代理地址:" + url + " 访问失败"));
continue;
} HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
HtmlNode node = doc.DocumentNode;
string xpathstring = "//tbody/tr";
HtmlNodeCollection collection = node.SelectNodes(xpathstring);
foreach (var item in collection)
{
var proxy = new IpProxy();
var xpath = "td[1]";
proxy.Address = item.SelectSingleNode(xpath).InnerHtml;
xpath = "td[2]";
proxy.Port = int.Parse(item.SelectSingleNode(xpath).InnerHtml);
Task.Run(() =>
{
PoolManageService.Add(proxy);
});
}
}
}
}
catch (Exception e)
{
LogUtils.ErrorLog(new Exception("下载逼格代理IP池出现故障", e));
}
} // 下载66免费代理
public void Downloadproxy66(object DATA)
{
try
{
List<string> list = new List<string>()
{
"http://www.66ip.cn/areaindex_35/index.html",
"http://www.66ip.cn/areaindex_35/2.html",
"http://www.66ip.cn/areaindex_35/3.html"
};
foreach (var utlitem in list)
{
string url = utlitem;
string html = HttpHelper.DownloadHtml(url, null);
if (string.IsNullOrEmpty(html))
{
LogUtils.ErrorLog(new Exception("代理地址:" + url + " 访问失败"));
break;
} HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(html);
HtmlNode node = doc.DocumentNode;
string xpathstring = "//table[@bordercolor='#6699ff']/tr";
HtmlNodeCollection collection = node.SelectNodes(xpathstring);
foreach (var item in collection)
{
var proxy = new IpProxy();
var xpath = "td[1]";
proxy.Address = item.SelectSingleNode(xpath).InnerHtml;
if (proxy.Address.Contains("ip"))
{
continue;
}
xpath = "td[2]";
proxy.Port = int.Parse(item.SelectSingleNode(xpath).InnerHtml);
Task.Run(() =>
{
PoolManageService.Add(proxy);
});
}
}
}
catch (Exception e)
{
LogUtils.ErrorLog(new Exception("下载66免费代理IP池出现故障", e));
}
}
}
这段代码也没什么营养,就不仔细解释了。
前面有说到,博主的爬虫服务都是以windows服务的方式部署的。以前一直用Timer来实现固定间隔多次循环,这次博主引用了Quartz.NET任务调度框架来做,代码看起来更优美一点。
Quartz.NET可直接在NuGet下载安装。
先写一个代理池的总调度任务类ProxyPoolTotalJob,继承IJob接口:
/// <summary>
/// 代理池总调度任务
/// </summary>
class ProxyPoolTotalJob : IJob
{
public void Execute(IJobExecutionContext context)
{
var spider = new IpPoolSpider();
spider.Initial();
}
}
接下来是在OnStart中运行的Run()方法实现:
private static void Run()
{
try
{
StdSchedulerFactory factory = new StdSchedulerFactory();
IScheduler scheduler = factory.GetScheduler();
scheduler.Start();
IJobDetail job = JobBuilder.Create<ProxyPoolTotalJob>().WithIdentity("job1", "group1").Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger1", "group1")
.StartNow()
.WithSimpleSchedule(
x => x
.WithIntervalInMinutes() // 28分钟一次
.RepeatForever()
).Build();
scheduler.ScheduleJob(job, trigger); }
catch (SchedulerException se)
{
Console.WriteLine(se);
}
}
最后采集具有反爬机制的html页面的时候,使用代理IP,这个相信大家都会,设置一下webRequest的Proxy参数即可。
webRequest.Proxy = new WebProxy(ip, port);
以上,就实现了一个基于redis的免费代理IP池。我们被封IP的爬虫服务又满血复活了,继续采集新数据去。
原创文章,代码都是从自己项目里贴出来的。转载请注明出处哦,亲~~~
记一次企业级爬虫系统升级改造(六):基于Redis实现免费的IP代理池的更多相关文章
- 记一次企业级爬虫系统升级改造(二):基于AngleSharp实现的抓取服务
爬虫系统升级改造正式启动: 在第一篇文章,博主主要介绍了本次改造的爬虫系统的业务背景与全局规划构思: 未来Support云系统,不仅仅是爬虫系统,是集爬取数据.数据建模处理统计分析.支持全文检索资源库 ...
- 记一次企业级爬虫系统升级改造(五):基于JieBaNet+Lucene.Net实现全文搜索
实现效果: 上一篇文章有附全文搜索结果的设计图,下面截一张开发完成上线后的实图: 基本风格是模仿的百度搜索结果,绿色的分页略显小清新. 目前已采集并创建索引的文章约3W多篇,索引文件不算太大,查询速度 ...
- python爬虫实战(三)--------搜狗微信文章(IP代理池和用户代理池设定----scrapy)
在学习scrapy爬虫框架中,肯定会涉及到IP代理池和User-Agent池的设定,规避网站的反爬. 这两天在看一个关于搜狗微信文章爬取的视频,里面有讲到ip代理池和用户代理池,在此结合自身的所了解的 ...
- python3爬虫系列19之反爬随机 User-Agent 和 ip代理池的使用
站长资讯平台:python3爬虫系列19之随机User-Agent 和ip代理池的使用我们前面几篇讲了爬虫增速多进程,进程池的用法之类的,爬虫速度加快呢,也会带来一些坏事. 1. 前言比如随着我们爬虫 ...
- Scrapy加Redis加IP代理池实现音乐爬虫
音乐爬虫 关注公众号"轻松学编程"了解更多. 目的:爬取歌名,歌手,歌词,歌曲url. 一.创建爬虫项目 创建一个文件夹,进入文件夹,打开cmd窗口,输入: scrapy star ...
- 反爬虫之搭建IP代理池
反爬虫之搭建IP代理池 听说你又被封 ip 了,你要学会伪装好自己,这次说说伪装你的头部.可惜加了header请求头,加了cookie 还是被限制爬取了.这时就得祭出IP代理池!!! 下面就是requ ...
- Python爬虫之ip代理池
可能在学习爬虫的时候,遇到很多的反爬的手段,封ip 就是其中之一. 对于封IP的网站.需要很多的代理IP,去买代理IP,对于初学者觉得没有必要,每个卖代理IP的网站有的提供了免费IP,可是又很少,写了 ...
- python爬虫18 | 就算你被封了也能继续爬,使用IP代理池伪装你的IP地址,让IP飘一会
我们上次说了伪装头部 ↓ python爬虫17 | 听说你又被封 ip 了,你要学会伪装好自己,这次说说伪装你的头部 让自己的 python 爬虫假装是浏览器 小帅b主要是想让你知道 在爬取网站的时候 ...
- ip代理池的爬虫编写、验证和维护
打算法比赛有点累,比赛之余写点小项目来提升一下工程能力.顺便陶冶一下情操 本来是想买一个服务器写个博客或者是弄个什么FQ的东西 最后刷知乎看到有一个很有意思的项目,就是维护一个「高可用低延迟的高匿IP ...
随机推荐
- linux上静态库链接的有关问题
求大神,linux下静态库链接的问题有两个文件和一个库,a.c, b.c,libh.a,其中b.c里面会有调用libh.a的函数func1,现在将a.c, b.c,libh.a编译链接生成可执行文件, ...
- 【Spring-web】AsyncRestTemplate源码学习
2017-01-23 by 安静的下雪天 http://www.cnblogs.com/quiet-snowy-day/p/6343347.html 本篇概要 类说明 类图 简单例子 精辟的内部类 类 ...
- 【python基础】之元组 集合 字典
元组 元组:元组和列表类似.但是元组中的元素是固定的(不能给一个元组添加,删除和替换元素以及重新排序) 1.创建元组 t1 = () #创建一个空元组 t2 = (1, 2, 3) t3 = tupl ...
- 编写JQuery插件-2
继续上一节的代码 (function(){ /* code */ })() 来我们介绍一下吧,首先定义一个匿名函数 fnction(){/* 这里放置代码 */} 然后用括号括起来, (fnction ...
- SVN-TortoiseSVN安装和常用操作步骤
安装VisualSVN-Server-2.0.5 服务端: 运行VisualSVN-Server-2.0.5.msi程序,点击Next,下面的截图顺序即为安装步骤: 2 图2: 注意:Server P ...
- 远程推送-----iOS
前言 说一下我了解的推送 正文 APNs--------Apple Push Notification service 1 远程推送的大概流程及其原理 我们的设备联网时(无论是蜂窝联网还是Wi-Fi联 ...
- Boost.Hana在visual studio 2017 rc中的残缺使用
最新的visual studio还不支持hana,不知道vs2017正式版本出后会不会支持.等不及了,先用rc版试试吧. 1.从https://github.com/boostorg/hana下载或拉 ...
- Javascript—①你好,世界!
新手Perfect教程之Javascript教程①-你好,世界! 前言:不知道Javascript是什么东东的自行度娘或google一下 Javascript在html<head>和< ...
- HBase介绍
欢迎和大家交流技术相关问题:邮箱: jiangxinnju@163.com博客园地址: http://www.cnblogs.com/jiangxinnjuGitHub地址: https://gith ...
- C++ 头文件系列(fstream)
1. 简介 该头文定义了与文件箱关联的流类的4个模版: basic_filebuf basic_ifstream basic_ofstream basic_fstream 和8个类型: filebuf ...