上一篇,完成了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">
<?php
namespace console\controllers;
use yii;
use yii\console\Controller;
use common\models\SougouPic as M;
use common\component\SougouPthreads;
use yii\console\Exception;
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">
<?php
namespace common\component;
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">//将执行结果记录到文本文件中
php yii sougou/download > sougoudownloadinfo.txt
3、下载完后效果一览
自动按尺寸归类图片
【参考资料】
- PHP Pthread多线程 操作