Heim > Artikel > Backend-Entwicklung > 大家有什么好方法,防止页面被机器人curl抓取?
以前一直研究抓取别人的页面内容,现在想请教一下各位前辈,根据大家的经验,有什么好方法防止页面被抓取吗?
我以前遇到2种情况,比较难抓取(指的是自动程序批量获取).
第一种:生成复杂的cookie验证,每几分钟过期一次,要curl抓取的话,每次都要手动粘贴cookie到CURLOPT_HEADER里。
第二种:如果一个IP在一段时间内频繁的抓取(指的是类似GOOGLE的搜索结果页面),那么隔一段会跳出一个验证码,需要人工验证。
别的,像内容写进js里,再打印到页面里之类的都可以破解以后批量获取。
各位前辈,请教你们的高见,最好能秀一下大家的代码,供大家切磋、破解。
图片....
我知道一个貌似是reboot.txt的文件放在网站中可以设置搜索引擎抓取页面。
期待牛人来回答一下,我就学习一下。
curl好像可以跟浏览者搞的一模一样啊,可以用其他思路搞,比如加很多垃圾代码,里面有你域名的连接,无规则的加入,像织梦防采集那样,这样采集你的人,他很难通过正则匹配到你的内容,就算匹配的差不多,每个页面都会有几个你的链接,如果他愿意采集,呵呵,免费外链也可以啊。
只要是浏览器能看到的,curl就能抓到
可灵活使用 CURLOPT_COOKIESESSION、CURLOPT_COOKIE、CURLOPT_COOKIEFILE、CURLOPT_COOKIEJAR 来处理 cookie,并不存在楼主的“每次都要手动粘贴cookie到CURLOPT_HEADER里”
虽然可以用js代码验证并跳转来阻止curl的动作,但下载 linux 下执行js代码的php扩展业已存在了
唯一可行的方案就是检测访问的频率
目前很多网站都是用此法,不过不是弹出对话框。而是输出无效的页面内容,让你白干一场
唯一可行的方案就是检测访问的频率
目前很多网站都是用此法,不过不是弹出对话框。而是输出无效的页面内容,让你白干一场
伟大的斑竹大人,有没有实例代码供小弟学习一下?谢谢。
我也来这里学习一下啊
应该无法防止机器人抓取网页吧,唯一可行的方案就是检测访问的频率~~~
如何最经济的检测访问的频率呢?建立临时数据表?session?
我大概几年前遇到过一个机票网站,它们采用了一种方法,令我当时束手无策。
刚才又回忆了一下,现在发出来,大家一起探讨下。
当然我不能完全获悉它的所有细节,只是根据当时的研究自己做了一些推测,他使用的方法大概如下:
页面第一次加载后,只是将一些基本的html加载出来,js会通过ajax将关键性的数据通过ajax请求回来,返回的可以是json,然后在通过页面js讲json解析,绘制到页面上。问题的关键是做那次ajax请求时,需要带一个特殊的参数过去才能正确获得数据。并且这个通过这个参数获得数据后,这个参数就失效了。而这个参数应该是有一定算法的,并且由这个动态页面在加载的同时生成。
做法大概可以这样:
1 请求页面a.php,a.php页面在生成需要返回浏览器的html的同时,根据特定算法生成一个验证串abc123(并且每次请求都生成的串都不一样),并写入数据库或第三方存储媒介。
2 a.php的html返回浏览器后,拼接出需要ajax请求的url,并且最后附加一个参数,就是刚才生成的验证串abc123。然后执行ajax的请求。接收ajax请求的页面,去数据库中查询一下这个abc123是否存在。如果存在,则返回正确的json数据,否则不返回或返回异常。
这样做,对于采集的一方来说。当你去抓那个a.php时,抓到之后ajax会自动执行一次。这个时候,你抓回来的页面虽然可以看到a.php中ajax请求得到的数据,你会发现源代码中没有它。而你想再用a.php的html源代码中的ajax url去请求一次,发现生成的那个abc123验证串已经失效了。
做个实验吧,先不考虑验ajax证串的问题:
1.php(也就是我们抓取方的脚本)
<?phpfunction request( $url, $header = '', $postfields = '' ){ $ch = curl_init(); $options = array( CURLOPT_URL => $url, CURLOPT_HEADER => 0, //CURLOPT_HTTPHEADER => $header, CURLOPT_NOBODY => 0, CURLOPT_PORT => 80, CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $postfields, CURLOPT_RETURNTRANSFER => 1, CURLOPT_FOLLOWLOCATION => 1, //CURLOPT_COOKIEJAR => $cookie_jar, //CURLOPT_COOKIEFILE => $cookie_jar, //CURLOPT_SSL_VERIFYPEER => 0, //CURLOPT_SSL_VERIFYHOST => 1, CURLOPT_TIMEOUT => 30 ); curl_setopt_array($ch, $options); $code = curl_exec($ch); curl_close($ch); return $code;}$url = 'http://www.angryfrog.com/2.php';echo request($url);
<script src="./js/jquery-1.7.1.min.js"></script><script> $(document).ready(function(){ $.get('http://www.angryfrog.com/3.php', '', function(data){ d=$.parseJSON(data);$('#tmp').html(d.node1);}); });</script><a id="tmp"></a>
<?php$a = array( 'node1' => 'data1', 'node2' => 'data2');echo json_encode($a);
sorry,突然想到,我那个想法是有bug的。
我只测试了同域的情况下,如果是真实情况的话,ajax请求是不可能被自动执行成功的。因为跨域了。
当我们从自己的服务器去请求对方页面,得到html和js,包括那些ajax。回到我们的浏览器后。域就变成我们自己服务器的了,这时页面上的ajax不可能跨域请求成功对方的ajax接口。也就谈不上那个生成的验证码被自动销毁的情况了。看来这种方法不行。
又仔细回忆了一下(时间实在太久远了)。当时我确实是看到对方页面上的ajax,并且包含了一个可疑的参数,每次请求得到后的都不同(而且确认不是为了防止cache用的),但当我自己尝试带着这个参数去请求这个url时,什么结果也得不到。而通过它的页面,请求这个地址却可以返回数据。不知是什么原因,referer、user-agent我也都模拟了。
可不可以这样?a.php页面生成验证串写入数据库后,这个串在很短的时间内就会失效。比如1秒。这点用redis或memcached就很容易做到,给那个key做一个失效时间。
当我们通过脚本抓取a.php后,需要分析它的源代码,找出ajax请求的地址,再去请求,时间会比较长,这个过程可能会超过1秒,那个验证串已经失效了,ajax接口则不会成功返回数据。而正常访问它的页面,页面执行ajax,速度会比较快不会超过1秒,因此能成功得到数据。
明天有时间,我把完整的代码写下试试看。
php_v8js 的作用是在 php 中执行 js 代码
而楼上的描述使用 php 去模拟 js 的动作
这显然不是一回事
这个问题其实说到底是看哪一方不惜工本
防的一方不惜工本,迫使抓的一方在考虑成本效益后放弃
抓的一方不惜工本,防的一方在考虑用户流失后放弃
你们还没见过那些疯狂的人而已
总的来说,在open web时代,抓的一方所花费成本要低很多
刘明,等看
采用加密算法生成相对复杂的认证标志,只有带这个标志才可访问,同时入口处提供验证码识别。
而验证码识别会降低用户体验。
而只是使用复杂的认证标志,一旦生成算法破解,一样可以批量发起请求。
总的来说,人能通过浏览器访问无非就是发送http请求,那么机器同样可以做到,无非是机器要先采集数据,分析清楚访问流程而已。
@ShadowSniper, 很好的实例哦,开阔思路了。
这就想到于:
浏览器访问A页面时,生成一个随机码,该随机码作为ajax参数传递到B页面,B页面需要验证这个随机码的合法性,然后返回数据到A页面。
所以直接curl A页面的话,什么也得不到。
直接curl B页面(ajax页面的话),由于没有合法的随机码,所以还是什么也得不到。
@ShadowSniper, 很好的实例哦,开阔思路了。
这就想到于:
浏览器访问A页面时,生成一个随机码,该随机码作为ajax参数传递到B页面,B页面需要验证这个随机码的合法性,然后返回数据到A页面。
所以直接curl A页面的话,什么也得不到。
直接curl B页面(ajax页面的话),由于没有合法的随机码,所以还是什么也得不到。
错了吧?
直接curlA,得到了一个随机码,然后模拟curlB并带着刚才那个随机码,不就获取最终想要的数据了么。
同时,你说的“B页面需要验证这个随机码的合法性,然后返回数据到A页面”,这个数据就是最终想要的数据,而这个数据只需要带上随机码就可以了。
@ShadowSniper, 很好的实例哦,开阔思路了。
这就想到于:
浏览器访问A页面时,生成一个随机码,该随机码作为ajax参数传递到B页面,B页面需要验证这个随机码的合法性,然后返回数据到A页面。
所以直接curl A页面的话,什么也得不到。
直接curl B页面(ajax页面的话),由于没有合法的随机码,所以还是什么也得不到。
难道你防的仅仅是curl?那整个造盾思路就错了
要防的是这个 点击看维基-webkit
现在基于webkit的矛(非GUI浏览器)多的是,远超curl了
csdn
都被抓取
http://s.yanghao.org/program/viewdetail.php?i=393421
引用 18 楼 changjay 的回复:@ShadowSniper, 很好的实例哦,开阔思路了。
这就想到于:
浏览器访问A页面时,生成一个随机码,该随机码作为ajax参数传递到B页面,B页面需要验证这个随机码的合法性,然后返回数据到A页面。
所以直接curl A页面的话,什么也得不到。
直接curl B页面(ajax页面的话),由于没有合法的随机码,所以还是什……
我说的那个方法,大概思路是对的。但我一开始没考虑跨域的问题。
a页面生成验证码,写入db。a带着这个验证码去请求b接口,b接口拿到a传过来的验证码,去db里查询是否存在,如果存在,就返回正确数据,并且从db中清除掉这个验证码。
所以由a页面生成的验证码,只能使用一次。
当你模拟请求a页面,a不光会生成一个验证码,同时会把这个流程走完,并且销毁掉这个验证码。也会返回数据,但这一次你无法得到a页面返回的数据(只能看到,但得不到。不信拿我的那几个例子去试验下)
而一般来说,页面中含有ajax的二次请求,我们应该在第一次请求得到页面中ajax请求的地址后,用正则分析出a页面生成的验证码和他ajax请求的地址,再用php带着这个验证码去请求一次。希望通过这样,来得到正确的数据。但可惜的是,在你第一次模拟请求a页面时,他已经把整个流程走完了,包括页面中的ajax会自动执行。那个生成验证码也被销毁了。所以这里就造成了个矛盾的问题。
这种情况,抓取方和被抓取方处于同域的情况下,是可以实现的。
但实际情况中,抓取方不可能和被抓取方处于同域,所以请求a页面后,可以得到生成的验证码,但是ajax请求不会成功,因为跨域。所以那个生成的验证码也不会被销毁。那么我们就可以拿到验证码后,再用php去请求一下那个ajax地址来获得正确的数据。
引用 18 楼 changjay 的回复:@ShadowSniper, 很好的实例哦,开阔思路了。
这就想到于:
浏览器访问A页面时,生成一个随机码,该随机码作为ajax参数传递到B页面,B页面需要验证这个随机码的合法性,然后返回数据到A页面。
所以直接curl A页面的话,什么也得不到。
直接curl B页面(ajax页面的话),由于没有合法的随机码,所以还是什……
a.php
function request( $url, $header = '', $postfields = '' ){ $ch = curl_init(); $options = array( CURLOPT_URL => $url, CURLOPT_HEADER => 0, //CURLOPT_HTTPHEADER => $header, CURLOPT_NOBODY => 0, CURLOPT_PORT => 80, CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $postfields, CURLOPT_RETURNTRANSFER => 1, CURLOPT_FOLLOWLOCATION => 1, //CURLOPT_COOKIEJAR => $cookie_jar, //CURLOPT_COOKIEFILE => $cookie_jar, //CURLOPT_SSL_VERIFYPEER => 0, //CURLOPT_SSL_VERIFYHOST => 1, CURLOPT_TIMEOUT => 30 ); curl_setopt_array($ch, $options); $code = curl_exec($ch); curl_close($ch); return $code;}$url = 'http://www.angryfrog.com/b.php';echo request($url);
<script>alert(123);</script>
ShadowSniper研究的比较深,谢谢。好好再琢磨一下。
抓数据,一般只抓页面,页面里的图片,CSS,JS等等都是不会继续向服务器请求的。所以很容易判断哪些用户的请求是爬虫,哪些不是:)
访问频率检查方案方面,请问大家有什么经验指点?
//第一步:入口文件检测IP黑名单实现禁止访问
//第二步:访问频率检测
$ip = get_client_ip(); //获取访问者IP
$ipCode = md5($ip);
$次数 = intval($cache->get($ipCode)); //把null转成0
if($次数 set($ipCode, ++$次数, 3000); //缓存过期时间为3000毫秒=3秒
else{
//将该IP加入黑名单,N天/N个小时后解除黑名单
}
建议在 .htaccess直接屏蔽对方的 IP地址段。
当然,也可以考虑iptables;
用js joson可以增加难度
抓数据,一般只抓页面,页面里的图片,CSS,JS等等都是不会继续向服务器请求的。所以很容易判断哪些用户的请求是爬虫,哪些不是:)
怎么理解,分析客户端是否下载了CSS,JS文件?这个怎么判断?还有怎么可以分辨出是搜索引擎爬虫还是不良爬虫?
引用 25 楼 LuciferStar 的回复:抓数据,一般只抓页面,页面里的图片,CSS,JS等等都是不会继续向服务器请求的。所以很容易判断哪些用户的请求是爬虫,哪些不是:)
怎么理解,分析客户端是否下载了CSS,JS文件?这个怎么判断?还有怎么可以分辨出是搜索引擎爬虫还是不良爬虫? 这个应该是服务器上防止采集的一个策略吧。
估计得服务器软件进行行为控制了。
mark 我也碰到过这样的问题 好像大多防这个都是服务器去处理了
sorry,突然想到,我那个想法是有bug的。
我只测试了同域的情况下,如果是真实情况的话,ajax请求是不可能被自动执行成功的。因为跨域了。
当我们从自己的服务器去请求对方页面,得到html和js,包括那些ajax。回到我们的浏览器后。域就变成我们自己服务器的了,这时页面上的ajax不可能跨域请求成功对方的ajax接口。也就谈不上那个生成的验证码被自动销毁……
大牛,腾讯新闻的好像也是这种高法,内容关键性的js全部是动态的 还各种包含,呵呵,头大