常见问题汇总

1、在哪里编写业务代码?

在每个应用的Start目录【/path/to/PHPCreeper-Application/Application/Spider/爬虫项目名称/Start/】下面列有不同的应用实例启动脚本, 这些脚本里的都分别对应有各自的onXXX业务回调,所以所有的业务代码都是在onXXX回调里编写。

2、如何脱离爬山虎应用开发框架进行自由开发?

PHPCreeper-Application 类似于传统的MVC框架的意义,主要是方便开发者进行敏捷开发, 所以说这个框架并不是必须的,不过作者推荐你使用爬山虎应用框架进行开发,相对更加省时省力、快速便捷;当然啦,开发者也完全可以单独引入爬山虎内核引擎,脱离爬山虎应用框架进行自由定制开发,一样简单高效。

以下是一个脱离爬山虎应用框架进行自由开发的简单示例

该启动脚本用来抓取github上按照star排名从高到低的TOP10项目:

<?php 
require "./vendor/autoload.php";

use PHPCreeper\Kernel\PHPCreeper;
use PHPCreeper\Producer;
use PHPCreeper\Downloader;
use PHPCreeper\Parser;
use PHPCreeper\Timer;

//切换语言环境,支持中文和英文,默认是中文【version >= 1.3.7】
//PHPCreeper::setLang('en');

//自v1.4.2起,predis已变更为默认的redis客户端,
//不过也可以切换为基于REDIS扩展的redis客户端.
//PHPCreeper::setDefaultRedisClient('redis');

//设置默认的时区, 默认是`Asia/Shanghai`【version >= 1.5.4】
//PHPCreeper::setDefaultTimezone('Asia/Shanghai');

//设置主进程PID文件【version >= 1.3.8】
//PHPCreeper::setMasterPidFile('/path/to/master.pid');

//根据组件保存相应的应用日志,也可以屏蔽掉相应日志级别的日志。【version >= 1.3.8】
//PHPCreeper::setLogFile('/path/to/phpcreeper.log');

//worker运作模式开关,爬山虎支持支持两种运作模式:【version >= 1.3.2】 
//单worker运作模式 和 多worker运作模式,默认是true即多worker运作模式.
//PHPCreeper::enableMultiWorkerMode(false);

//特别注意:仅单worker运作模式下不依赖redis,所以此时redis的配置可以忽略不管.
//特别注意:自v1.6.4起,redis锁机制已升级并默认使用官方推荐的更安全的分布式红锁,
//只有当所有的redis实例都显式的配置[use_red_lock === false]才会退化为旧版的锁机制.
$config['redis'] = [
    [
        'host'      =>  '127.0.0.1',
        'port'      =>  6379,
        'auth'      =>  false,
        'pass'      =>  'guest',
        'prefix'    =>  'PHPCreeper', 
        'database'  =>  '0',
        'connection_timeout' => 5,
        'read_write_timeout' => 0,
        //'use_red_lock'     => true,   //默认为true使用更安全的分布式红锁
    ],
];

//注意: 此处配置的context是全局context上下文,我们也可以为每条任务设置私有context上下文,
//其上下文成员完全相同,全局context与任务私有context最终采用合并覆盖的策略,具体参考手册。
//http://www.phpcreeper.com/docs/DevelopmentGuide/ApplicationConfig.html
//context上下文成员主要是针对任务设置的,但同时拥有很大灵活性,可以间接影响依赖性服务,
//比如可以通过设置context上下文成员来影响HTTP请求时的各种上下文参数 (可选项,默认为空)
//HTTP引擎默认采用Guzzle客户端,兼容支持Guzzle所有的请求参数选项,具体参考Guzzle手册。
//特别注意:个别上下文成员的用法是和Guzzle官方不一致的,一方面主要就是屏蔽其技术性概念,
//另一方面面向开发者来说,关注点主要是能进行简单的配置即可,所以不一致的会注释特别说明。
$config['task'] = array( 
    //'max_depth'       => 1,
    //'max_number'      => 1000,
    //'max_request'     => 1000,
    //'crawl_interval'  => 1,
    //'limit_domains'   => [],
    'context' => [
        'cache_enabled'   => false,
        'cache_directory' => '/tmp/DownloadCache4PHPCreeper/',
        //..................................................
    ],
); 

