使用easyswoole开发多进程多协程队列式爬虫

举报
仙士可 发表于 2023/06/21 16:52:02 2023/06/21
【摘要】 爬虫步骤我们先说一下一个完整的爬虫步骤。爬虫步骤分为2个阶段:1:根据初始页面,获取更多的待爬取页面2:根据页面,获取到自己想要的东西更多待爬取页面获取当我们填入一个初始页面时,我们需要通过某一个特定的逻辑,进行获取更多的页面例如:爬取百度页面,我们可以通过页码按钮,获取更多页面的html源码:爬取知乎用户,我们可以通过该用户的关注者,和粉丝爬取更多用户界面:结果获取获取到了页面html代码...

爬虫步骤

我们先说一下一个完整的爬虫步骤。

爬虫步骤分为2个阶段:

1:根据初始页面,获取更多的待爬取页面

2:根据页面,获取到自己想要的东西

更多待爬取页面获取

当我们填入一个初始页面时,我们需要通过某一个特定的逻辑,进行获取更多的页面

例如:

爬取百度页面,我们可以通过页码按钮,获取更多页面的html源码:

爬取知乎用户,我们可以通过该用户的关注者,和粉丝爬取更多用户界面:

结果获取

获取到了页面html代码之后,我们就可以根据相应的规则,获取到自己想要的东西了。

这里我推荐http://www.querylist.cc/  可使用jq的语法选择html页面的元素,非常好用

使用消息队列

我们现在已经知道了整个爬虫的步骤了,下一步是如何运行这个代码。

在上一步我们可以看出,一个页面,可能有多个待爬取页面,如果我们每次都是取一个页面,然后分析结果,然后再取一个页面,分析结果

这样会造成代码逻辑的难以掌控。

例如:

1:分析页面1,假设页面1有5个待爬取页面链接

2:分析页面1结果,存储

3:分析页面1的第一个结果待爬取页面2,页面2有5个待爬取页面链接

4:分析页面2的结果,存储

5:分析页面1的第二个待爬取页面3,页面3有5个待爬取页面链接。。。。。。

。。。。

这样会造成代码的难以控制,不好维护待爬取页面,我们可以使用队列的形式进行处理

1:初始页面存入分析队列

2:分析初始页面1,获取5个待爬取页面链接,存入分析队列

3:分析页面1的结果,存入结果队列

4:分析队列出列页面2,获取5个待爬取页面链接,存入分析队列

5:分析页面2的结果,存入结果队列

使用队列的情况下,逻辑将会非常的清晰,只需要每次将分析的页面出入队列,然后取出继续分析即可

同样,结果队列只需要新增一个结果消费进程,进行处理结果数据即可

实战

本人已经写好了基础的爬虫框架,基于easyswoole,使用redis队列进行消费。

github地址:https://github.com/tioncico/ESSpider

首先进行composer安装

composer up
复制

复制produce.php命名为dev.php,增加redis配置:

<?php
/**
 * Created by PhpStorm.
 * User: yf
 * Date: 2019-01-01
 * Time: 20:06
 */

return [
    'SERVER_NAME' => "EasySwoole",
    'MAIN_SERVER' => [
        'LISTEN_ADDRESS' => '0.0.0.0',
        'PORT'           => 9501,
        'SERVER_TYPE'    => EASYSWOOLE_WEB_SERVER, //可选为 EASYSWOOLE_SERVER  EASYSWOOLE_WEB_SERVER EASYSWOOLE_WEB_SOCKET_SERVER,EASYSWOOLE_REDIS_SERVER
        'SOCK_TYPE'      => SWOOLE_TCP,
        'RUN_MODEL'      => SWOOLE_PROCESS,
        'SETTING'        => [
            'worker_num'            => 8,
            'task_worker_num'       => 8,
            'reload_async'          => true,
            'task_enable_coroutine' => true,
            'max_wait_time'         => 3
        ],
    ],
    'TEMP_DIR'    => null,
    'LOG_DIR'     => null,
    /*################ REDIS CONFIG ##################*/
    'REDIS'       => [
        'host' => '127.0.0.1',
        'port' => '6379',
        'auth' => '',
        'serialize'=>true
    ],
];
复制

