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 读取文件内容代码(txt,js等)
Dec 06 PHP
自己在做项目过程中学到的PHP知识收集
Aug 20 PHP
基于python发送邮件的乱码问题的解决办法
Apr 25 PHP
利用curl抓取远程页面内容的示例代码
Jul 23 PHP
PHP图片处理之使用imagecopyresampled函数实现图片缩放例子
Nov 19 PHP
十大使用PHP框架的理由
Sep 26 PHP
关于PHP通用返回值设置方法
Mar 31 PHP
Thinkphp5结合layer弹窗定制操作结果页面
Jul 07 PHP
PHP编程实现微信企业向用户付款的方法示例
Jul 26 PHP
php连接MSsql server的五种方法总结
Mar 04 PHP
PHP中类与对象功能、用法实例解读
Mar 27 PHP
PHP+MySql实现一个简单的留言板
Jul 19 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生成随机数或者字符串的代码
2008/09/05 PHP
PHP中SQL查询语句的id=%d解释(推荐)
2016/12/10 PHP
PHP实现对数组分页处理实例详解
2017/02/07 PHP
PHP使用preg_split和explode分割textarea存放内容的方法分析
2017/07/03 PHP
js取整数、取余数的方法
2014/05/11 Javascript
js调试工具console.log()方法查看js代码的执行情况
2014/08/08 Javascript
JavaScript设计模式之建造者模式介绍
2014/12/28 Javascript
JQuery替换DOM节点的方法
2015/06/11 Javascript
jQuery实现的多级下拉菜单效果代码
2015/08/24 Javascript
js实现目录链接,内容跟着目录滚动显示的简单实例
2016/10/15 Javascript
基于Vuejs框架实现翻页组件
2020/06/29 Javascript
微信小程序之页面拦截器的示例代码
2017/09/07 Javascript
vue-cli 目录结构详细讲解总结
2019/01/15 Javascript
Vue 实现前进刷新后退不刷新的效果
2019/06/14 Javascript
[00:15]天涯墨客终极技能展示
2018/08/25 DOTA
详解tensorflow训练自己的数据集实现CNN图像分类
2018/02/07 Python
python爬虫框架scrapy实现模拟登录操作示例
2018/08/02 Python
Python面向对象类编写细节分析【类,方法,继承,超类,接口等】
2019/01/05 Python
Python线程之定位与销毁的实现
2019/02/17 Python
Python中format()格式输出全解
2019/04/12 Python
对Python中小整数对象池和大整数对象池的使用详解
2019/07/09 Python
python代码编写计算器小程序
2020/03/30 Python
完美解决jupyter由于无法import新包的问题
2020/05/26 Python
Python自动巡检H3C交换机实现过程解析
2020/08/14 Python
利用python制作拼图小游戏的全过程
2020/12/04 Python
Pyside2中嵌入Matplotlib的绘图的实现
2021/02/22 Python
HelloFresh澳大利亚:订购你的美味食品盒、健康餐食
2018/03/28 全球购物
园长自我鉴定
2013/10/06 职场文书
团日活动总结怎么写
2014/06/25 职场文书
毕业设计论文评语
2014/12/31 职场文书
外贸业务员岗位职责
2015/02/13 职场文书
项目负责人岗位职责
2015/02/15 职场文书
小学教师暑期培训心得体会
2016/01/09 职场文书
《颐和园》教学反思
2016/02/19 职场文书
实习报告范文之电话客服岗位
2019/07/26 职场文书
Java实现聊天机器人完善版
2021/07/04 Java/Android