当爬⾍被拒绝时(AccessDenied)
由于要准备测试数据,不得不⼤量爬取某个⽹站的内容。为了防⽌被封,特意将爬⾍设计为单线程同步的爬⾍。结果在爬了⼤约3万个页⾯的时候,对⽅发回Access Denied。等⼀段时间后再启动爬⾍,结果还是Access Denied。这时才明⽩这样的想法太天真了,当初就应该其它⽅法来避免才对。⽽本⽂则记述了这些其它⽅法。
1. 伪装user agent
User agent 是HTTP协议的中的⼀个字段,其作⽤是描述发出HTTP请求的终端的⼀些信息。服务器通过这个字段就可以知道要访问⽹站的是什么⼈了。每个浏览器,每个正规的爬⾍都有其固定的user agent,因
此只要将这个字段改为这些知名的user agent,就可以成功伪装了。不过,不推荐伪装知名爬⾍,因为这些爬⾍很可能有固定的IP,如百度爬⾍。与此相对的,伪装浏览器的user agent是⼀个不错的主意,因为浏览器是任何⼈都可以⽤的,换名话说,就是没有固定IP。推荐准备若⼲个浏览器的user agent,然后每次发送请求的时候就从这⼏个user agents中随机选⼀个填上去。IE的⼏个user agent如下:
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
设置代码如下(假设使⽤JAVA + HttpClient 4.1.2)
HttpGet getMethod = new HttpGet("URL");
getMethod.setHeader("User-Agent", "user agent内容");
2. log in
虽然有些⽹站不登陆就能访问,但是它⼀检测到某IP的访问量有异常,就会马上提出登陆要求。如果是不带验证码的,那么果断登陆吧。不过,在登陆之前要做些准备——查清楚POST登陆请求时要附带哪些参
数。我的做法是先⽤录制登陆过程,然后将这⼀过程导出为jmeter⽂件,最后⽤查看登陆所需的参数。查完后,就可以登陆,具体如下所⽰
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost postMethod = new HttpPost("passportblogs/login.aspx"); //注意⽤post
//登陆博客园所需要的参数
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair("tbUserName", "风炎"));
nvps.add(new BasicNameValuePair("tbPassword", "zero"));
nvps.add(new BasicNameValuePair("btnLogin", "登录"));
nvps.add(new BasicNameValuePair("__EVENTTARGET", ""));
nvps.add(new BasicNameValuePair("__EVENTARGUMENT", ""));
文件访问被拒绝nvps.add(new BasicNameValuePair("__VIEWSTATE", "/wEPDwULLTE1MzYzODg2NzZkGAEFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYBBQtjaGtSZW1lbWJlcm1QYDyKKI9af4b67Mzq2xFaL9Bt")); nvps.add(new BasicNameValuePair("__EVENTVALIDATION", "/wEWBQLWwpqPDQLyj/OQAgK3jsrkBALR55GJDgKC3IeGDE1m7t2mGlasoP1Hd9hLaFoI2G05"));
nvps.add(new BasicNameValuePair("ReturnUrl", "wwwblogs/"));
nvps.add(new BasicNameValuePair("txtReturnUrl", "wwwblogs/"));
postMethod.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
HttpResponse response = ute(postMethod);
由于httpClient会⾃动管理cookie,所以接下来直接get或者post就⾏了。
3. 使⽤代理
如果对⽅⽤某段时间内某IP的访问次数来判定爬⾍,然后将这些爬⾍的IP都封掉的话,以上伪装就失效了。对⽅的这个思路隐含着⼀个假设:爬⾍的访问量必然⽐正常⽤户的⼤很多,因⽽只要使这个假设不成⽴就
可以了。这时就该代理上场了。所谓代理就是介于⽤户与⽹站之间的第三者:⽤户先将请求发到代理,然后代理再发到服务器,这样看起来就像是代理在访问那个⽹站了。这时,服务器会将这次访问算到代理头上。同
时⽤多个代理的话,单个IP的访问量就降下去了,于是就有可能逃过⼀劫。不过,这个⽅法最⼤的问题就是到稳定的代理(有钱买代理的,可以⽆视这句话)。我⽬前是在,但到的⼤部分都不能⽤,少部分能⽤
的也不稳定。求分享好⽤的免费代理。
假设到/买了N个代理,那么要如何管理这些代理呢?我的想法是做⼀个类似于内存池的IP池。这样做的好处是便于管理以及易于扩展。当只有⼀个代理时,其⽤法如下所⽰
DefaultHttpClient httpclient = new DefaultHttpClient();
//此代理不保证你看到的时候还存活
HttpHost proxy = new HttpHost("", 8080);
//如果代理要认证,则加上以下语句
// CredentialsProvider().setCredentials(new AuthScope("proxy adress", proxy port),
/
/ new UsernamePasswordCredentials("username", "password"));
//记得将⽹址拆成以下形式
HttpHost targetHost = new HttpHost("wwwblogs"); //⽹站名前⾯不要加
HttpGet httpget = new HttpGet("/FengYan/");
HttpResponse response = ute(targetHost, httpget);
补充下,如果是ADSL拨号,那么⽆需担⼼被封IP,因为⼀般来说,当你重新拨号时,你会得到⼀个不⼀样的IP。
4. 降低访问频率
如果说不到⼜免费⼜稳定的代理呢?那只好⽤最后⼀招了——降低访问频率。这样做可以达到与⽤代理⼀样的效果——防⽌被对⽅从访问量上看出来。当然,在抓取效率上会差很多。此外,降低访问频率只是⼀
个指导思想,在这个思想下,可以得到很多具体做法,例如:每抓取⼀个页⾯就休息随机秒(个⼈感觉⽐固定时间的要好);限制每天抓取的页⾯数量。
5. 总结
防⽌被封的“理”是伪装成正常⽤户,只要按着这个“理”⾛,总能到具体的“法”。虽说如此,对于⼀个接触爬⾍不久的⼩⽩,例如在下,是很难知道正常⽤户访问⼀个⽹站时的所有细节的。因此,知道些反爬⾍的“法”,然后有针对地进⾏拆招还是⼗分必要的。描述反爬的“法”的⽂章,推荐“”。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论