zoukankan      html  css  js  c++  java
  • 多线程方式采集搜狗高清壁纸的实现

    上一篇,完成了Windows下PHP多线程扩展pthreads的安装,下面就利用多线程进行图片的采集

    一、实现前准备工作

    1、打开搜狗图片网站

    打开控制台,分析异步请求数据规律

    2、搜狗图片存储数据表结构创建

    打开搜狗异步请求链接,查看响应结果中的json数据


    根据上图中图片详情创建搜狗图片数据表结构sql语句如下:

    CREATE TABLE `sougou_pic` (
      `sougou_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '表主键id',
      `id` int(11) DEFAULT NULL COMMENT '搜过网站图片id',
      `did` int(10) DEFAULT NULL,
      `thumbUrl` varchar(255) DEFAULT NULL,
      `thumb_width` int(10) DEFAULT NULL,
      `thumb_height` int(10) DEFAULT NULL,
      `sthumbUrl` varchar(255) DEFAULT NULL,
      `sthumb_width` int(10) DEFAULT NULL,
      `sthumb_height` int(10) DEFAULT NULL,
      `bthumbUrl` varchar(255) DEFAULT NULL,
      `bthumb_width` int(10) DEFAULT NULL,
      `bthumb_height` int(10) DEFAULT NULL,
      `pic_url` varchar(255) DEFAULT NULL,
      `width` int(10) DEFAULT NULL,
      `height` int(10) DEFAULT NULL,
      `size` int(10) DEFAULT NULL,
      `ori_pic_url` varchar(255) DEFAULT NULL,
      `ext_url` varchar(255) DEFAULT NULL,
      `page_title` varchar(64) DEFAULT NULL,
      `page_url` varchar(255) DEFAULT NULL,
      `title` varchar(64) DEFAULT NULL,
      `tags` varchar(64) DEFAULT NULL,
      `group_mark` varchar(8) DEFAULT NULL,
      `group_index` int(10) DEFAULT NULL,
      `publish_time` int(10) DEFAULT NULL,
      `surr1` varchar(16) DEFAULT NULL,
      `surr2` varchar(16) DEFAULT NULL,
      `category` varchar(16) DEFAULT NULL,
      `weight` int(10) DEFAULT NULL,
      `deleted` int(10) DEFAULT NULL,
      `waplink` varchar(255) DEFAULT NULL,
      `weblink` varchar(255) DEFAULT NULL,
      `intime` int(10) DEFAULT NULL COMMENT '添加时间',
      `pfrom` varchar(255) DEFAULT '',
      PRIMARY KEY (`sougou_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=11088 DEFAULT CHARSET=utf8;
    

    3、录入搜狗图片到数据库

    采集代码这里省略,需要注意的是,采集过程中防止超时的存在(主要可能还是搜狗有做简单反爬虫处理),超时采集不到就延时5秒继续采集。

    下面是录入完成后数据表一览

    二、多线程方式下载数据库中已录入的搜狗图片

    1、采用Yii2框架实现

    • Yii2框架控制台(console)下创建命令行可执行脚本文件SougouController.php,代码如下:
    
    <?php
    
    namespace consolecontrollers;
    
    use yii;
    use yiiconsoleController;
    use commonmodelsSougouPic as M;
    use commoncomponentSougouPthreads;
    use yiiconsoleException;
    
    class SougouController extends Controller
    {
        /**
         * 下载搜狗图片
         */
        public function actionDownload()
        {
            try{
                $stime=microtime(true);
    
                $arrsSougouPic = M::myTables();//3500,6030,9636
                echo '图片总数量共: '.count($arrsSougouPic).PHP_EOL;
    
                //线程池
                $pool = array();
    
                foreach ($arrsSougouPic as $member){
                    $sougou_id = $member['sougou_id'];
                    while (true){
                        if(count($pool) < 5){
                            //要下载的原图
                            $ori_pic_url = $member['ori_pic_url'];
                            $pool[$sougou_id] = new SougouPthreads($member['sougou_id'], $member['size'], $member['title'], $ori_pic_url, $member['width'], $member['height']);
                            $pool[$sougou_id]->start();
                            break;
                        }else{
                            foreach ( $pool as $name => $worker){
                                if(! $worker->isRunning()){
                                    unset($pool[$name]);
                                }
                            }
                        }
                    }
                }
    
                $arrsSougouPic = null;
    
                echo "Download completed!".PHP_EOL;
    
                $etime=microtime(true);//获取程序执行结束的时间
                $total=$etime-$stime;   //计算差值
                echo '共运行时间:'.$total.'秒'.PHP_EOL;
            } catch (Exception $e) {
                echo '【' , date('H:i:s') , '】', '【系统错误】', $e->getMessage(), "".PHP_EOL;
            }
        }
        
    }
    
    
    • 搜狗多线程类继承线程类,SougouPthreads.php代码如下
    
    <?php
    namespace commoncomponent;
    
    use Yii;
    use Thread;
    
    class SougouPthreads extends Thread
    {
        public $running = false;
        public $sougou_id = '';
        public $title = '';
        public $size;
        public $ori_pic_url = '';
        public $width = '';
        public $height = '';
        protected $saveDir = '';
        protected $downloadFailedTxt;
    
        public function __construct($sougou_id, $size, $title, $ori_pic_url, $width, $height)
        {
            $this->sougou_id = $sougou_id;
            $this->size = $size;
            $this->title = $title;
            $this->ori_pic_url = $ori_pic_url;
            $this->width = $width;
            $this->height = $height;
    
            $this->saveDir.='./static/sougouImages/'.date('Y-m-d').'/'.$this->width.'_'.$this->height.'/';
            $this->downloadFailedTxt = $this->saveDir.'1_downloadfailedlist.txt';
            if(!is_dir($this->saveDir)){
                mkdir($this->saveDir, 0777, true);
                chmod($this->saveDir, 0777);
            }
        }
    
        public function run()
        {
            //下载
            $return = $this->downloadImage();
            if (!$return) {
                echo $this->ori_pic_url.' Download failed'.PHP_EOL;
            }else{
                echo $this->ori_pic_url.' Download completed'.PHP_EOL;
            }
        }
    
    
        /**
         * 下载图片
         * @return bool
         */
        public function downloadImage()
        {
            //图片后缀
            $basename = basename($this->ori_pic_url);
            $dot = strrpos($basename, '.');
            $imageExt = substr($basename, $dot);
            $imageTitle = substr($basename, 0, $dot);
            if(strlen($this->title)<2){
                //图片名称
                $imageName = $imageTitle.'_'.$this->sougou_id;
            }else{
                //图片名称
                $imageName = $this->title.'_'.$this->sougou_id;
            }
            $imageName = iconv('UTF-8', 'GBK', $imageName);
            //保存图片路径及名称
            $filename = $this->saveDir.$imageName.$imageExt;
            //判断文件是否已下载
            if(file_exists($filename)){
                file_put_contents($this->downloadFailedTxt, $this->ori_pic_url.' --文件已下载'.PHP_EOL, FILE_APPEND);
                return true;
            }
            //获取远程文件
            $imgContent = $this->myCurl($this->ori_pic_url);
            if(!$imgContent){
                return false;
            }
            //保存图片到本地
            $return=file_put_contents($filename, $imgContent);
    
            if(!file_exists($filename)){
                //记录下载失败的图片信息
                file_put_contents($this->downloadFailedTxt, $this->ori_pic_url.' --下载失败'.PHP_EOL, FILE_APPEND);
                return false;
            }
    
            //图片大小与录入时记录的图片大小不一致,说明图片下载失败
            if(filesize($filename) != $this->size){
                //下载图片不完整,删除
                unlink($filename);
                file_put_contents($this->downloadFailedTxt, $this->ori_pic_url.' --下载图片不完整'.PHP_EOL, FILE_APPEND);
                return false;
            }
            return true;
        }
    
    
        /**
         * @author RenZhicai <renzhicai.sz@mopon.cn>
         * 自定义curl请求
         * @param string $url
         * @return mixed
         */
        public function myCurl($url='')
        {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_TIMEOUT,60);   //只需要设置一个秒的数量就可以
            if(preg_match('/https:///', $url)){
                curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //这个是重点。
            }
            curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1');
            $output = curl_exec($ch);
            if($output === false){
                //记录curl请求失败的详情
                $errorInfo = "cURL Error: ".curl_error($ch);
                file_put_contents('curl_error_'.date('Ymd').'.txt', $errorInfo, FILE_APPEND);
            }
            curl_close($ch);
    
            return $output;
        }
    }
    
    

    2、在Yii2项目根目录执行控制台脚本(console)

    //将执行结果记录到文本文件中
    php yii sougou/download > sougoudownloadinfo.txt
    

    3、下载完后效果一览

    自动按尺寸归类图片

    【参考资料】

  • 相关阅读:
    webpack学习_管理输出(管理资源插件)
    vue路由
    vue动态组件,组件缓存
    vue组件间传参
    模块化
    安装Vue脚手架,创建Vue项目
    Vue常用指令
    VUE概述
    小程序调用微信支付接口
    Android音视频开发之-WebRTC技术实践
  • 原文地址:https://www.cnblogs.com/renzhicai/p/7863473.html
Copyright © 2011-2022 走看看