啦啦啦,本週工作日的最後一天,我來冒個泡
預備
要了解CURL的使用:參考一:我自己總結的curl的使用;
參考二:CURL手冊;
參考三:匹配查找
一、背景,原因
今天其實沒有特別的事情,突然想起來前端時間朋友的網店,因爲供應商不給提供圖片數據包,只能一張一張的保存,然後上傳,我就覺着我試試獲取網站的圖片吧(支持獲取https協議網站);
二、漫漫請求路
這個實現就是獲取網站的信息,那麼首先映入腦海的萬能的CURL方法,不瞭解的可以點擊去學習一下。這裏很重要,只有抓取到頁面數據你才能獲取到想要的東西並保存下來;
首先,獲取頁面數據:
這個封裝的方法也是支持抓取http、https兩種協議的網站頁面信息
public function is_request($url, $ssl = true, $type = "GET", $data = null)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
$user_agent = isset($_SERVER["HTTP_USERAGENT"]) ?
$_SERVER['HTTP_USERAGENT'] :
'Mozilla / 5.0 (Windows NT 6.1; WOW64) AppleWebKit / 537.36 (KHTML, like Gecko) Chrome / 50.0.2661.102 Safari / 537.36';
curl_setopt($curl, CURLOPT_USERAGENT, $user_agent);//請求代理信息
curl_setopt($curl, CURLOPT_AUTOREFERER, true);//referer頭 請求來源
curl_setopt($curl, CURLOPT_TIMEOUT, 30);//請求超時
curl_setopt($curl, CURLOPT_HEADER, false);//是否處理響應頭
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);//curl_exec()是否返回響應
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
if ($ssl) {
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);//禁用後curl將終止從服務端進行驗證
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);//檢查服務器ssl證書中是否存在一個公用名(common name)
}
if ($type == 'POST') {
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
//發出請求
$response = curl_exec($curl);
if ($response === false) {
return false;
}
return $response;
}
其次,就是通過正則匹配,獲取頁面中所有的滿足你條件的字符串組:
$img_pattern = "|<img[^>]+src=['\" ]?([^ '\"?]+)['\" >]|U";
preg_match_all($img_pattern, $content, $img_out, PREG_SET_ORDER);
最後嘍,你都獲取到了頁面中所有的img標籤,那就可以循環保存在自己指定的文件中嘍:
/**
* 保存單個圖片的方法
*
* @param String $capture_url 用於抓取圖片的網頁地址
* @param String $img_url 需要保存的圖片的url
*
*/
public function save_one_img($capture_url,$img_url)
{
//圖片路徑地址
// if ( strpos($img_url, 'http://')!==false )
// {
// // $img_url = $img_url;
// }else
// {
// $domain_url = substr($capture_url, 0,strpos($capture_url, '/',8)+1);
// $img_url=$domain_url.$img_url;
// }
$pathinfo = pathinfo($img_url); //獲取圖片路徑信息
$pic_name=$pathinfo['basename']; //獲取圖片的名字
if (file_exists($this->save_path.$pic_name)) //如果圖片存在,證明已經被抓取過,退出函數
{
echo $img_url . '<span style="color:red;margin-left:80px">該圖片已經抓取過!</span><br/>';
return;
}
//將圖片內容讀入一個字符串
// dd($img_url);
// info($img_url);
$img_data = @file_get_contents($img_url); //屏蔽掉因爲圖片地址無法讀取導致的warning錯誤
if ( strlen($img_data) > $this->img_size ) //下載size比限制大的圖片
{
$img_size = file_put_contents($this->save_path . $pic_name, $img_data);
if ($img_size)
{
echo $img_url . '<span style="color:green;margin-left:80px">圖片保存成功!</span><br/>';
} else
{
echo $img_url . '<span style="color:red;margin-left:80px">圖片保存失敗!</span><br/>';
}
} else
{
echo $img_url . '<span style="color:red;margin-left:80px">圖片讀取失敗!</span><br/>';
}
}
當然,爲了避免重複下載,我判斷了是否已經下載過,下面的完整的項目代碼:BaseService主要是爲了引入is_request()
三、重中之重,完整的代碼
class GetImgController extends Controller
{
public $save_path; //抓取圖片的保存地址
//抓取圖片的大小限制(單位:字節) 只抓比size比這個限制大的圖片
public $img_size=0;
//定義一個靜態數組,用於記錄曾經抓取過的的超鏈接地址,避免重複抓取
public static $a_url_arr=array();
protected $baseService ;
/**
* @param BaseService $baseService
*/
public function __construct(BaseService $baseService)
{
$this->save_path=public_path().'/uploadfile/curl_img/chumaoqi/lunbo/';
$this->img_size=0;
$this->baseService = $baseService;
}
/**
* 遞歸下載抓取首頁及其子頁面圖片的方法 ( recursive 遞歸)
*
* @param Request $request
*
*/
public function recursive_download_images(Request $request)
{
$capture_url = $request->input('url');
if (!in_array($capture_url,self::$a_url_arr)) //沒抓取過
{
self::$a_url_arr[]=$capture_url; //計入靜態數組
} else //抓取過,直接退出函數
{
return;
}
$this->download_current_page_images($capture_url); //下載當前頁面的所有圖片
//用@屏蔽掉因爲抓取地址無法讀取導致的warning錯誤
$content=@file_get_contents($capture_url);
//匹配a標籤href屬性中?之前部分的正則
$a_pattern = "|<a[^>]+href=['\" ]?([^ '\"?]+)['\" >]|U";
preg_match_all($a_pattern, $content, $a_out, PREG_SET_ORDER);
$tmp_arr=array(); //定義一個數組,用於存放當前循環下抓取圖片的超鏈接地址
foreach ($a_out as $k => $v)
{
/**
* 去除超鏈接中的 空'','#','/'和重複值
* 1: 超鏈接地址的值 不能等於當前抓取頁面的url, 否則會陷入死循環
* 2: 超鏈接爲''或'#','/'也是本頁面,這樣也會陷入死循環,
* 3: 有時一個超連接地址在一個網頁中會重複出現多次,如果不去除,會對一個子頁面進行重複下載)
*/
if ( $v[1] && !in_array($v[1],self::$a_url_arr) &&!in_array($v[1],array('#','/',$capture_url) ) )
{
$tmp_arr[]=$v[1];
}
}
foreach ($tmp_arr as $k => $v)
{
//超鏈接路徑地址
if ( strpos($v, 'http://')!==false ) //如果url包含http://,可以直接訪問
{
$a_url = $v;
}else //否則證明是相對地址, 需要重新拼湊超鏈接的訪問地址
{
$domain_url = substr($capture_url, 0,strpos($capture_url, '/',8)+1);
$a_url=$domain_url.$v;
}
$this->recursive_download_images($a_url);
}
}
/**
* 下載當前網頁下的所有圖片
*
* @param String $capture_url 用於抓取圖片的網頁地址
* @return Array 當前網頁上所有圖片img標籤url地址的一個數組
*/
public function download_current_page_images($capture_url)
{
// $capture_url = $request->input('url');
$content = $this->baseService->is_request($capture_url);
//匹配img標籤src屬性中?之前部分的正則
$img_pattern = "|<img[^>]+src=['\" ]?([^ '\"?]+)['\" >]|U";
preg_match_all($img_pattern, $content, $img_out, PREG_SET_ORDER);
$photo_num = count($img_out);
//匹配到的圖片數量
echo '<h1>'.$capture_url . "共找到 " . $photo_num . " 張圖片</h1>";
foreach ($img_out as $k => $v)
{
$this->save_one_img($capture_url,$v[1]);
}
}
/**
* 保存單個圖片的方法
*
* @param String $capture_url 用於抓取圖片的網頁地址
* @param String $img_url 需要保存的圖片的url
*
*/
public function save_one_img($capture_url,$img_url)
{
//圖片路徑地址
// if ( strpos($img_url, 'http://')!==false )
// {
// // $img_url = $img_url;
// }else
// {
// $domain_url = substr($capture_url, 0,strpos($capture_url, '/',8)+1);
// $img_url=$domain_url.$img_url;
// }
$pathinfo = pathinfo($img_url); //獲取圖片路徑信息
$pic_name=$pathinfo['basename']; //獲取圖片的名字
if (file_exists($this->save_path.$pic_name)) //如果圖片存在,證明已經被抓取過,退出函數
{
echo $img_url . '<span style="color:red;margin-left:80px">該圖片已經抓取過!</span><br/>';
return;
}
//將圖片內容讀入一個字符串
// dd($img_url);
// info($img_url);
$img_data = @file_get_contents($img_url); //屏蔽掉因爲圖片地址無法讀取導致的warning錯誤
if ( strlen($img_data) > $this->img_size ) //下載size比限制大的圖片
{
$img_size = file_put_contents($this->save_path . $pic_name, $img_data);
if ($img_size)
{
echo $img_url . '<span style="color:green;margin-left:80px">圖片保存成功!</span><br/>';
} else
{
echo $img_url . '<span style="color:red;margin-left:80px">圖片保存失敗!</span><br/>';
}
} else
{
echo $img_url . '<span style="color:red;margin-left:80px">圖片讀取失敗!</span><br/>';
}
}
}
其中recursive_download_images()是遞歸下載指定頁面以及子頁面下的圖片,download_current_page_images()只是下載指定地址頁面的圖片,你可以稍作調整,從而滿足你的需求。
四、寫在最後
網絡有很多這種curl請求獲取頁面數據的,大家都可以參考