xixizizixixi/fatgoose

1.0.9 2020-11-05 09:30 UTC

This package is auto-updated.

Last update: 2024-04-11 21:45:17 UTC


README

  • 多进程可能出现的问题:因为多进程时各个进程之间的布隆过滤器无法保持一致,所以历史记录表和抓取任务表可能会出现重复内容。一般情况下也没必要使用多进程。

  • 多个线程使用同一个tor链路:已实测如果有多个线程正在使用同一个tor链路(比如下载),此时用kill -1 tor进程id切换tor链路,不会对这些线程产生影响,新的线程会使用新的tor链路

  • 长时间抓取需要考虑的问题:一般默认8小时后数据库连接将会断开,如果任务跑的时间特别长,修改mysql数据库配置的interactive_timeout和wait_timeout

  • 目前下文中所指"自定义信息数组"包含:① 'task'键保存任务数组 ② 'opt'键保存抓取选项数组 ③ 'tor'键保存一个数组['port'=>端口号,'pid'=>进程id]

  • 通过addTask()方法或者手动向抓取任务表中添加任务时需注意:因为先添加的任务先处理,所以添加任务的顺序会影响采集到的数据在数据库中的排列顺序。通常老的任务应该先添加,最新任务后添加。

  • 即使返回响应状态码200,调用了抓取成功回调函数,也并不一定是"真正的抓取成功"了,因为返回的内容很可能是预期外的其他内容,所以务必进行特征检测,保证是需求的内容

快速开始 —— 抓取

//创建FatGoose对象
$fg=new FatGoose(); 

//设置抓取回调函数数组
$fg->setCallbacksArr();

//注册一个回调函数,自动传入自定义信息数组的引用,此回调函数在创建每个curl资源的时候都会调用
//这个回调函数可以(1)用返回值设置额外的或覆盖已存在的curl选项(2)往自定义信息数组里面注入额外信息
/*此回调函数大致结构如下,特别要注意参数是引用传递

    function(&$customInfoArr) 
    {
        ...
        $customInfoArr['sum']=10000;     注入了额外信息
        ...
        return [CURLOPT_PROXYTYPE=>CURLPROXY_HTTP,CURLOPT_PROXY=>'127.0.0.1:1080'];   设置额外的curl选项
    }

*/
$fg->registerFuncExtraCurlOpt();

//添加初始抓取任务,要注意添加任务的顺序,先添加,先抓取。
//初始抓取任务只需添加一次,随后可注释掉
$fg->addTask();

//开始抓取
$fg->run();

快速开始 —— 监视

//创建FatGoose对象
$fg=new FatGoose(); 

//设置监视回调函数数组
$fg->setMonitorCallbacksArr();

//开始监视
$fg->monitor();

抓取回调函数自动传入的参数情况

  • 静态方法mCrawl()用的回调函数没有中括号[ ]里面的部分,也没有返回值。此方法主要用于一些简单的抓取和进行抓取测试。

  • curl信息数组里面有什么可以看这个页面的"Return Values"部分 https://www.php.net/manual/en/function.curl-getinfo.php

  • onSuccess

    • p1:curl信息数组
    • p2:抓取到的内容
    • [ p3:自定义信息数组 ]
    • [ p4:pdo对象 ]

    这个回调函数主要有三个作用:

    ①对抓取到的内容进行分析,提取出自己想要的数据保存到数据库中

    ②返回一个数组,里面的url会成为下一级别的抓取任务。形式:

    • [ [ url , url , ...... ],false ] 这种形式默认extraInfo为null
    • [ [ [ url,extraInfo ] , [ url,extraInfo ] , ...... ] , false ]
    • 上面的extraInfo是个关联数组
    • 上面false改为true可临时无视布隆过滤器

    ③返回"reset"重置任务,任务状态重新设置为0;返回"ignore"则先跳过任务,任务状态会保持在1,以后再处理

  • onSuccessWithUnexpectedCode

    • p1:curl信息数组
    • [ p2:自定义信息数组 ]
    • [ p3:pdo对象 ]

    返回"reset"重置任务,任务状态重新设置为0

  • onFail

    • p1:目标url
    • p2:错误消息
    • p3:错误码
    • [ p4:自定义信息数组 ]
    • [ p5:pdo对象 ]

