php Swoole多线程爬虫 九

153 阅读1分钟

「这是我参与2022首次更文挑战的第23天,活动详情查看:2022首次更文挑战

课程背景

  • 我作为一个PHP工程师 虽然这几年PHP没落了
  • 但我还是有责任补充一些PHP方面的高级教程
  • 掘金粑粑开始更文奖励了 不能白白拿人家的奖励
  • 应该发表一些高层次的PHP的技术文章 别让PHP倒了

正文开始

上面的章节中我们跟着分析思路一步一步的完成了我们的多线程的爬取程序。这一节中我们继续。

整个章节最终的完整代码如下所示。vender中需要 Guzzle组件。

/**
 * [多线程图片爬取脚本] 
 * Author Liiy. 
 * Date 2022/02/01. 
 * Time 17:21. 
 */

require 'vendor/autoload.php';
$total = new swoole_atomic(0); //计数器

$worker_num = 20; //线程数
$num = 2822; //总页数
$base_url = "https://toutiao.sanhao.com/news-list.php?u=p%s";

//开启Redis
$to_key = 'sanhao_list';
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('admin123');

//生成目标连接
$redis->del($to_key);
for ($i=1; $i <= $num; $i++) { 
    $redis->lpush($to_key,sprintf($base_url,$i));
}

for ($i=0; $i < $worker_num; $i++) { 
    $process = new swoole_process(function($pro) use ($to_key, $redis,$num,$worker_num, $total){
        $per_count = ceil($num/$worker_num);
        for ($j=0; $j < $per_count; $j++) { 
            try {
                $url = $redis->rpop($to_key);
                echo sprintf("目标url:%s",$url).PHP_EOL;
                if($url){
                    $client = new \GuzzleHttp\Client([ 'verify' => false]);
                    $response = $client->request('get', $url);
                    $body = (string)$response->getBody();
                    $dom = new DOMDocument();
                    @$dom->loadHTML($body);
                    $xpath = new DOMXPath($dom);
    
                    //提取图片
                    $data = $xpath->query("//div[@class='news-list-box']/div[@class='news-list-box-right']/a/img/@src");
                    for($k = 0; $k < $data->length; $k++){
                        $items = $data->item($k);
                        $pic_url = $items->nodeValue;
                        $url_path = 'http:'.$pic_url;
                        $file_name_arr = explode('/',$url_path);
                        $file_name =$file_name_arr[array_key_last($file_name_arr)];
                        $file_name = mt_rand(1000, 9999).'_'.$file_name;
                        $res_pic = $client->request('get', $url_path, ['sink' => './img/' . $file_name]);
        
                        echo sprintf("图片%s存储结果:%s",$file_name,$res_pic->getStatusCode()).PHP_EOL;
                    }
                }
            } catch (\Throwable $th) {
                echo "遇到异常 继续执行".PHP_EOL;
            }
            $total->add(1); 
        }

        $pro->exit();
    },false);
    $process->start();
}

for ($i=0; $i < $worker_num; $i++) { 
    swoole_process::wait();
}

下面是爬取过程中的运行截图,跟cpu消耗。我是在虚拟机中用了1核1G内存,所以cpu会跑满。 image.png

image.png

最后是最终结果,爬取到了 34000多张图片。 image.png

总结

虽然不是很难的技术,但是也是需要去不断的学习的。这些技术平时做学习可以,千万不要去搞一些非法的事情。