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上传文件,创建递归目录的实例代码
Oct 18 PHP
Drupal读取Excel并导入数据库实例
Mar 02 PHP
PHP提示Cannot modify header information - headers already sent by解决方法
Sep 22 PHP
PHP图片自动裁切应付不同尺寸的显示
Oct 16 PHP
浅谈PHP错误类型及屏蔽方法
May 27 PHP
PHP获取链表中倒数第K个节点的方法
Jan 18 PHP
php取出数组单个值的方法
Mar 12 PHP
PHP分页显示的方法分析【附PHP通用分页类】
May 10 PHP
php 中htmlentities导致中文无法查询问题
Sep 10 PHP
PHP实现简易计算器功能
Aug 28 PHP
php多进程模拟并发事务产生的问题小结
Dec 07 PHP
PHP7.0连接DB操作实例分析【基于mysqli】
Sep 26 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
日本十大惊悚动漫
2020/03/04 日漫
深思 PHP 数组遍历的差异(array_diff 的实现)
2008/03/23 PHP
php 遍历数据表数据并列表横向排列的代码
2009/09/05 PHP
php header功能的使用
2013/10/28 PHP
PHP制作万年历
2015/01/07 PHP
javascript编程起步(第四课)
2007/01/10 Javascript
JavaScript 中的事件教程
2007/04/05 Javascript
javascript优先加载笔记代码
2008/09/30 Javascript
JQuery验证工具类搜集整理
2013/01/16 Javascript
JS表单验证的代码(常用)
2016/04/08 Javascript
Vue.js每天必学之过渡与动画
2016/09/06 Javascript
javascript 内置对象及常见API详细介绍
2016/11/01 Javascript
JavaScript表单验证的两种实现方法
2017/02/11 Javascript
nodejs入门教程六:express模块用法示例
2017/04/24 NodeJs
基于webpack 实用配置方法总结
2017/09/28 Javascript
vue-cli的eslint相关用法
2017/09/29 Javascript
vue首次赋值不触发watch的解决方法
2018/09/11 Javascript
微信小程序云开发(数据库)详解
2019/05/17 Javascript
javascript中的数据类型检测方法详解
2019/08/07 Javascript
使用webpack搭建pixi.js开发环境
2020/02/12 Javascript
[01:54]TI珍贵瞬间系列(三):翻盘
2020/08/28 DOTA
如何使用VSCode愉快的写Python于调试配置步骤
2018/04/06 Python
python输出第n个默尼森数的实现示例
2020/03/08 Python
关于tensorflow softmax函数用法解析
2020/06/30 Python
Python使用文件操作实现一个XX信息管理系统的示例
2020/07/02 Python
python3 简单实现组合设计模式
2020/07/02 Python
python实现图片素描效果
2020/09/26 Python
Nip + Fab官网:英国美容品牌
2019/08/26 全球购物
《蚂蚁和蝈蝈》教学反思
2014/02/24 职场文书
建设单位项目负责人任命书
2014/06/06 职场文书
幼儿园八一建军节活动方案
2014/08/27 职场文书
2015新学期校长寄语(3篇)
2015/03/25 职场文书
买卖合同纠纷代理词
2015/05/25 职场文书
高中开学感言
2015/08/01 职场文书
感恩教育主题班会
2015/08/12 职场文书
2016年“七一建党节”广播稿
2015/12/18 职场文书