ThinkPHP5.1+swoole+QueryList实现异步爬取数据功能

先讲下为什么要使用swoole异步任务,在项目中我们经常会遇到执行时间比较久的请求(上传,爬取等),让用户一直等待不是好的体验,所以我们使用swoole异步请求,先返回‘执行中’,等异步任务执行完毕再修改状态。
接下来我们来实现swoole在thinkphp 里的集成:
1.安装swoole
推荐使用官网提供的安装方式 安装swoole扩展
2.安装QueryList

composer require jaeger/querylist

文档地址 querylist

3.在Tp5里自定义一个命令行类
在application下建立一个console文件夹用来存放自定义命令文件,然后在该文件夹下新建Crawler.php文件,编辑application目录下的command.php文件
添加如下代码

return [
    'app\console\Crawler',
];
深度截图_选择区域_20190920133914.png

编写 Crawler.php

<?php

namespace app\Console;

use QL\QueryList;
use think\console\Command;
use think\console\Input;
use think\console\Output;


class Ceshi extends Command{
    protected $server;
    protected function configure()
    {
        //参考tp5自定义命令行手册
        $this->setName('crawler:start')->setDescription('Start Crawler Server!');
    }

    protected function execute(Input $input, Output $output)
    {
        $serv = new \swoole_server('0.0.0.0',9502);//9502为swoole监听端口,可以自行设置
        $serv->set(array('task_worker_num' => 4));//异步进程数量 根据实际情况进行配置,参照官网提供的方案
        $serv->on('connect', function ($serv, $fd){

        });
        $serv->on('receive', function($serv, $fd, $from_id,$data) {
            //投递异步任务 $data为接口传递的参数,接收参数做一些处理之后交给task
            echo'收到任务';
            $serv->task($data);
        });
        $serv->on('task', function ($serv, $task_id, $from_id, $data) {
            //接收receive传递的任务,进行执行
            //本例中实现的是爬取京东商品任务 ,大家可以根据自身情况修改
            echo'执行任务';
            $this->crawler($data);
        });
        $serv->on('finish', function ($serv, $task_id, $data) {

        });
        $serv->start();
    }

    /**
     * 采集商品数据
     * @param $activity_id
     * @return bool
     */
    private function crawler($activity_id)
    {
        //假设 $number 为京东活动id
        $number = 123456;
        $data = [];
        $limit = 1;//起始
        $ql = QueryList::getInstance();
        for (; ;) {
            $offset = $limit * 30 + 1;//偏移量
            //这个url是通过分析京东加载商品接口提取出来的,修改这几个参数就能模拟分页爬取到京东全部活动的商品
            $url = 'https://search.jd.com/s_new.php?activity_id=' . $number . '&vt=2&scc=1&page=' . $limit . '&s=' . $offset . '&scrolling=y&tpl=1_M';
            //这里使用了代理,因为循环爬取的原因被京东检测到了封了ip,所以使用动态代理爬取,代理的使用根据代理服务商提供的api每个都不同,在本文不详细介绍
            $crawler = $this->immediate($url);
            if ($crawler) {
                $query = [];
                //phpquery 的核心思想就是使用php像js一样通过dom操作页面
                //下面代码的意思是 获取页面的html 找到class为gl-item的子元素,并遍历(就是遍历京东页面展示的商品div)
                $ql->html($crawler)->find('.gl-item')->children()->map(function ($item) use (&$query, $number, $activity_id) {
                    $tags = '';
                    //找到标签展示规律并提取
                    $item->find('.p-icons')->children()->map(function ($child_tag) use (&$tags) {
                        $tags .= $child_tag->html() . ',';
                    });
                    //找到商品价格展示规律并提取
                    $price = $item->find('.p-price>strong>i')->html();
                    if (!$price) {
                        $price = $item->find('.p-price>strong')->attrs('data-price')[0] ?? 0;
                    }
                    if ($price && $price > 0) {
                        //这里通过节点找到需要的数据和数据表对应存到mysql
                        $query[] = [
                            'activity_id' => $activity_id,
                            'activity_number' => $number,
                            'goods_number' => $item->find('.p-operate>a')->attrs('data-sku')[0] ?? '',
                            'title' => $item->find('.p-name-type-2>a>em')->text(),
                            'image' => 'http:' . $item->find('.p-img>a>img')->attrs('source-data-lazy-img')[0] ?? '',
                            'price' => $price,
                            'tags' => rtrim($tags, ','),
                            'shop_name' => $item->find('.p-shop>span>a')->html(),
                            'shop_number' => $item->find('.p-img>div')->attrs('data-venid')[0] ?? '',
                        ];

                    }
                });
                if (count($query)) {
                    foreach ($query as $k => $v) {
                        $data[] = $v;
                    }
                    $limit++;
                } else {
                    break;
                }
            }
            //尽量让爬虫等待一秒再执行,避免内存溢出
            sleep(1);
        };
        //爬虫功能结束之后及时释放内存
        $ql->destruct();
        //.......
        //接下来把数据存进mysql中就大功告成啦
    }

}

4.写一个接口去调用异步任务

public function swoole_task(Request $request){
        $type = $request->param('type');
        $client = new \swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
        $ret = $client->connect("服务器ip", 9502);
        if(empty($ret)){
            return 'FAIL';
        } else {
            $client->send($type);//提交任务到crawler.php 处理 我是传参$type实现不同的异步任务调用
            return 'SUCCESS';
        }
    }

5.进入tp5 项目根目录执行命令

php think crawler:start//通常用于调试

让swoole监听命令以守护进程方式运行(服务器)

php think crawler:start &

6.执行上面写好的调用接口swoole_task 可以在你想用的任何地方调用
7.效果


深度截图_选择区域_20190920142220.png

本文提供的方法仅供参考,实例并不能直接执行,需要大家理解工作原理后结合自身项目进行使用

8.推荐一下本文使用技术在项目中的应用,微信搜索‘东东小卖部’,每天会爬取最新的京东满减打折活动,
通过算法凑成满减之后将商品组合返回给用户,亲身体验过非常不错,这个项目对于喜欢网购的朋友们来说绝对会带给你非常棒的体验。
大家要是觉得本文有帮助的话,帮忙关注下公众号分享给身边的人,不许白嫖哦,十分感谢


微信图片_20190920104620.jpg

微信图片_20190920104614.jpg

d19aaddda144ad34e5809b91dfa20cf431ad8526.jpg

e37546d98d1001e9f3030819b70e7bec54e79726.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容