php 爬虫 多线程,读:我用爬虫一天时间“偷了”知乎一百万用户,只为证明PHP是世界上最好的语言...

在互联网上流传着这么一篇文章《我用爬虫一天时间“偷了”知乎一百万用户,只为证明PHP是世界上最好的语言》,不知道知乎的网站管理人员怎么想的,万一给他的领导知道了……

看了他的源码,发现worker.php不就是简化版的workerman框架么,派生出子进程用于采集。

然后我在他的源码包里找到了phpQuery.php,可是没找到调用的地方,倒是在cls_query.php和user.php找到了一大堆正则表达式,我只能说人才啊,放着这么好的工具不用,非要自己用正则实现。

最厉害的是rolling_curl.php中的实现方法,功能全,支持多线程请求。

数据库方面使用了mysql和redis缓存,一天能扒这么多用户说明性能上不是问题。

感慨:

站在知乎的角度:互联网其实充满了机器人,只要有网页,都是公开的,即使是登陆后才能查看,也会暴露给登陆过的机器人。最简单的办法就是抗DDOS自动封IP,cdn厂商都提供这个功能,另外nginx有限速和屏蔽IP的模块,虽然这些办法无法封锁采集,但也能拖慢采集速度以减小损失。

站在旁观者的角度:代码很厉害啊,几个类收下了,有时间可以上上知乎,很良心的网站,不要拿我们的用户数据做坏事。采集开慢点,不能采集太快,这样影响别人访问网站的速度,采集过度就是攻击行为,被封IP也是活该!

给采集者的一点建议:phpQuery.php真心不错,比自己写的正则表达式要容易太多了,万一采集的网页格式发生变化了改起来很麻烦,正则表达式的成本太高。

刚学PHP的时候用的是火车头采集软件,通过界面设置可以获取到一堆采集的数据,处理起来并不轻松。自从认识phpQuery,再也不用火车头了,缺点是占用内存有点高,用完释放内存会好很多。现在作为一名雇员,不得不从别人的网站采集数据,用到phpQuery的地方太多了。

PS:虽然phpQuery很方便也很强大,但是有些情况下不能正确解析某个页面,我猜那篇偷知乎数据的作者可能是遇到了这样的情况,后来我又掌握了一门新的框架《phpQuery和simple_html_dom DOM解析器对比》,操作是复杂了些但是对页面的兼容性要强于phpQuery。再后来,使用nodejs来分析页面更方便了些,毕竟nodejs才是真正的爬虫王者。

另外,这里贴3个函数代码,可以方便处理采集来的数据。

第1个是str_replace的单次替换版本,PHP自带的str_replace只能全部替换://仅替换一次

function str_replace_once($needle, $replace, $haystack) {

// Looks for the first occurence of $needle in $haystack

// and replaces it with $replace.

$pos = strpos($haystack, $needle);

if ($pos === false) {

return $haystack;

}

return substr_replace($haystack, $replace, $pos, strlen($needle));

}

第2个是截取函数,在火车头采集软件中有类似的功能,可以去掉左侧字符和右侧字符,如果找不到左侧和右侧字符则默认不截取。/**

* 用于字符串截取,用于截取2个字符串之间的内容,不含边界

* @param string $haystack

* @param string $left

* @param string $right

* @return string

*/

function subByString($haystack, $left = '', $right = '')

{

$left_pos = false;

$right_pos = false;

if($left == '' || ($left_pos = strpos($haystack, $left)) === false)

{

$start_pos = 0;

}else{

$start_pos = $left_pos;

}

$right_data = substr($haystack, $start_pos + ($left_pos === false ? 0 : strlen($left)));

if($right == '' || ($right_pos = strpos($right_data, $right)) === false)

{

return substr($haystack, $left_pos === false ? 0 : $left_pos+strlen($left));

}else{

$end_pos = $start_pos + $right_pos;

return substr($haystack, $left_pos === false ? 0 : $left_pos+strlen($left), $end_pos-$start_pos);

}

}

第3个是逆向截取函数,依赖上面的subByString,用于逆向截取,实现更变态的功能://逆向截取

function get_middle_reverse($haystack, $left = '', $right = '')

{

$revhtml = strrev($haystack);

$revsuffix = strrev($right);

$revpreffix = strrev($left);

$middle = subByString($revhtml, $revsuffix, $revpreffix);

$result = strrev($middle);

return $result;

}

subByString是一个非常赞的截取函数,只需要传入完整的字符串,左侧字符串(如果没查找到则置为空),右侧字符串(如果没查找到则置为空)进行截取,适合任意编码的字符串(前提是你传入的字符串参数编码一致)。例如:<?php

header('Content-type:text/html;charset=utf-8');

$str = '我是“ABC”长度为3个letter';

//正常截取,左侧和右侧均能查找到

print_r('

');

print_r(subByString($str, '“ABC”长', '3个l'));

print_r('

');

print_r('

');

//非正常截取,不传后2个参数则原字符串返回

print_r(subByString($str));

print_r('

');

print_r('

');

//只传入左侧字符,右侧全部返回

print_r(subByString($str, '“ABC”长'));

print_r('

');

print_r('

');

//只传入右侧字符,左侧全部返回

print_r(subByString($str, '', '3个l'));

print_r('

');

get_middle_reverse是一个更赞的截取函数,可以实现逆向截取。例如:<?php

header('Content-type:text/html;charset=utf-8');

$str = '我是“ABC”长度为3个letter';

print_r('

');

//截取字母l和t之间的字符e,第三个参数定位的是靠左侧的t

print_r(subByString($str, 'l', 't'));

print_r('

');

print_r('

');

//如果我们在截取过程中需要保证右侧的t是最后一个t则需要用到逆向截取

//打印出et,第三个参数定位的是最右侧的t

print_r(get_middle_reverse($str, 'l', 't'));

print_r('

');

逆向截取在网页采集中非常管用,因为你需要的数据可能在标识字符串(网页中唯一字符串)的左侧,例如:<?php

header('Content-type:text/html;charset=utf-8');

//最后一页的超链接,如何才能获取30这个数字

$str = 'lastPage';

//使用逆向截取,将标识字符串功能转移到第三个参数

print_r('

');

//">lastPage是仅有一次的标识字符串,而page=却多次出现

//打印出30

print_r(get_middle_reverse($str, 'page=', '">lastPage'));

print_r('

');

注意:这里的逆向截取依赖strrev函数,我们知道strrev函数仅支持英文字符和英文标点,如果需要中文字符逆向截取请看后面的中文修复方案:

随便收藏,请保留本文地址!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值