php file_get_contents抓取Gzip网页乱码的三种解决方法


Posted in PHP onNovember 12, 2013

把抓取到的内容转下编码即可($content=iconv("GBK", "UTF-8//IGNORE", $content);),我们这里讨论的是如何抓取开了Gzip的页面。怎么判断呢?获取的头部当中有Content-Encoding: gzip说明内容是GZIP压缩的。用FireBug看一下就知道页面开了gzip没有。下面是用firebug查看我的博客的头信息,Gzip是开了的。

请求头信息原始头信息
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Connection keep-alive
Cookie __utma=225240837.787252530.1317310581.1335406161.1335411401.1537; __utmz=225240837.1326850415.887.3.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=%E4%BB%BB%E4%BD%95%E9%A1%B9%E7%9B%AE%E9%83%BD%E4%B8%8D%E4%BC%9A%E9%82%A3%E4%B9%88%E7%AE%80%E5%8D%95%20site%3Awww.nowamagic.net; PHPSESSID=888mj4425p8s0m7s0frre3ovc7; __utmc=225240837; __utmb=225240837.1.10.1335411401
Host www.nowamagic.net
User-Agent Mozilla/5.0 (Windows NT 5.1; rv:12.0) Gecko/20100101 Firefox/12.0

下面介绍一些解决方案:

1. 使用自带的zlib库
如果服务器已经装了zlib库,用下面的代码可以轻易解决乱码问题。

$data = file_get_contents("compress.zlib://".$url);

2. 使用CURL代替file_get_contents

function curl_get($url, $gzip=false){
 $curl = curl_init($url);
 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
 curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
 if($gzip) curl_setopt($curl, CURLOPT_ENCODING, "gzip"); // 关键在这里
 $content = curl_exec($curl);
 curl_close($curl);
 return $content;
}

3. 使用gzip解压函数

function gzdecode($data) { 
  $len = strlen($data); 
  if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) { 
    return null;  // Not GZIP format (See RFC 1952) 
  } 
  $method = ord(substr($data,2,1));  // Compression method 
  $flags  = ord(substr($data,3,1));  // Flags 
  if ($flags & 31 != $flags) { 
    // Reserved bits are set -- NOT ALLOWED by RFC 1952 
    return null; 
  } 
  // NOTE: $mtime may be negative (PHP integer limitations) 
  $mtime = unpack("V", substr($data,4,4)); 
  $mtime = $mtime[1]; 
  $xfl   = substr($data,8,1); 
  $os    = substr($data,8,1); 
  $headerlen = 10; 
  $extralen  = 0; 
  $extra     = ""; 
  if ($flags & 4) { 
    // 2-byte length prefixed EXTRA data in header 
    if ($len - $headerlen - 2 < 8) { 
      return false;    // Invalid format 
    } 
    $extralen = unpack("v",substr($data,8,2)); 
    $extralen = $extralen[1]; 
    if ($len - $headerlen - 2 - $extralen < 8) { 
      return false;    // Invalid format 
    } 
    $extra = substr($data,10,$extralen); 
    $headerlen += 2 + $extralen; 
  } 
  $filenamelen = 0; 
  $filename = ""; 
  if ($flags & 8) { 
    // C-style string file NAME data in header 
    if ($len - $headerlen - 1 < 8) { 
      return false;    // Invalid format 
    } 
    $filenamelen = strpos(substr($data,8+$extralen),chr(0)); 
    if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) { 
      return false;    // Invalid format 
    } 
    $filename = substr($data,$headerlen,$filenamelen); 
    $headerlen += $filenamelen + 1; 
  } 
  $commentlen = 0; 
  $comment = ""; 
  if ($flags & 16) { 
    // C-style string COMMENT data in header 
    if ($len - $headerlen - 1 < 8) { 
      return false;    // Invalid format 
    } 
    $commentlen = strpos(substr($data,8+$extralen+$filenamelen),chr(0)); 
    if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) { 
      return false;    // Invalid header format 
    } 
    $comment = substr($data,$headerlen,$commentlen); 
    $headerlen += $commentlen + 1; 
  } 
  $headercrc = ""; 
  if ($flags & 1) { 
    // 2-bytes (lowest order) of CRC32 on header present 
    if ($len - $headerlen - 2 < 8) { 
      return false;    // Invalid format 
    } 
    $calccrc = crc32(substr($data,0,$headerlen)) & 0xffff; 
    $headercrc = unpack("v", substr($data,$headerlen,2)); 
    $headercrc = $headercrc[1]; 
    if ($headercrc != $calccrc) { 
      return false;    // Bad header CRC 
    } 
    $headerlen += 2; 
  } 
  // GZIP FOOTER - These be negative due to PHP's limitations 
  $datacrc = unpack("V",substr($data,-8,4)); 
  $datacrc = $datacrc[1]; 
  $isize = unpack("V",substr($data,-4)); 
  $isize = $isize[1]; 
  // Perform the decompression: 
  $bodylen = $len-$headerlen-8; 
  if ($bodylen < 1) { 
    // This should never happen - IMPLEMENTATION BUG! 
    return null; 
  } 
  $body = substr($data,$headerlen,$bodylen); 
  $data = ""; 
  if ($bodylen > 0) { 
    switch ($method) { 
      case 8: 
        // Currently the only supported compression method: 
        $data = gzinflate($body); 
        break; 
      default: 
        // Unknown compression method 
        return false; 
    } 
  } else { 
    // I'm not sure if zero-byte body content is allowed. 
    // Allow it for now...  Do nothing... 
  } 
  // Verifiy decompressed size and CRC32: 
  // NOTE: This may fail with large data sizes depending on how 
  //       PHP's integer limitations affect strlen() since $isize 
  //       may be negative for large sizes. 
  if ($isize != strlen($data) || crc32($data) != $datacrc) { 
    // Bad format!  Length or CRC doesn't match! 
    return false; 
  } 
  return $data; 
}

使用:
$html=file_get_contents('https://3water.com/');
$html=gzdecode($html);

就介绍这三个方法,应该能解决大部分gzip引起的抓取乱码问题了。
PHP 相关文章推荐
Snoopy类使用小例子
Apr 15 PHP
php ob_flush,flush在ie中缓冲无效的解决方法
May 09 PHP
PHPWind与Discuz截取字符函数substrs与cutstr性能比较
Dec 05 PHP
使用Sphinx对索引进行搜索
Jun 25 PHP
PHP调用MsSQL Server 2012存储过程获取多结果集(包含output参数)的详解
Jul 03 PHP
php模板原理讲解
Nov 13 PHP
php下载文件源代码(强制任意文件格式下载)
May 09 PHP
php随机获取金山词霸每日一句的方法
Jul 09 PHP
php利用header函数下载各种文件
Aug 24 PHP
MAC下通过改apache配置文件切换php多版本的方法
Apr 26 PHP
PHP序列化和反序列化深度剖析实例讲解
Dec 29 PHP
laravel使用redis队列实例讲解
Mar 23 PHP
CodeIgniter使用phpcms模板引擎
Nov 12 #PHP
php用正则表达式匹配URL的简单方法
Nov 12 #PHP
CodeIgniter基本配置详细介绍
Nov 12 #PHP
PHP URL路由类实例
Nov 12 #PHP
PHP set_error_handler()函数使用详解(示例)
Nov 12 #PHP
php inc文件使用的风险和注意事项
Nov 12 #PHP
php防止SQL注入详解及防范
Nov 12 #PHP
You might like
对javascript和select部件的结合运用
2006/10/09 PHP
PHP可变函数的使用详解
2013/06/14 PHP
9个实用的PHP代码片段分享
2015/01/22 PHP
Yii2实现增删改查后留在当前页的方法详解
2017/01/13 PHP
50款非常棒的 jQuery 插件分享
2012/03/29 Javascript
JS保存和删除cookie操作 判断cookie是否存在
2013/11/13 Javascript
JavaScript中的立即执行函数表达式介绍
2015/03/15 Javascript
Jquery easyui 实现动态树
2015/11/17 Javascript
JavaScript 输出显示内容(document.write、alert、innerHTML、console.log)
2016/12/14 Javascript
bootstrap confirmation按钮提示组件使用详解
2017/08/22 Javascript
快速理解 JavaScript 中的 LHS 和 RHS 查询的用法
2017/08/24 Javascript
JS实现统计字符串中字符出现个数及最大个数功能示例
2018/06/04 Javascript
Vue常见面试题整理【值得收藏】
2018/09/20 Javascript
vue组件之间的数据传递方法详解
2019/04/19 Javascript
微信小程序实现拖拽功能
2019/09/26 Javascript
原生javascript运动函数的封装示例【匀速、抛物线、多属性的运动等】
2020/02/23 Javascript
Python中操作文件之write()方法的使用教程
2015/05/25 Python
Python验证文件是否可读写代码分享
2017/12/11 Python
python实现淘宝秒杀聚划算抢购自动提醒源码
2020/06/23 Python
用Python将mysql数据导出成json的方法
2018/08/21 Python
python多线程并发实例及其优化
2019/06/27 Python
python中对数据进行各种排序的方法
2019/07/02 Python
如何基于Python制作有道翻译小工具
2019/12/16 Python
PyQt使用QPropertyAnimation开发简单动画
2020/04/02 Python
pandas dataframe 中的explode函数用法详解
2020/05/18 Python
通过canvas转换颜色为RGBA格式及性能问题的解决
2019/11/22 HTML / CSS
使用SVG实现提示框功能的示例代码
2020/06/05 HTML / CSS
Noon埃及:埃及在线购物
2019/11/26 全球购物
幼儿教师思想汇报
2014/01/10 职场文书
小学综治宣传月活动总结
2014/07/02 职场文书
关键在于落实心得体会
2014/09/03 职场文书
大学四年个人总结
2015/03/03 职场文书
小学国庆节活动总结
2015/03/23 职场文书
2015年工商所工作总结
2015/05/21 职场文书
2016庆祝国庆67周年宣传语
2015/11/25 职场文书
导游词之山东红叶谷
2019/10/31 职场文书