• 欢迎来到我的博客
  • [email protected]

修复、更新 phpspider 框架

学习笔记 tianlan 1年前 (2020-08-18) 963次浏览 0个评论 扫描二维码
文章目录[隐藏]

phpspider

是一个 php 爬虫框架,不得不说功能很 nice。

文档:https://doc.phpspider.org/

github:https://github.com/owner888/phpspider

过时函数

我的环境:

  • linux nginx php7.2 宝塔
  • php redis 拓展 no-debug-non-zts-20170718/redis.so
  • Redis 6.0.6

过时了的函数(我目前发现的):

// core/queue.php:993
//其中 lSize() 过时,应该用 lLen()
return self::$links[self::$link_name]->lSize($key);

发现的 bug

children 字段相关

某个字段的 children 字段,当

'source_type'  => "attached_url"

那么 attached_url 是不应该进入到请求队列的。

作者在注释中也说明了这点:

修复、更新 phpspider 框架

可是在 2112 行,调用的 request_url() 方法,确确实实会让 url 加入到队列(当请求失败时),具体代码我就不贴了,太多了不好贴。

我是这样修复的:

先标记一下,这是 attached_url :

$link['url'] = $collect_url;
/**
 * 天蓝二开
 * 标记一下 attached_url
 */
$link['url_type'] = 'attached_url';
$link = $this->link_uncompress($link);

然后在 request_url() 方法中对有这个标记的 $link 单独处理:

public function request_url($url, $link = array())
{
    ...

    if ($http_code != 200) {
        // 如果是301、302跳转, 抓取跳转后的网页内容
        if ($http_code == 301 || $http_code == 302) {
            $info = requests::$info;
            //if (isset($info['redirect_url'])) 
            if (!empty($info['redirect_url'])) {
                $url                      = $info['redirect_url'];
                requests::$input_encoding = null;
                $method                   = empty($link['method']) ? 'get' : strtolower($link['method']);
                $params                   = empty($link['params']) ? array() : $link['params'];
                $html                     = requests::$method($url, $params);
                // 有跳转的就直接获取就好,不要调用自己,容易进入死循环
                //$html = $this->request_url($url, $link);
                if ($html && !empty($link['context_data'])) {
                    $html .= $link['context_data'];
                }
            } else {
                return false;
            }
        } else {

            /**
             * 天蓝二开
             * 在这里处理 attached_url 阻止进入队列
             * 好像还需要对 采集次数什么的进行处理,麻烦,我这里就不搞了
             * 所以可能会导致采集面板中的那些次数有误差
             */
            if (!empty(self::$configs['max_try']) and $link['url_type'] == 'attached_url') {
                $now_try_num = 0;


                do {
                    $now_try_num++;
                    if ($now_try_num < $link['max_try']) {
                        log::error("天蓝二开 Failed to download [attached_url] page {$url}, retry({$now_try_num})");
                        $html = requests::$method($url, $params);
                    } else {
                        //超过最大次数,没办法,返回假吧
                        return false;
                    }
                } while (in_array(requests::$status_code, array('0', '502', '503', '429', '507')));


                return $html;
            }


            if (!empty(self::$configs['max_try']) and $http_code == 407) {
                // 扔到队列头部去, 继续采集
                $this->queue_rpush($link);
                log::error("Failed to download page {$url}");
                self::$collect_fail++;
            } elseif (!empty(self::$configs['max_try']) and in_array($http_code, array('0', '502', '503', '429'))) {
                // 采集次数加一
                $link['try_num']++;
                // 抓取次数 小于 允许抓取失败次数
                if ($link['try_num'] < $link['max_try']) {
                    // 扔到队列头部去, 继续采集
                    $this->queue_rpush($link);
                }
                log::error("Failed to download page {$url}, retry({$link['try_num']})");
            } else {
                log::error("Failed to download page {$url}");
                self::$collect_fail++;
            }
            log::error("HTTP CODE: {$http_code}");
            return false;
        }
    }

    ...
}

重试次数无效

设置了 max_try 但是还是尝试一次:

2020-08-26 14:20:52 [debug] Find scan page: $url

2020-08-26 14:20:53 [error] Failed to download page $url, retry(1)

2020-08-26 14:20:53 [error] HTTP CODE: 0

这样之后就没有下文了!不会进行重试,上面的 (1) 只是尝试次数,而非 重试次数。

bug 定位:

public function queue_rpush($link = array(), $allowed_repeat = false)
{
    ...
    if (self::$use_redis)
    {...}
    else
    {
       /**
        * 天蓝注
        * 作者说 self::$collect_urls 是【要抓取的URL数组】
        * 在这段代码中,只要 url 入队了,就会被加入 $collect_urls
        * 那么当 url 下载失败,重新入队时,就会因为
        * !array_key_exists($key, self::$collect_urls) === false
        * 而无法入队
        * 这显然不合适
        *
        * 上面使用 redis 的分支也存在相似问题
        *
        * 解决办法:在 重试url 入队之前,将 url 移出 self::$collect_urls
        */
        $key = md5($url);
        if (!array_key_exists($key, self::$collect_urls))
        {
            self::$collect_urls_num++;
            self::$collect_urls[$key] = time();
            array_unshift(self::$collect_queue, $link);
            $status = true;
        }
    }
    return $status;
}

结语

phpspider 是一款很棒的开源产品,希望开发者可以尽快修复,越做越好!


天蓝, 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:修复、更新 phpspider 框架
喜欢 (1)
[[email protected]]
分享 (0)

您必须 登录 才能发表评论!