监视回调函数自动传入的参数情况

监视器对监视任务表中的任务进行监视(周期抓取),抓取成功后调用回调函数,回调函数中对页面是否更新进行判断。

  • onMonitorSuccess
    • p1:curl信息数组
    • p2:抓取到的内容
    • p3:自定义信息数组
    • p4:pdo对象
    • p5:布隆过滤器对象

返回数组(形式同onSuccess的返回值)则向抓取任务表中追加新的任务(任务级别加1),返回true则更新抓取任务表中与当前监视任务对应的任务为未抓取(0)状态以便再次抓取。

数据去重(布隆过滤器)

针对每个抓取的目标网站建立一个历史url集合,对即将添加到抓取任务表的url判断是否在这个集合中,没在才添加,并将这个新的url加入到集合中。

技术上采用布隆过滤器(bloomfilter):时间和空间效率极高,有误判“结果在集合中,但实际不在集合中”,“结果不在集合中,实际也一定不在集合中”。所以使用bloomfilter最大的损失也就是有一些页面漏抓而已,这是完全可以承受的。

项目地址: https://github.com/pleonasm/bloom-filter 使用时直接参考即可

如果每次创建布隆过滤器对象都通过历史url表,当数据量特别大的时候整个过程会非常慢,而且很占内存。此时可考虑使用布隆过滤器缓存文件,如果缓存文件存在,则用缓存文件创建对象,否则还是通过历史url表创建对象。

注意:①缓存文件只适用于单进程,否则多个进程之间会相互覆盖②如果程序异常终止或强制终止,缓存文件会和历史url表不一致,此时应该手动删除缓存文件以便生成新的缓存文件

配置数组的配置项说明

$config=[

        //创建布隆过滤器时使用的预估条目数(确保添加到布隆过滤器中的条目数小于这个值)
        'item_num'=>1000000,
        //创建布隆过滤器时使用的误判几率
        'probability'=>0.0001,
        //无视布隆过滤器,开启时添加任务到任务表不会受到布隆过滤器的阻止
        'ignore_bf'=>false,
        //是否使用布隆过滤器缓存文件
        'use_bf_cache_file'=>false,
        //布隆过滤器缓存文件的路径
        'bf_cache_file_path'=>'/home/data_bf',

        //是否启用tor代理,必须保证当前环境已经创建了若干tor代理进程
        'use_tor'=>false,

        //tor代理进程的端口号和pid的映射数组 key是端口号 value是进程id
        //形如 [20001=>1234,20002=>1235,20003=>1236,......]
        'tor_ports_pids'=>[],


        //爬取失败重试次数
        'retry'=>1,

        //线程数
        'thread_num'=>15,

        //是否开启守护模式,周期性从抓取任务表中取任务进行抓取
        'daemon'=>false,
        //开启守护模式后间隔多少秒尝试进行一次爬取
        'daemon_interval'=>86400,

        //监视器时间间隔
        'monitor_interval'=>43200,

        //是否随机用户代理字符串
        'random_user_agent'=>false,
        //预定义的一系列用户代理字符串
        'user_agent'=>
            [ ],
        //curl默认选项
        'curl_opt'=>
            [
                CURLOPT_RETURNTRANSFER => true,  //抓取结果作为字符串返回,不输出到页面
                CURLOPT_CONNECTTIMEOUT => 60,  //连接60秒超时
                CURLOPT_TIMEOUT => 120, //函数执行120秒超时
                CURLOPT_FOLLOWLOCATION => true,  //跟踪重定向

                //设置Accept-Encoding请求头。同时能对压缩的响应内容解码
                CURLOPT_ENCODING => 'gzip, deflate',
                //设置用户代理字符串
                //百度蜘蛛 Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)
                //谷歌机器人 Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
                CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
                CURLOPT_HEADEROPT => CURLHEADER_UNIFIED, //向目标服务器和代理服务器的请求都使用CURLOPT_HTTPHEADER定义的请求头
                //构建更加真实的请求头
                CURLOPT_HTTPHEADER=> [
                    'Connection: close',
                    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
                    'Upgrade-Insecure-Requests: 1',
                    'Accept-Language: en-US,en;q=0.9,de;q=0.8,ja;q=0.7,ru;q=0.6,zh-CN;q=0.5,zh;q=0.4',
                    'Cache-Control: no-cache',
                ],

                /*设置代理*/
                //CURLOPT_PROXYTYPE=>CURLPROXY_HTTP,//设置代理类型CURLPROXY_HTTP或CURLPROXY_SOCKS5
                //CURLOPT_PROXY=>'127.0.0.1:1080',//设置代理的ip地址和端口号

                /*抓取https页面必要*/
                //CURLOPT_SSL_VERIFYPEER=>true,
                //CURLOPT_CAINFO=>'/home/cacert.pem',
                //CURLOPT_SSL_VERIFYHOST=>2,
            ],
        //默认数据库配置
        'database'=>
            [
                //服务器地址
                'host'=>'',
                //用户名
                'username'=>'',
                //密码
                'password'=>'',
                //端口
                'port'=>3306,

            ]

    ]