本身自带了某网站的爬取逻辑,直接运行即可看到:

php easyswoole start
复制

现在我们说下如何爬取其他网站的步骤

爬取http://moe.005.tv/moeimg/动漫图片网站

清空/App/Spider/Event.php的方法逻辑

<?php

namespace App\Spider;

use EasySwoole\Utility\File;
use QL\QueryList;

/**
 * Created by PhpStorm.
 * User: tioncico
 * Date: 19-6-16
 * Time: 上午9:53
 */
class Event
{

    static function consume($data, $html)
    {
    }

    static function produce($data, $html)
    {
    }
}
复制

编写生产代码(获取更多待爬取页面逻辑):

首先,我们要确定,我们的初始页面是http://moe.005.tv/moeimg/,然后我们可以根据下一页按钮获取更多的页面

static function produce($data, $html)
{
    //获得一个queryList对象,并且防止报错
    libxml_use_internal_errors(true);
    @$ql = QueryList::html($html);

    //查询下一页链接,用于继续爬取数据
    $nextLink = $ql->find('.pagelist .n')->attr('href');
    RedisLogic::addProduce($nextLink);

    //查询所有需要爬取的数据,用于爬取里面的图片
    $imgConsumeList = $ql->find('.zhuti_w_list li a')->attrs('href')->all();
    foreach ($imgConsumeList as $value) {
        RedisLogic::addConsume([
            'type' => 1,//消费标识
            'url'  => $value,
        ]);
    }
    return true;
}
复制

编写消费代码

现在我们需要点击一个图片进入,可以发现很多图片,例如:http://moe.005.tv/78243.html

现在,我们编写消费代码:

 static function consume($data, $html)
    {
        //获得一个queryList对象,并且防止报错
        libxml_use_internal_errors(true);
        if ($data['type'] == 1) {
            //消费类型为1,则代表还不是下载图片,需要进行二次消费
            //查询下一页链接,用于继续爬取数据
            @$ql = QueryList::html($html);
            $nextLink = $ql->find('.pagelist .n')->attr('href');
            $nextLink = HttpClientLogic::getTrueUrl($data['url'],$nextLink);
            if ($nextLink) {
                RedisLogic::addConsume([
                    'type' => 1,//消费标识
                    'url'  => $nextLink,
                ]);
            }
            $imgList = $ql->find('.content_nr img')->attrs('src')->all();
//            var_dump($img);
            foreach ($imgList as $img) {
                RedisLogic::addConsume([
                    'type' => 2,//消费标识
                    'url'  => $img,
                ]);
            }
        } elseif ($data['type'] == 2) {
            $urlInfo = parse_url($data['url']);
            $filePath = EASYSWOOLE_ROOT . '/Temp/' . $urlInfo['host'] . $urlInfo['path'];
//            var_dump($filePath);
            File::createFile($filePath, $html);
//            var_dump($data['url']);
        }

    }
复制

初始页面链接可通过协程调用进行增加:

<?php
/**
 * Created by PhpStorm.
 * User: tioncico
 * Date: 19-6-16
 * Time: 下午5:35
 */
include "./vendor/autoload.php";
\EasySwoole\EasySwoole\Core::getInstance()->initialize();
go(function (){
    \App\Spider\RedisLogic::clearConsumeMap();//清除消费map
    \App\Spider\RedisLogic::clearProduceMap();//清除生产map
    \App\Spider\RedisLogic::clearConsumeList();//清除消费队列
    \App\Spider\RedisLogic::clearProduceList();//清除生产队列
    //新增默认队列
    \App\Spider\RedisLogic::addProduce('http://moe.005.tv/moeimg/');
});
复制

直接运行

php easyswoole start
复制

即可实现爬虫爬取页面

爬虫框架补充

github地址:https://github.com/tioncico/ESSpider

1:可通过EasySwooleEvent.php  文件,进行配置爬取的协程数,不建议太大

2:本爬虫没有做ip池,需要的可自行实现

3:本爬虫框架只适用于学习,请不要用于违法用途

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。