CUrl 蜘蛛 优化 CURLOPT_HEADERFUNCTION

正搞一个小蜘蛛,用 CUrl 写的,遇到一个问题,分析完 url 后,有可能遇到 rar 或 jpg 等资源文件,也是要下载回来分析内容。

这样的做法太笨了,有很多缺点:

  1. 浪费带宽,文件也许很大
  2. 文件无用,下载回来也无法分析文件内容

怎么解决?

看浏览器会发送 Accept 指令,告诉服务器可接受的内容类型,但这不能阻止服务器返回不接受的内容,即哪怕请求的资源不在 Accept 列表中,仍然会把文件返回给客户端。

这方法不行。

想着,有没有办法,在得到服务器 response 的时候先分析 header,如果不是可接受的类型,就断掉连接,不必下载后续内容?

如果用 fsockopen 写的网络通讯接口,这一点很好实现。但 CUrl 怎么控制?

仔细看文档,找到一个选项 CURLOPT_HEADERFUNCTION。

这个选项要给一个回调函数作为参数,回调函数相当于一个触发器,CUrl 会把每一条 response 的 header 指令传给这个函数,由函数来决定如何执行后面的步骤。

回调函数要定义 2 个参数,第 1 个是 CUrl 的资源标识符,第 2 个是单独的一条 header 字符串。

如果想让 CUrl 继续下载后续内容,那么回调函数应该返回 header 字符串的长度:

return strlen($strOneHeader);

如果不想继续下载,直接返回数字 0,那么 CUrl 就会发送 TCP 的终止连接的指令,不会继续下载后续内容了。

加上这个触发器,经过测试,我的小蜘蛛可以成功地忽略非 text/html 类型的文件,大大加快了抓取速度,避免了很多问题!

小提示,给 CURLOPT_HEADERFUNCTION 设置回调函数的时候,文档上说要一个字符串形式的函数名作为参数。

这不准确。

实际上 PHP 可以指定任意类型的回调函数,可以是纯函数、类的静态方法和对象的方法:

  • 纯函数:$callback = ‘my_callback_func’;
  • 类常量:$callback = array(‘NAME_OF_CLASS’, ‘nameOfMethod’);
  • 对象方法:$callback = array($object, ‘publicMethod’);

完。

Tags: