当前位置: 首页 > 工具软件 > PHP-spider > 使用案例 >

phpspider 简单用法和学习,分类一对多爬取数据

凌恩
2023-12-01

最近上面让爬一些数据,以为可以尝试学习使用python,奈何最终让我用PHP实现,减少开发时间…然后在网上找,果然已经有大佬分享----phpspider,还有一些php爬虫框架,但是考虑到是国人开发,代码可读性高(全中文注释,注释清晰,详细),并且在github上有近3K的star,最终决定使用phpspider。

作者很有意思,代码注释风趣,并且各种情况都做了兼容,只需要轻轻配置一下,不需要我们做太多的操作,甚至还给出了好几个demo供我们研究。

下载地址:下载地址
文档地址:文档地址

简单学习xpath后,过了一遍文档,开始尝试。我需要爬的是一个商标分类,群组,商品的网站,从源码和js里分析后各页面后,添加配置:

$config = [
    'name'=>'商标类',
    'tasknum'=>1,//进程数
    'log_show'=>true,//是否显示日志
    'domains'=>[//定义爬取域
        'test.com',
        'www.test.com',
    ],
    'scan_urls'=>[//入口页面
        'http://www.test.com/ncl/01.html'
    ],
    'content_url_regexes'=>[//内容
        'http://www.test.com/category/search.html\?intCls=\d+'
    ],
    'max_try'=>5,//最大尝试次数
    'db_config'=>[
        'host'=>'127.0.0.1',
        'user'=>'root',
        'pass'=>'123',
        'port'=>3306,
        'name'=>'dataname',
    ],
];

经过分析,我爬取的页面的列表没有实际意义,因此没有写list_url_regexes配置,有列表可以增加此配置,可大幅提升爬虫效率!
商标分类有45,每个类下又有n个群组,每个群组下有多个商品,分析页面后得知,45类有有45个url,因此需要把这些url添加到带爬队列中:

$spider = new phpspider($config);
$spider->on_start = function($phpspider){
    $db_config = $phpspider->get_config("db_config");
    db::set_connect('default',$db_config);
    db::init_mysql();
    for($i=1;$i<46;$i++){
        if($i<10){
            $i = '0'.$i;
        }
        $phpspider->add_url('http://www.test.com/category/search.html?intCls='.$i);
    }
};

顺便把数据库也初始化,方便后面操作。
再来写群组和商品的爬去,经分析,发现每个页面的群组都是相同的div和class,并且商品也在这个div里,保存在商品中,添加配置fileds

'fields'=>[
        [
            'name'=>'parent',
            'selector'=>"//div[@class='result-data']",
        ]
    ]

这样就能拿到所有同一分类下(同一页面),不同群组的div和包含的商品的html,查看文档,文档上介绍说,fields中可以使用children,是一个树形结构(并且可以一直加下去,有兴趣可查看源码,代码中是递归操作),结合文档示例,修改fields配置:

'fields'=>[
        [
            'name'=>'parent',
            'selector'=>"//div[@class='result-data']",
            'children'=>[
                [
                    'name'=>'group',
                    'selector'=>'//div[@class="result-data-top"]',
                ],
                [
                    'name'=>'item',
                    'selector'=>'//input[@type="checkbox"]/@value',
                ]
            ]
        ]
    ]

尝试运行后,发现只有每个类型(页面)都只拿到1个群组(group),和1个商品(item)!并且不加children时得到的html都是包含所有需要数据的!
怀疑是xpath不熟悉,写错了,根据文档的运行前测试后得知,xpath没有问题!
然后开始查看源码,最终发现这个判断

if (is_array($values)) 
                {
                    if ($repeated) 
                    {
                        $fields[$conf['name']] = $values;
                    }
                    else
                    {
                        $fields[$conf['name']] = $values[0];
                    }
                }
                else 
                {
                    $fields[$conf['name']] = $values;
                }

好吧,原来在fields里还可以添加配置,repeated,否则就只会返回数组中的第一个,默认是false,修改为true,文档中也有描述,怪自己忽略忘记了这个配置…再次修改配置

'fields'=>[
        [
            'name'=>'parent',
            'selector'=>"//div[@class='result-data']",
            'repeated' => true,
            'children'=>[
                [
                    'name'=>'group',
                    'selector'=>'//div[@class="result-data-top"]',
                    'repeated' => true,
                ],
                [
                    'name'=>'item',
                    'selector'=>'//input[@type="checkbox"]/@value',
                    'repeated' => true,
                ]
            ]
        ]
    ]

运行尝试,OK
现在开始处理数据,因为在我的数据库中,群组和商品是分开的,现在爬出来的数据,显然不适合参照demo中自动保存,因此需要自己修改处理!
查找文档,果然大佬已经准备好了,on_extract_page这个回调函数可以在抽取完后进一步处理字段:

$spider->on_extract_field = function($filename,$data){
    if($filename == 'parent'){
       /*中间就是处理代码,$data就是抽取出来的数据,数组格式*/
    }
    return $data;
};

完成!
全程不过100行左右代码,配置就将近一半了,不需要管底层逻辑,发送请求等等,算是懒人福音,以后有机会学习一下底层实现,此框架推荐!

 类似资料: