该文章主要介绍了简单的爬虫,将网站上的图片抓取到本地,可深度抓取
方式1: 抓取指定图片
/**
* PHP将网页上的图片攫取到本地存储
* @param string $imgUrl 图片url地址
* @param string $saveDir 本地存储路径 默认存储在当前路径
* @param null $fileName 图片存储到本地的文件名
* @return array
*/
function crabImage($imgUrl = '', $saveDir = 'uploads/', $fileName = null)
{
if (empty($imgUrl)) {
return false;
}
//获取图片信息大小
$imgSize = getImageSize($imgUrl);
if (!in_array($imgSize['mime'], array('image/jpg', 'image/gif', 'image/png', 'image/jpeg'), true)) {
return false;
}
//获取后缀名
$_mime = explode('/', $imgSize['mime']);
$_ext = '.' . end($_mime);
if (empty($fileName)) { //生成唯一的文件名
$fileName = uniqid(time(), true) . $_ext;
}
//开始攫取
ob_start();
readfile($imgUrl);
$imgInfo = ob_get_contents();
ob_end_clean();
if (!is_dir($saveDir)) {
mkdir($saveDir, 0755, true);
}
$fp = fopen($saveDir . $fileName, 'a');
$imgLen = strlen($imgInfo); //计算图片源码大小
$_inx = 1024; //每次写入1k
$_time = ceil($imgLen / $_inx);
for ($i = 0; $i < $_time; $i++) {
fwrite($fp, substr($imgInfo, $i * $_inx, $_inx));
}
fclose($fp);
return array('file_name' => $fileName, 'save_path' => $saveDir . $fileName);
}
方式2: 抓取指定图片(处理重定向)
/**
* 下载远程图片
* @param string $url 图片的绝对url
* @param string $filepath 文件的完整路径(例如/www/images/test) ,此函数会自动根据图片url和http头信息确定图片的后缀名
* @param string $filename 要保存的文件名(不含扩展名)
* @return mixed 下载成功返回一个描述图片信息的数组,下载失败则返回false
*/
function downloadImage($url, $filepath = 'uploads/', $filename = '')
{
if(!$url){
return false;
}
//服务器返回的头信息
$responseHeaders = array();
//原始图片名
$originalfilename = '';
//图片的后缀名
$ext = '';
$ch = curl_init($url);
//设置curl_exec返回的值包含Http头
curl_setopt($ch, CURLOPT_HEADER, 1);
//设置curl_exec返回的值包含Http内容
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//设置抓取跳转(http 301,302)后的页面
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
//设置最多的HTTP重定向的数量
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
//服务器返回的数据(包括http头信息和内容)
$html = curl_exec($ch);
//获取此次抓取的相关信息
$httpinfo = curl_getinfo($ch);
curl_close($ch);
if ($html !== false) {
//分离response的header和body,由于服务器可能使用了302跳转,所以此处需要将字符串分离为 2+跳转次数 个子串
$httpArr = explode("\r\n\r\n", $html, 2 + $httpinfo['redirect_count']);
//倒数第二段是服务器最后一次response的http头
$header = $httpArr[count($httpArr) - 2];
//倒数第一段是服务器最后一次response的内容
$body = $httpArr[count($httpArr) - 1];
$header .= "\r\n";
//获取最后一次response的header信息
preg_match_all('/([a-z0-9-_]+):\s*([^\r\n]+)\r\n/i', $header, $matches);
if (!empty($matches) && count($matches) == 3 && !empty($matches[1]) && !empty($matches[1])) {
for ($i = 0; $i < count($matches[1]); $i++) {
if (array_key_exists($i, $matches[2])) {
$responseHeaders[$matches[1][$i]] = $matches[2][$i];
}
}
}
//获取图片后缀名
if (0 < preg_match('{(?:[^\/\\\\]+)\.(jpg|jpeg|gif|png|bmp)$}i', $url, $matches)) {
$originalfilename = $matches[0];
$ext = $matches[1];
} else {
if (array_key_exists('Content-Type', $responseHeaders)) {
if (0 < preg_match('{image/(\w+)}i', $responseHeaders['Content-Type'], $extmatches)) {
$ext = $extmatches[1];
}
}
}
//保存文件
if (!empty($ext)) {
//如果目录不存在,则先要创建目录
if (!is_dir($filepath)) {
mkdir($filepath, 0755, true);
}
if (empty($filename)) { //生成唯一的文件名
$filename = uniqid(time(), true);
}
$filename = $filepath . $filename . ".$ext";
$local_file = fopen($filename, 'w');
if (false !== $local_file) {
if (false !== fwrite($local_file, $body)) {
fclose($local_file);
$sizeinfo = getimagesize($filename);
return array('filepath' => realpath($filepath), 'width' => $sizeinfo[0], 'height' => $sizeinfo[1], 'orginalfilename' => $originalfilename, 'filename' => pathinfo($filename, PATHINFO_BASENAME));
}
}
}
}
return false;
}
方式3: 深度抓取或者只抓取当前页面(抓取过的再次抓取不会重复进行)
- 封装类
<?php
namespace grabpictures;
class downloadImage
{
private $save_path; //抓取图片的保存地址
//抓取图片的大小限制(单位:字节) 只抓比size大的图片
private $img_size = 0;
//定义一个静态数组,用于记录曾经抓取过的的超链接地址,避免重复抓取
public static $a_url_arr = array();
//是否只爬取当前页面:true-当前页面,false-深层爬取
private $only_current_page;
/**
* @param String $save_path 抓取图片的保存地址
* @param Int $img_size 抓取图片的保存地址
*/
public function __construct($save_path, $img_size, $only_current_page = true)
{
$this->mkdir($save_path);
$this->save_path = $save_path;
$this->img_size = $img_size;
$this->only_current_page = $only_current_page;
}
/**
* 递归下载抓取首页及其子页面图片的方法 ( recursive 递归)
*
* @param String $capture_url 用于抓取图片的网址
*
*/
public function recursive_download_images($capture_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];
}
}
if(!$this->only_current_page){
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地址的一个数组
*/
private function download_current_page_images($capture_url)
{
$content = @file_get_contents($capture_url); //屏蔽warning错误
//匹配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
*
*/
private 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;
}
//将图片内容读入一个字符串
$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/>';
}
}
private function mkdir($path)
{
if (!file_exists($path)) {
@mkdir($path, 0755, true);
}
}
}
- 使用
<?php
use grabpictures\downloadImage;
class Test
{
public function index()
{
set_time_limit(0); //设置脚本的最大执行时间 根据情况设置
$download_img = new downloadImage('./upload/curl/images/', 0); //实例化下载图片对象
$download_img->recursive_download_images('http://sc.chinaz.com/tupian/191021556795.htm');
}
}