API说明

  • __construct()

    创建FatGoose对象,参数依次为数据库名、任务表名、历史表名、监视表名、配置选项数组

  • setCallbacksArr()

    设置抓取回调函数数组。此数组的格式为

    /*
       [
        ['0级抓取成功的回调函数','0级抓取成功但状态码有问题的回调函数','0级抓取失败的回调函数'],//0级任务回调函数
        ['1级抓取成功的回调函数','1级抓取成功但状态码有问题的回调函数','1级抓取失败的回调函数'],//1级任务回调函数
        ......
        ...... 以此类推可以无限级
       ]
    */
  • setMonitorCallbacksArr()

    设置监视回调函数数组。此数组的格式为

    /*
       [0级监视任务成功的回调函数,1级监视任务成功的回调函数,2级监视任务成功的回调函数......]  
    */
  • addTask()

    用于添加抓取任务,第一个参数是任务数组,第二个参数是否忽略布隆过滤器(默认false)。任务数组的格式为

    /*
       [ [[url,extraInfo],level],[[url,extraInfo],level],...... ] 
    
       [ [url,level],[url,level],...... ]  样的形式则默认extraInfo为null
    */
  • registerFuncExtraCurlOpt()

    注册一个回调函数,自动传入自定义信息数组的引用,此回调函数在创建每个curl资源的时候都会调用

    这个回调函数可以(1)用返回值设置额外的或覆盖已存在的curl选项(2)往自定义信息数组里面注入额外信息

    此回调函数大致结构如下,特别要注意参数是引用传递

    /*
       function(&$customInfoArr) 
       {
           ...
           $customInfoArr['sum']=10000;     注入了额外信息
           ...
           return [CURLOPT_PROXYTYPE=>CURLPROXY_HTTP,CURLOPT_PROXY=>'127.0.0.1:1080'];   设置额外的curl选项
       }
    */
  • run()

    开始爬取

  • monitor()

    开始监视

  • 静态方法 mCrawl()

    多线程异步爬虫,此方法功能有所简化,主要用于简单的抓取和抓取测试。传入的参数依次为,待抓取的页面(字符串或数组)、抓取成功的回调函数、响应状态码预期外的回调函数、抓取失败的回调函数、线程数、重试次数、抓取选项数组

  • 静态方法 absoluteUrl()

    相对url转绝对url。传入的参数依次为,待转换的url(字符串或数组)、参照url,如果是目录后面带上/

  • 静态方法 customArrayMerge()

    将第二个数组的数组项合并到第一个数组中,有则覆盖,无则追加,并且实现递归。