国产+高潮+在线,国产 av 仑乱内谢,www国产亚洲精品久久,51国产偷自视频区视频,成人午夜精品网站在线观看

webman爬山虎插件(PHP爬蟲(chóng)引擎)

v1.0.6 版本
2024-10-20 版本更新時(shí)間
300 安裝
14 star

簡(jiǎn)介

webman的爬山虎插件: 讓爬取工作變得更加簡(jiǎn)單高效。

更新

  • 本插件的使用說(shuō)明最近一次更新時(shí)間是:2024-10-20,由于爬山虎迭代版新增了許多新特性和API,而且完全向下兼容,所以建議將本插件更新至最新版v1.0.6,同時(shí)確保將爬山虎同步更新至>= v1.9.9。
  • 重大更新:爬山虎自v1.8.7起,開(kāi)始支持無(wú)頭瀏覽器即支持運(yùn)行JavaScript代碼及其渲染的動(dòng)態(tài)頁(yè)面。使用非常簡(jiǎn)單,無(wú)縫切換,只需要通過(guò)$context上下文啟用或禁用無(wú)頭瀏覽器開(kāi)關(guān)即可。

安裝

composer require blogdaren/webman-phpcreeper

效果圖

使用說(shuō)明

  • 首先要明確一個(gè)概念:爬山虎有三種容器分別是:生產(chǎn)器、下載器、解析器。
  • 編寫(xiě)一個(gè)爬蟲(chóng)非常簡(jiǎn)單:配置搞定以后,只需要在對(duì)應(yīng)容器內(nèi)的onXXXX回調(diào)方法內(nèi)編寫(xiě)業(yè)務(wù)邏輯即可。
  • 由于爬蟲(chóng)應(yīng)用相對(duì)WEB應(yīng)用而言比較獨(dú)立,所以app內(nèi)的爬蟲(chóng)目錄結(jié)構(gòu)建議自行獨(dú)立部署。
  • 首先在自己的app項(xiàng)目下手動(dòng)創(chuàng)建有效的爬蟲(chóng)目錄,比如:app/spider。
  • 然后在爬蟲(chóng)目錄內(nèi)app/spider創(chuàng)建相應(yīng)的容器句柄類Hanlder。
  • 最后在對(duì)應(yīng)容器內(nèi)的onXXXX回調(diào)方法內(nèi)編寫(xiě)業(yè)務(wù)邏輯。
  • 若啟用無(wú)頭瀏覽器開(kāi)關(guān),默認(rèn)使用無(wú)頭chrome驅(qū)動(dòng),反之使用默認(rèn)的guzzle驅(qū)動(dòng),若爬取的不是動(dòng)態(tài)頁(yè),建議禁用。

舉個(gè)例子

注意:提供的例子如果未能按照預(yù)期工作,請(qǐng)檢查修改爬取規(guī)則,因?yàn)樵凑綝OM極可能更新了。

模擬抓取未來(lái)3天內(nèi)北京的天氣預(yù)報(bào)

開(kāi)發(fā)步驟

1、創(chuàng)建爬蟲(chóng)目錄:app/spider

2、創(chuàng)建生產(chǎn)器句柄類文件:app/spider/Myproducer.php

<?php
/**
 * @script   Myproducer.php
 * @brief    生產(chǎn)器Handler
 * @author   blogdaren<blogdaren@163.com>
 * @create   2022-04-01
 */

namespace app\spider;

use PHPCreeper\Timer;
use PHPCreeper\Crontab;