function startAppProducer()
{
    global $config;
    $producer = new Producer($config);

    $producer->setName('AppProducer')->setCount(1);
    $producer->onProducerStart = function($producer){
        //task private context
        $context = [];

        //在v1.6.0之前,爬山虎主要使用OOP风格的API来创建任务:
        //$producer->newTaskMan()->setXXX()->setXXX()->createTask()
        //$producer->newTaskMan()->setXXX()->setXXX()->createTask($task)
        //$producer->newTaskMan()->setXXX()->setXXX()->createMultiTask()
        //$producer->newTaskMan()->setXXX()->setXXX()->createMultiTask($task)

        //自v1.6.0开始,爬山虎提供了更加短小便捷的API来创建任务, 而且参数类型更加丰富:
        //注意:仅仅只是扩展,原有的API依然可以正常使用,提倡扩展就是为了保持向下兼容。
        //1. 单任务API:$task参数类型可支持:[字符串 | 一维数组]
        //1. 单任务API:$producer->createTask($task);
        //2. 多任务API:$task参数类型可支持:[字符串 | 一维数组 | 二维数组]
        //2. 多任务API:$producer->createMultiTask($task);

        //使用字符串:不推荐使用,配置受限,需要自行处理抓取结果
        //$task = "https://github.com/search?q=stars:%3E1&s=stars&type=Repositories";
        //$producer->createTask($task);
        //$producer->createMultiTask($task);

        //使用一维数组:推荐使用,配置丰富,引擎内置处理抓取结果
        $task = $_task = array(
            'active' => true,         //是否激活当前任务,只有配置为false才会冻结任务,默认true
            'url' => "https://github.com/search?q=stars:%3E1&s=stars&type=Repositories",
            "rule" => array(          ////如果该字段留空默认将返回原始下载数据
                'title' => ['ul.repo-list div.f4.text-normal > a',      'text'],
                'stars' => ['ul.repo-list div.mr-3:nth-of-typ(1) > a',  'text'],
            ), 
            'rule_name' =>  '',       //如果留空将使用md5($task_id)作为规则名
            'refer'     =>  '',
            'type'      =>  'text',   //可以自由设定类型
            'method'    =>  'get',
            "context"   =>  $context, //任务私有context
        );
        $producer->createTask($task);
        $producer->createMultiTask($task);

        //使用二维数组: 推荐使用,配置丰富,因为是多任务,所以只能调用createMultiTask()接口
        $task = array(
            array(
                'url' => "https://github.com/search?q=stars:%3E1&s=stars&type=Repositories",
                "rule" => array(
                    'title' => ['ul.repo-list div.f4.text-normal > a',      'text'],
                    'stars' => ['ul.repo-list div.mr-3:nth-of-typ(1) > a',  'text'],
                ), 
                //'rule_name' => 'r1', //it will use md5($task_id) as rule_name if leave empty
                "context" => $context,
            ),
            array(
                'url' => "https://github.com/search?q=stars:%3E1&s=stars&type=Repositories",
                "rule" => array(
                    'title' => ['ul.repo-list div.f4.text-normal > a',      'text'],
                    'stars' => ['ul.repo-list div.mr-3:nth-of-typ(1) > a',  'text'],
                ), 
                //'rule_name' => 'r2', //it will use md5($task_id) as rule_name if leave empty
                "context" => $context,
            ),
        );
        $producer->createMultiTask($task);
    };
}

function startAppDownloader()
{
    global $config;
    $downloader = new Downloader($config);

    //set the client socket address based on the listening parser server 
    //注意:如果手动复制了本段代码代码,将汉字【冒号】更改为【:】,不要问为什么文档不直接写【:】
    $downloader->setName('AppDownloader')->setCount(2)->setClientSocketAddress([
        'ws://127.0.0.1冒号8888',
    ]);

    $downloader->onBeforeDownload = function($downloader, $task){
        //disable http ssl verify in any of the following two ways 
        //$downloader->httpClient->disableSSL();
        //$downloader->httpClient->setOptions(['verify' => false]);
    }; 

    //some more downloader callbacks commonly used
    //$downloader->onDownloaderStart = function($downloader){};
    //$downloader->onDownloaderStop  = function($downloader){};
    //$downloader->onStartDownload = function($downloader, $task){};
    //$downloader->onAfterDownload = function($downloader, $download_data, $task){};
    //$downloader->onDownloaderMessage = function($downloader, $parser_reply){};
}

function startAppParser()
{
    $parser = new Parser();
    $parser->setName('AppParser')->setCount(1)->setServerSocketAddress('websocket://0.0.0.0:8888');
    $parser->onParserExtractField = function($parser, $download_data, $fields){
        pprint($fields);
    };

    //some more parser callbacks commonly used
    //$parser->onParserStart = function($parser){};
    //$parser->onParserStop  = function($parser){};
    //$parser->onParserMessage = function($parser, $connection, $download_data){};
    //$parser->onParserFindUrl = function($parser, $sub_url){};
}


//启动生产器
startAppProducer();

//启动下载器
startAppDownloader();

//启动解析器
startAppParser();

//start phpcreeper
PHPCreeper::start();

results matching ""

    No results matching ""