先看效果
实现原理
发送请求 :将输入的目标网址及保存路径名称采用AJAX异步的方式发送到image.info.php文件,该文件中包含有一个ImageCatch类,注意:因为有一个是指定目标图片抓取,一个是只要指定一个网址,如http://www.111cn.net形式,所以还要有一个参数用来判断是指定目标抓取还是指定网站抓取。
接收请求 :接收发送过来的两个参数,目标网址及保存路径,实例化ImageCatch类,将地址及保存路径传进去,用file_get_contents函数将目标地址的内容读取赋值给一个变量$content。
先说指定图片抓取的实现 :指定图片抓取的方法实现比较简单,直接用file_get_contents函数将图片读取到,再用file_put_contents写入到一个文件保存起来就可以了。
指定网址抓取图片的实现
方法跟指定图片地址抓取就有点不一样了,因为采用的是jquery+ajax无刷新模式抓取,所以,请求要一次一次发,先说第一次发什么请求,很显然,第一次发的请求内容是获取目标网址的所有图片地址及图片总数,那要怎样获取目标网址的所有图片地址呢?思路跟上面的一样,但方法不同;
第一步:用file_get_contents函数读取目标网址赋值给一个content变量。
第二步:用正则匹配所有img标签里的src属性,并保存在一个数组,这样网页的图片地址就已经拿到了
第三步:用正则匹配所有样式表文件link标签的href属性,并保存在一个数组$arr1
第四步:还是用file_get_contents函数读取获取的样式表文件,再用正则去匹配到css样式里的url背景图片地址,并保存在一个数组$arr2,这样css样式的图片又拿到了
第五步:将$arr1和$arr2用array_merge函数进行合并成$arr,再用一个数组$arr3(‘total’=>count($arr))得出图片总数并追加到数组$arr里面去,这样图片地址和总数都拿到了
第六步:用json_encode编译一个返回json数据 第七步:接收返回回来的json数据,将数据都存入一个数组,判断是否数组为空,不为空,则用函数递归的方法调用一个函数,每调用一次,在返回结果后就将该数组的第一个元素去掉,再判断数组是否为空,不为空,则继续发送抓取请求,直到数组为空,全部图片就已经都抓取完毕。
好了现在看例子
index.php
代码如下 | |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>PHP远程图片抓取</title> <style> body { margin:0; padding:0; } #content { width:90%; height:auto; margin:0 auto; margin-top:20px; font-size:12px; color:#333; } #content .h1 { width:100%; line-height:30px; text-align:left; } #content .h2 { width:100%; line-height:30px; text-align:left; } #content .Schedule { width:auto; height:12px; margin:15px 0px; display:none; background:url() } #content ul { width:100%; height:auto; margin-top:10px; } #content ul li { height:24px; line-height:24px;} #content font { color:#f00; } </style> <script type="text/javascript" src="js/jquery.js"></script> <script> $(document).ready(function() { var TargetUrl; var Save; function error(info) { $('#content .h2 font').text(info); } function statusInfo(info) { $('#content ul').append('<li>'+info+'</li>'); } //禁用按钮 function start_d() { $('#Single,#more').attr('disabled','disabled'); } //解放按钮 function start_s() { $('#Single,#more').removeProp('disabled'); } //进度跳转 function href() { location.href='#bottom'; } //单个图片抓取 $('#content .h1 #Single').click(function() { TargetUrl=$('#content .h2 .TargetUrl').val(); Save=$('#content .h2 .Save').val(); if (TargetUrl=='') { error(' * 请填写目标网址'); return; } if (Save=='') { error(' * 请填写保存目录'); return; } var zurl=new Array(TargetUrl); start_d(); Crawl(zurl,Save); }); function Crawl(zurl,Save) { start_d(); $('#content .Schedule').show(); if (zurl.length>0) { var curl=zurl[0]; $.ajax({ url:'image.info.php?Single=Single', dataType:'json', type:'POST', data:'TargetUrl='+curl+'&Save='+Save, success: function(data) { if (data.status=='ok') { statusInfo('远程图片 <font>'+curl+'</font> 抓取成功 已保存在 <font>'+data.FileSave+'</font> 文件大小:<font>'+data.FileSize+'</font>'); zurl.shift(); //删除第一个数组元素并返回 Crawl(zurl,Save); //使用函数递归 href(); }else { zurl.shift(); //删除第一个数组元素并返回 Crawl(zurl,Save); //使用函数递归 statusInfo(data.status); //显示失败信息 $('#content .Schedule').hide(); //隐藏LOADING图片 start_s(); //按钮启用 href(); } } }); }else { $('#content .Schedule').hide(); statusInfo('图片抓取完毕'); start_s(); href(); } } //多个图片抓取 $('#content .h1 #more').click(function() { TargetUrl=$('#content .h2 .TargetUrl').val(); Save=$('#content .h2 .Save').val(); if (TargetUrl=='') { error(' * 请填写目标网址'); return; } var str=/^(https?://)?([da-z.-]+).([a-z.]{2,6})([/w .-]*)*/?$/; if (!str.test(TargetUrl)) { error(' * 目标网址不正确'); return; } if (Save=='') { error(' * 请填写保存目录'); return; } start_d(); $('#content .Schedule').show(); $.ajax({ url:'image.info.php?more=more', dataType:'json', type:'POST', data:'TargetUrl='+TargetUrl+'&Save='+Save, success: function(data) { if (data[0]!='no') { statusInfo('在目标网址 <font>'+TargetUrl+'</font> 找到 <font>'+data['total']+'</font> 张图片,现正在进行抓取....'); var zurl=new Array(); for (i=0; i<data['total']; i++) { zurl.push(data[i]); } Crawl(zurl,Save); }else { statusInfo("未抓取找到任何图片"); $('#content .Schedule').hide(); start_s(); } } }); }); $('#clear').click(function() { $('#content ul li').remove(); }); }); </script> </head> <body> <div id="content"> <h1>PHP远程图片抓取程序</h1> <div class="h1"> 指定图片抓取:<input type="button" value=" 开始抓取 " id="Single" /> <font>目标网址如:http://www.111cn.Net/123.jpg</font> 指定网址抓取:<input type="button" value=" 开始抓取 " id="more" /> <font>目标网址如:http://www.111cn.Net</font> <input type="button" value=" 清空状态信息 " id="clear" /> </div> <div class="Schedule"><font>正在抓取,请稍后...</font> <img src="loading.gif" border="0" /></div> <div class="h2">目标网址:<input type="text" class="TargetUrl" size="40" /> 保存地址:<input type="text" class="Save" /><font></font></div> <ul> </ul> <a name="bottom"></a> </div> </body> </html> |
images.info.php
代码如下 | |
<?php header('Content-Type; text/json; charset=utf-8'); $Single=$_GET['Single']; $more=$_GET['more']; $TargetUrl=$_POST['TargetUrl']; $Save=$_POST['Save']; //判断是抓取单个图片还是多个图片 if ($Single=='Single') { $ImageCatch=new ImageCatch($TargetUrl,$Save); $ImageCatch->S(); }else if ($more=='more') { $ImageCatch=new ImageCatch($TargetUrl,$Save); $ImageCatch->M(); } //图片抓取类 class ImageCatch { private $TargetUrl; //目标地址 private $Save; //保存地址 private $FileName; //文件名称及路径 private $Type; //文件类型 private $Size; //文件大小 //构造函数 public function __construct($TargetUrl,$Save) { $this->TargetUrl=str_replace("'",'',$TargetUrl); //去掉单引号 $this->Save=$Save; } //CSS样式表中图片抓取方法 public function CSS() { $content=@file_get_contents($this->TargetUrl); //CSS图片过滤 preg_match_all('/<link.+href="?(.*?.css)"?.+>/i',$content,$css); $css[1]=array_unique($css[1]);//移除重复的值 $match2=array(); if (count($css[1])>0) { foreach($css[1] as $val) { if (!preg_match('/^(https?://)/i',$val)) { $val=$this->TargetUrl.'/'.$val; $csscontent=@file_get_contents($val); }else { $csscontent=@file_get_contents($val); } //匹配图片URL地址 preg_match_all('/url((.*))/i',$csscontent,$cssimg); $cssimg[1]=array_unique($cssimg[1]);//移除重复的值 } foreach($cssimg[1] as $val) { //去除 " ) 字符 $val=preg_replace(array('/"|)/'),'',$val); //去除../字符 $val=str_replace('../','',$val); //检查是否是http://开头,如果不是则加上要抓取的网址 if (!preg_match('/^(https?://)/i',$val)) { array_push($match2,$this->TargetUrl.'/'.$val); }else { array_push($match2,$val); } } return $match2; } } //计算并返回图片数量及地址 public function M() { $content=@file_get_contents($this->TargetUrl); //网页图片过滤 $str='/<img.+src="?(.+.(jpg|gif|bmp|bnp|png))"?.+>/i'; preg_match_all($str,$content,$res); if ($res[1]) { $res[1]=array_unique($res[1]);//移除重复的值 $httpstr='/^(https?://)/i'; $match=array(); foreach($res[1] as $val) { if (!preg_match($httpstr,$val)) { array_push($match,$this->TargetUrl.'/'.$val); }else { array_push($match,$val); } } $cssimg=$this->CSS(); //扫描出css文件图片的总数与网页图片相加得到总数 $total=array("total"=>count($match)+count($cssimg)); $result=array_merge($total,$match,$cssimg); //返回JSON数据 echo json_encode($result); }else { $res=array('no'); echo json_encode($res); } exit; } //抓取并保存图片 public function S() { $this->Type=substr(strrchr($this->TargetUrl,'.'),1); $this->FileName=$this->Save.'/'.substr(strrchr($this->TargetUrl,'/'),1); $this->imageType(); $content=@file_get_contents($this->TargetUrl); $this->imageDir(); if (!@file_put_contents($this->FileName,$content,FILE_USE_INCLUDE_PATH)) { @unlink($this->FileName); exit('{"status":"没有找到 '.$this->TargetUrl.' 图片"}'); }else { $this->imageSize(); exit('{"status":"ok","FileSave":"'.$this->FileName.'","FileSize":"'.$this->Size.'"}'); } } //新建目录 private function imageDir() { if (!@file_exists($this->Save)) { if (!@mkdir($this->Save,0700)) { exit('{"status":"新建保存目录失败"}'); } } } //文件类型判断 private function imageType() { $typeArr=array('jpg','png','gif','zip','rar'); if (!in_array($this->Type,$typeArr)) { exit('{"status":"要执行抓取的文件扩展名有错误,'.$this->TargetUrl.'"}'); } } //文件大小检测 private function imageSize() { if (file_exists($this->FileName)) { $this->Size=filesize($this->FileName); if ($this->Size>1024*1024*1024) { $this->Size=round($this->Size/1024/1024/1024,2).' GB'; }else if ($this->Size>1024*1024) { $this->Size=round($this->Size/1024/1024,2).' MB'; }else if ($this->Size>1024) { $this->Size=$this->Size/1024; $this->Size=ceil($this->Size).'KB'; }else { $this->Size=$this->Size.'bit'; } }else { return '未找到文件'; } } } ?> |