class Myproducer extends \Webman\PHPCreeper\Producer
{
    /**
     * @brief   生產(chǎn)任務(wù)
     *
     * @return  mixed
     */
    public function makeTask()
    {
        //注意:這里說(shuō)的版本并不是webman爬山虎插件的版本,而是爬山虎的版本.
        //注意:這里說(shuō)的版本并不是webman爬山虎插件的版本,而是爬山虎的版本.
        //注意:這里說(shuō)的版本并不是webman爬山虎插件的版本,而是爬山虎的版本.

        //在v1.6.0之前,爬山虎主要使用OOP風(fēng)格的API來(lái)創(chuàng)建任務(wù):
        //$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開(kāi)始,爬山虎提供了更加短小便捷的API來(lái)創(chuàng)建任務(wù), 而且參數(shù)類型更加豐富:
        //注意:僅僅只是擴(kuò)展,原有的API依然可以正常使用,提倡擴(kuò)展就是為了保持向下兼容。
        //1. 單任務(wù)API:$task參數(shù)類型可支持:[字符串 | 一維數(shù)組]
        //2. 單任務(wù)API:$producer->createTask($task);
        //3. 多任務(wù)API:$task參數(shù)類型可支持:[字符串 | 一維數(shù)組 | 二維數(shù)組]
        //4. 多任務(wù)API:$producer->createMultiTask($task);

        //使用字符串:不推薦使用,配置受限,需要自行處理抓取結(jié)果
        //$task = "http://www.weather.com.cn/weather/101010100.shtml";
        //$producer->createTask($task);
        //$producer->createMultiTask($task);

        //任務(wù)私有context,其上下文成員與全局context完全相同,最終會(huì)采用合并覆蓋策略
        $private_task_context = array(
            //是否緩存下載數(shù)據(jù)(可選項(xiàng),默認(rèn)false)
            'cache_enabled'   => true,
            //緩存下載數(shù)據(jù)存放目錄  (可選項(xiàng),默認(rèn)位于系統(tǒng)臨時(shí)目錄下)
            'cache_directory' => sys_get_temp_dir() . '/DownloadCache4PHPCreeper/',
            //在特定的生命周期內(nèi)是否允許重復(fù)抓取同一個(gè)URL資源(可選項(xiàng),默認(rèn)false)
            'allow_url_repeat' => true,
            //要不要跟蹤完整的HTTP請(qǐng)求參數(shù),開(kāi)啟后終端會(huì)顯示完整的請(qǐng)求參數(shù) [默認(rèn)false]
            'track_request_args' => true,
            //要不要跟蹤完整的TASK數(shù)據(jù)包,開(kāi)啟后終端會(huì)顯示完整的任務(wù)數(shù)據(jù)包 [默認(rèn)false]
            'track_task_package' => true,
            //在v1.6.0之前,如果rulename留空,默認(rèn)會(huì)使用 md5($task_url)作為rulename
            //自v1.6.0開(kāi)始,如果rulename留空,默認(rèn)會(huì)使用 md5($task_id) 作為rulename
            //所以這個(gè)配置參數(shù)是僅僅為了保持向下兼容,但是不推薦使用,因?yàn)橛袧撛陔[患
            //換句話如果使用的是v1.6.0之前舊版本,那么才有可能需要激活本參數(shù) [默認(rèn)false]
            'force_use_md5url_if_rulename_empty' => false,
            //強(qiáng)制使用多任務(wù)創(chuàng)建API的舊版本參數(shù)風(fēng)格,保持向下兼容,不再推薦使用 [默認(rèn)false]
            'force_use_old_style_multitask_args' => false,
            //設(shè)置http請(qǐng)求頭:默認(rèn)引擎會(huì)自動(dòng)偽裝成常見(jiàn)的各種隨機(jī)User-Agent
            'headers' => [
                //'User-Agent' => 'Mozilla/5.0 Chrome/124.0.0.0 Safari/537.36',
                //'Accept'     => 'text/html,*/*',
            ],
            //cookies成員的配置格式和guzzle官方不大一樣,屏蔽了cookieJar,取值[false|array]
            'cookies' => [
                //'domain' => 'domain.com',
                //'k1' => 'v1',
                //'k2' => 'v2',
            ],
            //無(wú)頭瀏覽器,如果是動(dòng)態(tài)頁(yè)面考慮啟用,否則應(yīng)當(dāng)禁用 [默認(rèn)使用chrome且為禁用狀態(tài)]
            'headless_browser' => ['headless' => false, /*更多其他無(wú)頭參數(shù)*/],
            //除了內(nèi)置參數(shù)之外,還可以自由配置自定義參數(shù),在上下游業(yè)務(wù)鏈應(yīng)用場(chǎng)景中十分有用
            'user_define_arg1' => 'user_define_value1',
            'user_define_arg2' => 'user_define_value2',
            //更多其他上下文參數(shù)詳見(jiàn)官方手冊(cè)
        );

        $task = array(
            'active' => true,       //是否激活當(dāng)前任務(wù),只有配置為false才會(huì)凍結(jié)任務(wù),默認(rèn)true
            'url'    => 'http://www.weather.com.cn/weather/101010100.shtml',
            "rule" => array(        //如果該字段留空默認(rèn)將返回原始下載數(shù)據(jù)
                '日子' => ['div#7d ul.t.clearfix h1',      'text', [], 'function($field_name, $data){
                    return  date("Y-m-d") . " | " . $data; 
                }'],                //關(guān)于回調(diào)字符串的用法務(wù)必詳看官方手冊(cè)
                '天氣'  => ['div#7d ul.t.clearfix p.wea',   'text'],
                '溫度'  => ['div#7d ul.t.clearfix p.tem',   'text'],
            ),
            'rule_name' =>  '',     //如果留空將使用md5($task_id)作為規(guī)則名
            'refer'     =>  '',
            'type'      =>  'text', //已喪失原本的概念設(shè)定,可以自由設(shè)定類型
            'method'    =>  'get',
            'context'   =>  $private_task_context,
        );

        $this->createTask($task);
    }

