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中在数据库中保存Checkbox数据(2)
Oct 09 PHP
PHP 5.0对象模型深度探索之对象复制
Mar 27 PHP
php连接数据库代码应用分析
May 29 PHP
thinkPHP实现将excel导入到数据库中的方法
Apr 22 PHP
PHP中set_include_path()函数相关用法分析
Jul 18 PHP
实现PHP搜索加分页
Oct 12 PHP
php注册审核重点解析(数据访问)
May 23 PHP
详解PHP 二维数组排序保持键名不变
Mar 06 PHP
PHP函数积累总结
Mar 19 PHP
laravel多条件查询方法(and,or嵌套查询)
Oct 09 PHP
PHP的图像处理实例小结【文字水印、图片水印、压缩图像等】
Dec 20 PHP
PHP单元测试配置与使用方法详解
Dec 27 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语法速查表
2006/12/06 PHP
yii2.0使用Plupload实现带缩放功能的多图上传
2015/12/22 PHP
phpstudy的php版本自由修改的方法
2017/10/18 PHP
ThinkPHP 5.1 跨域配置方法
2019/10/11 PHP
javascript eval和JSON之间的联系
2009/12/31 Javascript
javascript preload&amp;lazy load
2010/05/13 Javascript
一个JQuery写的点击上下滚动的小例子
2011/08/27 Javascript
window.open关于浏览器拦截问题分析及解决方法
2013/02/05 Javascript
js 获取class的元素的方法 以及创建方法getElementsByClassName
2013/03/11 Javascript
Web Inspector:关于在 Sublime Text 中调试Js的介绍
2013/04/18 Javascript
jquery 触发a链接点击事件解决方案
2013/05/02 Javascript
引用 js在IE与FF之间的区别详细解析
2013/11/20 Javascript
html5+javascript制作简易画板附图
2014/04/25 Javascript
Angular 页面跳转时传参问题
2016/08/01 Javascript
JavaScript实现自动切换图片代码
2016/10/11 Javascript
JS监控关闭浏览器操作的实例详解
2017/09/12 Javascript
基于node.js express mvc轻量级框架实践
2017/09/14 Javascript
解决Vue 通过下表修改数组,页面不渲染的问题
2018/03/08 Javascript
详解Vue单元测试case写法
2018/05/24 Javascript
Vue项目添加动态浏览器头部title的方法
2018/07/11 Javascript
CentOS7中源码编译安装NodeJS的完整步骤
2018/10/13 NodeJs
vue动态禁用控件绑定disable的例子
2019/10/28 Javascript
Python ORM框架SQLAlchemy学习笔记之数据添加和事务回滚介绍
2014/06/10 Python
Python Dataframe 指定多列去重、求差集的方法
2018/07/10 Python
python的继承知识点总结
2018/12/10 Python
详解vscode实现远程linux服务器上Python开发
2020/11/10 Python
python tkinter实现下载进度条及抖音视频去水印原理
2021/02/07 Python
美国知名艺术画网站:Art.com
2017/02/09 全球购物
Chicco婴儿用品美国官网:汽车座椅、婴儿推车、高脚椅等
2018/11/05 全球购物
毕业生自我鉴定
2013/12/04 职场文书
学生干部的自我评价分享
2014/01/18 职场文书
吃空饷专项治理工作实施方案
2014/03/04 职场文书
婚礼主持词
2014/03/13 职场文书
小学校长先进事迹材料
2014/05/13 职场文书
求职自我评价范文
2015/03/09 职场文书
用Python实现一个打字速度测试工具来测试你的手速
2021/05/28 Python