记一次企业级爬虫系统升级改造(六):基于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 ...
随机推荐
- Excel实用知识3
纯手打,可能有错别字,使用的版本是office2013 转载请注明出处 http://www.cnblogs.com/hnnydxgjj/p/6343914.html ,谢谢 数据透视表 数据透视表是 ...
- 【G】开源的分布式部署解决方案(二) - 好项目是从烂项目基础上重构出来的
分析目前项目结构 眼前出现这么一坨坨的文件夹,相信很多人已经看不下去了.是的,首先就是要把它给做掉. 按照这个项目文件夹的命名意图,大概可以划分如下: 1.Business:业务代码 2.Data:数 ...
- Hadoop权威指南:HDFS-目录,查询文件系统,删除文件
Hadoop权威指南:HDFS-目录,查询文件系统,删除文件 [TOC] 目录 FileSystem实例提供了创建目录的方法 public boolean mkdirs(Path f) throws ...
- 【求Java工程师/专家】大型互联网公司急招
互联网行业排名Top公司,目前项目扩张阶段,需求数量较多的JAVA中高端后台开发人员,需要有分布式系统开发经验,年后有找工作的同学可以联系我了. 工作地点:杭州 岗位要求: 1.精通Java SE和J ...
- LCD驱动移植在在mini2440(linux2.6.29)和FS4412(linux3.14.78)上实现对比(deep dive)
1.Linux帧缓冲子系统 帧缓冲(FrameBuffer)是Linux为显示设备提供的一个接口,用户可以将帧缓冲看成是显示内存的一种映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作 ...
- 如何编写一个gulp插件
很久以前,我们在"细说gulp"随笔中,以压缩JavaScript为例,详细地讲解了如何利用gulp来完成前端自动化. 再来短暂回顾下,当时除了借助gulp之外,我们还利用了第三方 ...
- 如何在Oracle中复制表结构和表数据 【转载】
1. 复制表结构及其数据: create table table_name_new as select * from table_name_old 2. 只复制表结构: create table ta ...
- excel中VBA的使用
遇到的问题 在工作中遇到了一点小小的问题,需要给我负责带的班级的同学们测试男生1000米,女生800米的成绩.表格是这样的: 体育成绩表 序号 班级 姓名 性别 男1000.女800 成绩 1 1 张 ...
- Linux输入子系统(一) _驱动编码
输入设备都有共性:中断驱动+字符IO,基于分层的思想,Linux内核将这些设备的公有的部分提取出来,基于cdev提供接口,设计了输入子系统,所有使用输入子系统构建的设备都使用主设备号13,同时输入子系 ...
- Asp.net mvc 知多少(八)
本系列主要翻译自<ASP.NET MVC Interview Questions and Answers >- By Shailendra Chauhan,想看英文原版的可访问[http: ...