    /**
     * @brief    使用無(wú)頭瀏覽器爬JavaScript渲染的取動(dòng)態(tài)頁(yè)面
     *
     * @return   mixed
     */
    public function makeDynamicTask()
    {
        $private_task_context = [
            //是否緩存下載數(shù)據(jù)(可選項(xiàng),默認(rèn)false)
            'cache_enabled'   => true,
            //緩存下載數(shù)據(jù)存放目錄  (可選項(xiàng),默認(rèn)位于系統(tǒng)臨時(shí)目錄下)
            'cache_directory' => sys_get_temp_dir() . '/DownloadCache4PHPCreeper/',
            //無(wú)頭瀏覽器,如果是動(dòng)態(tài)頁(yè)面考慮啟用,否則應(yīng)當(dāng)禁用 [默認(rèn)使用chrome且為禁用狀態(tài)]
            'headless_browser' => ['headless' => true, /*更多其他無(wú)頭參數(shù)*/],
        ];

        $dynamic_task = array(
            'url' => "https://www.toutiao.com",
            'rule' => array(
                '今日頭條熱榜標(biāo)題' => ['div.show-monitor ol li a', 'aria-label'],
                '今日頭條熱榜鏈接' => ['div.show-monitor ol li a', 'href'],
            ),
            'context' => $private_task_context,
        );

        $this->createTask($dynamic_task);
    }

    /**
     * @brief    onProducerStart
     *
     * @param    object $producer
     *
     * @return   mixed
     */
    public function onProducerStart($producer)
    {
        $this->makeTask();
        $this->makeDynamicTask();

        //使用Timer定時(shí)器創(chuàng)建任務(wù)
        //Timer::add(5, [$this, "makeTask"], [], true);

        //使用Crontab定時(shí)器創(chuàng)建任務(wù)
        //new Crontab('*/5 * * * * *', function(){
            //$this->makeTask();
        //});
    }

    /**
     * @brief    onProducerStop
     *
     * @param    object $producer
     *
     * @return   mixed
     */
    public function onProducerStop($producer)
    {
    }

