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 相关文章推荐
php 小乘法表实现代码
Jul 16 PHP
基于PHP的cURL快速入门教程 (小偷采集程序)
Jun 02 PHP
PHP安全配置详细说明
Sep 26 PHP
深入理解用mysql_fetch_row()以数组的形式返回查询结果
Jun 05 PHP
PHP系统命令函数使用分析
Jul 05 PHP
PHP imagegrabscreen和imagegrabwindow(截取网站缩略图)的实例代码
Nov 07 PHP
ThinkPHP中数据操作案例分析
Sep 27 PHP
php关闭warning问题的解决方法
May 17 PHP
PHP不使用递归的无限级分类简单实例
Nov 05 PHP
Yii2配置Nginx伪静态的方法
May 05 PHP
thinkphp3.2实现在线留言提交验证码功能
Jul 19 PHP
php的无刷新操作实现方法分析
Feb 28 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
php实现每天自动变换随机问候语的方法
2015/05/12 PHP
浅谈PHP的$_SERVER[SERVER_NAME]
2017/02/04 PHP
PHP获取文件扩展名的方法实例总结
2017/06/10 PHP
LazyForm jQuery plugin 定制您的CheckBox Radio和Select
2009/10/24 Javascript
jQuery结合Json提交数据到Webservice,并接收从Webservice返回的Json数据
2011/02/18 Javascript
jQuery之$(document).ready()使用介绍
2012/04/05 Javascript
javascript针对DOM的应用分析(四)
2012/04/15 Javascript
toggle()隐藏问题的解决方法
2014/02/17 Javascript
使用JS实现图片展示瀑布流效果的实例代码
2016/09/12 Javascript
Avalonjs 实现简单购物车功能(实例代码)
2017/02/07 Javascript
Canvas 绘制粒子动画背景
2017/02/15 Javascript
vue.js从安装到搭建过程详解
2017/03/17 Javascript
vue.js实现用户评论、登录、注册、及修改信息功能
2020/05/30 Javascript
基于jQuery.i18n实现web前端的国际化
2018/05/04 jQuery
详解微信小程序文件下载--视频和图片
2019/04/24 Javascript
Vue CLI项目 axios模块前后端交互的使用(类似ajax提交)
2019/09/01 Javascript
微信小程序全选多选效果实现代码解析
2020/01/21 Javascript
[02:32]DOTA2英雄基础教程 祸乱之源
2013/12/23 DOTA
跟老齐学Python之正规地说一句话
2014/09/28 Python
python之从文件读取数据到list的实例讲解
2018/04/19 Python
Python实现的个人所得税计算器示例
2018/06/01 Python
浅谈python下含中文字符串正则表达式的编码问题
2018/12/07 Python
python文件写入write()的操作
2019/05/14 Python
python os模块简单应用示例
2019/05/23 Python
详解Python中的各种转义符\n\r\t
2019/07/10 Python
3行Python代码实现图像照片抠图和换底色的方法
2019/10/10 Python
利用Tensorflow构建和训练自己的CNN来做简单的验证码识别方式
2020/01/20 Python
HTML5+CSS3实现无插件拖拽上传图片(支持预览与批量)
2017/01/05 HTML / CSS
西班牙在线宠物食品和配件商店:bitiba
2019/10/11 全球购物
三年级评语大全
2014/04/23 职场文书
歌颂祖国演讲稿
2014/05/04 职场文书
防沙治沙典型材料
2014/05/07 职场文书
出差报告范文
2014/11/06 职场文书
综合管理员岗位职责
2015/02/11 职场文书
保外就医申请书范文
2015/08/06 职场文书
Python学习之时间包使用教程详解
2022/03/21 Python