    /**
     * @brief    onProducerReload
     *
     * @param    object $producer
     *
     * @return   mixed
     */
    public function onProducerReload($producer)
    {
    }
}

3、創(chuàng)建下載器句柄類文件:app/spider/Mydownloader.php

<?php
/**
 * @script   Mydownloader.php
 * @brief    下載器Handler
 * @author   blogdaren<blogdaren@163.com>
 * @create   2022-04-01
 */

namespace app\spider;

class Mydownloader extends \Webman\PHPCreeper\Downloader
{
    /**
     * @brief    onDownloaderStart
     *
     * @param    object $downloader
     *
     * @return   mixed
     */
    public function onDownloaderStart($downloader)
    {
        $downloader->setClientSocketAddress([
            'ws://127.0.0.1:8888',
        ]);
    }

    /**
     * @brief    onDownloaderStop
     *
     * @param    object $downloader
     *
     * @return   mixed
     */
    public function onDownloaderStop($downloader)
    {
    }

    /**
     * @brief    onDownloaderReload
     *
     * @param    object $downloader
     *
     * @return   mixed
     */
    public function onDownloaderReload($downloader)
    {
    }

    /** 
     * @brief    onDownloaderConnectToParser
     *
     * @param    object $connection
     *
     * @return   mixed
     */
    public function onDownloaderConnectToParser($connection)
    {
        //$connection->bufferFull = true;
    }

    /**
     * @brief    onDownloaderMessage
     *
     * @param    object $downloader
     * @param    string $parser_reply
     *
     * @return   mixed
     */
    public function onDownloaderMessage($downloader, $parser_reply)
    {
        //pprint($parser_reply, __METHOD__);
    }

    /**
     * @brief    onBeforeDownload
     *
     * @param    object $downloader
     * @param    array  $task
     *
     * @return   mixed
     */
    public function onBeforeDownload($downloader, $task)
    {
        //$downloader->httpClient->setConnectTimeout(3);
        //$downloader->httpClient->setTransferTimeout(10);
        //$downloader->httpClient->setHeaders(array());
        //$downloader->httpClient->setProxy('http://127.0.0.1:8800');
    }

    /**
     * @brief    onStartDownload
     *
     * @param    object $downloader
     * @param    array  $task
     *
     * @return   mixed
     */
    public function onStartDownload($downloader, $task)
    {
    }

    /**
     * @brief    onAfterDownload
     *
     * @param    object $downloader
     * @param    array  $download_data
     * @param    array  $task
     *
     * @return   mixed
     */
    public function onAfterDownload($downloader, $download_data, $task)
    {
        //pprint($downloader->getDbo('test'), __METHOD__);
    }

   /**
     * @brief    onTaskEmpty
     *
     * @param    object  $downloader
     *
     * @return   mixed
     */
    public function onTaskEmpty($downloader)
    {
        //$downloader->createTask($task);
    }

    /**
     * @brief    onHeadlessBrowserOpenPage
     *
     * @param    object  $downloader
     * @param    object  $browser
     * @param    object  $page
     * @param    string  $url
     *
     * @return   mixed
     */
    public function onHeadlessBrowserOpenPage($downloader, $browser, $page, $url)
    {
        //注意:靈活設(shè)計(jì)特定類型的返回值有助于對(duì)付各種復(fù)雜的應(yīng)用場(chǎng)景
        //1. 返回false, 會(huì)觸發(fā)中斷后續(xù)的業(yè)務(wù)邏輯;
        //2. 返回string,會(huì)觸發(fā)中斷后續(xù)的業(yè)務(wù)邏輯,一般多用于返回頁(yè)面的HTML;
        //3. 返回array, 會(huì)繼續(xù)執(zhí)行后續(xù)的業(yè)務(wù)邏輯,一般多用于返回?zé)o頭瀏覽器選項(xiàng)參數(shù);
        //4. 返回其他,  會(huì)繼續(xù)執(zhí)行后續(xù)的業(yè)務(wù)邏輯,相當(dāng)于是什么也沒(méi)有發(fā)生;

        //注意:一般無(wú)需調(diào)用如下幾行代碼,因?yàn)榕郎交?nèi)部默認(rèn)會(huì)自動(dòng)調(diào)用無(wú)頭API做同樣的工作.
        //$page->navigate($url)->waitForNavigation('firstMeaningfulPaint');
        //$html = $page->getHtml();
        //return $html;
    }
}

4、創(chuàng)建解析器句柄類文件:app/spider/Myparser.php

<?php 
/**
 * @script   Myparser.php
 * @brief    解析器Handler
 * @author   blogdaren<blogdaren@163.com>
 * @create   2022-04-01
 */

namespace app\spider;

class Myparser extends \Webman\PHPCreeper\Parser
{
    /**
     * @brief    onParserStart
     *
     * @param    object $parser
     *
     * @return   mixed
     */
    public function onParserStart($parser)
    {
    }

    /**
     * @brief    onParserStop
     *
     * @param    object $parser
     *
     * @return   mixed 
     */
    public function onParserStop($parser)
    {
    }

    /**
     * @brief    onParserReload
     *
     * @param    object $parser
     *
     * @return   mixed
     */
    public function onParserReload($parser)
    {
    }

    /**
     * @brief    onParserMessage
     *
     * @param    object $parser
     * @param    object $connection
     * @param    string $download_data
     *
     * @return   mixed
     */
    public function onParserMessage($parser, $connection, $download_data)
    {
         //pprint(strlen($download_data), __METHOD__);
    }

    /**
     * @brief    onParserFindUrl
     *
     * @param    object $parser
     * @param    string $sub_url
     *
     * @return   mixed
     */
    public function onParserFindUrl($parser, $sub_url)
    {
        //發(fā)現(xiàn)子URL后,也可以根據(jù)子URL創(chuàng)建新任務(wù)
        //$parser->createTask($sub_url);
        return $url;
    }

    /**
     * @brief    onParserExtractField
     *
     * @param    object $parser
     * @param    string $download_data
     * @param    array  $fields
     *
     * @return   mixed
     */
    public function onParserExtractField($parser, $download_data, $fields)
    {
        !empty($fields) && pprint($fields[$parser->task['rule_name']]);
    }
}

5、修改插件的process配置文件設(shè)置對(duì)應(yīng)的Handler

<?php
use app\spider\Myproducer;
use app\spider\Mydownloader;
use app\spider\Myparser;

return [
    'myproducer' => [
        'handler'     => Myproducer::class,
        'listen'      => '',
        'count'       => 1,
        'constructor' => ['config' =>
            include('spider/global.php')
        ],
    ],
    'mydownloader' => [
        'handler'     => Mydownloader::class,
        'listen'      => '',
        'count'       => 1,
        'constructor' => ['config' =>
            include('spider/global.php')
        ],
    ],
    'myparser' => [
        'handler'     => Myparser::class,
        'listen'      => 'websocket://0.0.0.0:8888',
        'count'       => 1,
        'constructor' => ['config' =>
            include('spider/global.php')
        ],
    ],
];

注意事項(xiàng)

  • 爬蟲(chóng)應(yīng)用自有的配置文件要保持相對(duì)獨(dú)立;
  • process配置內(nèi)的關(guān)于進(jìn)程構(gòu)造函數(shù)的配置一般不要?jiǎng)?
  • 目前需要手動(dòng)設(shè)置下載器的$downloader->setClientSocketAddress([]);
  • 依賴redis服務(wù),所以務(wù)必啟動(dòng)redis-server;
  • 按照規(guī)范每一個(gè)獨(dú)立的容器實(shí)例最好對(duì)應(yīng)唯一的一個(gè)Handler;

爬山虎開(kāi)發(fā)文檔

贊助商