有时候用 file_get_contents() 函数抓取网页会发生乱码现象。有两个原因会导致乱码,一个是编码问题,一个是目标页面开了Gzip。

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

1 请求头信息原始头信息
2 Accept  text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
3 Accept-Encoding gzip, deflate
4 Accept-Language zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
5 Connection  keep-alive
6 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
7 Host    www.nowamagic.net
8 User-Agent  Mozilla/5.0 (Windows NT 5.1; rv:12.0) Gecko/20100101 Firefox/12.0

下面介绍一些解决方案:

1. 使用自带的zlib库

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

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

2. 使用CURL代替file_get_contents

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

3. 使用gzip解压函数

001 function gzdecode($data) {
002   $len = strlen($data);
003   if ($len < 18 || strcmp(substr($data,0,2),"\x1f\x8b")) {
004     return null;  // Not GZIP format (See RFC 1952)
005   }
006   $method = ord(substr($data,2,1));  // Compression method
007   $flags  = ord(substr($data,3,1));  // Flags
008   if ($flags & 31 != $flags) {
009     // Reserved bits are set -- NOT ALLOWED by RFC 1952
010     return null;
011   }
012   // NOTE: $mtime may be negative (PHP integer limitations)
013   $mtime = unpack("V", substr($data,4,4));
014   $mtime = $mtime[1];
015   $xfl   = substr($data,8,1);
016   $os    = substr($data,8,1);
017   $headerlen = 10;
018   $extralen  = 0;
019   $extra     = "";
020   if ($flags & 4) {
021     // 2-byte length prefixed EXTRA data in header
022     if ($len - $headerlen - 2 < 8) {
023       return false;    // Invalid format
024     }
025     $extralen = unpack("v",substr($data,8,2));
026     $extralen = $extralen[1];
027     if ($len - $headerlen - 2 - $extralen < 8) {
028       return false;    // Invalid format
029     }
030     $extra = substr($data,10,$extralen);
031     $headerlen += 2 + $extralen;
032   }
033  
034   $filenamelen = 0;
035   $filename = "";
036   if ($flags & 8) {
037     // C-style string file NAME data in header
038     if ($len - $headerlen - 1 < 8) {
039       return false;    // Invalid format
040     }
041     $filenamelen = strpos(substr($data,8+$extralen),chr(0));
042     if ($filenamelen === false || $len - $headerlen - $filenamelen - 1 < 8) {
043       return false;    // Invalid format
044     }
045     $filename = substr($data,$headerlen,$filenamelen);
046     $headerlen += $filenamelen + 1;
047   }
048  
049   $commentlen = 0;
050   $comment = "";
051   if ($flags & 16) {
052     // C-style string COMMENT data in header
053     if ($len - $headerlen - 1 < 8) {
054       return false;    // Invalid format
055     }
056     $commentlen = strpos(substr($data,8+$extralen+$filenamelen),chr(0));
057     if ($commentlen === false || $len - $headerlen - $commentlen - 1 < 8) {
058       return false;    // Invalid header format
059     }
060     $comment = substr($data,$headerlen,$commentlen);
061     $headerlen += $commentlen + 1;
062   }
063  
064   $headercrc = "";
065   if ($flags & 1) {
066     // 2-bytes (lowest order) of CRC32 on header present
067     if ($len - $headerlen - 2 < 8) {
068       return false;    // Invalid format
069     }
070     $calccrc = crc32(substr($data,0,$headerlen)) & 0xffff;
071     $headercrc = unpack("v", substr($data,$headerlen,2));
072     $headercrc = $headercrc[1];
073     if ($headercrc != $calccrc) {
074       return false;    // Bad header CRC
075     }
076     $headerlen += 2;
077   }
078  
079   // GZIP FOOTER - These be negative due to PHP's limitations
080   $datacrc = unpack("V",substr($data,-8,4));
081   $datacrc = $datacrc[1];
082   $isize = unpack("V",substr($data,-4));
083   $isize = $isize[1];
084  
085   // Perform the decompression:
086   $bodylen = $len-$headerlen-8;
087   if ($bodylen < 1) {
088     // This should never happen - IMPLEMENTATION BUG!
089     return null;
090   }
091   $body = substr($data,$headerlen,$bodylen);
092   $data = "";
093   if ($bodylen > 0) {
094     switch ($method) {
095       case 8:
096         // Currently the only supported compression method:
097         $data = gzinflate($body);
098         break;
099       default:
100         // Unknown compression method
101         return false;
102     }
103   } else {
104     // I'm not sure if zero-byte body content is allowed.
105     // Allow it for now...  Do nothing...
106   }
107  
108   // Verifiy decompressed size and CRC32:
109   // NOTE: This may fail with large data sizes depending on how
110   //       PHP's integer limitations affect strlen() since $isize
111   //       may be negative for large sizes.
112   if ($isize != strlen($data) || crc32($data) != $datacrc) {
113     // Bad format!  Length or CRC doesn't match!
114     return false;
115   }
116   return $data;
117 }

使用:

1 $html=file_get_contents('http://www.nowamagic.net/librarys/veda/');
2 $html=gzdecode($html);

就介绍这三个方法,应该能解决大部分gzip引起的抓取乱码问题了。

如何抓取开了gzip的网页的更多相关文章

  1. 简易数据分析 12 | Web Scraper 翻页——抓取分页器翻页的网页

    这是简易数据分析系列的第 12 篇文章. 前面几篇文章我们介绍了 Web Scraper 应对各种翻页的解决方法,比如说修改网页链接加载数据.点击"更多按钮"加载数据和下拉自动加载 ...

  2. htmlunit抓取js执行后的网页源码

    上次我不是写了一个自动抓取博客访问量吗 (点击打开链接) 可是昨天晚上我又运行的时候,发现不能用了.. 运行了几次 发现使用URLConnection 得到的网页源码和浏览器直接查看的不同. URLC ...

  3. Java HttpURLConnection 抓取网页内容 解析gzip格式输入流数据并转换为String格式字符串

    最近GFW为了刷存在感,搞得大家是头晕眼花,修改hosts 几乎成了每日必备工作. 索性写了一个小程序,给办公室的同事们分享,其中有个内容 就是抓取网络上的hosts,废了一些周折. 我是在一个博客上 ...

  4. Scrapy爬虫框架教程(四)-- 抓取AJAX异步加载网页

    欢迎关注博主主页,学习python视频资源,还有大量免费python经典文章 sklearn实战-乳腺癌细胞数据挖掘 https://study.163.com/course/introduction ...

  5. Python3抓取javascript生成的html网页

    用urllib等抓取网页,只能读取网页的静态源文件,而抓不到由javascript生成的内容. 究其原因,是因为urllib是瞬时抓取,它不会等javascript的加载延迟,所以页面中由javasc ...

  6. 网络包抓取开发包 Npcap

    Npcap 是 Nmap 项目的网络包抓取库在 Windows 下的版本. Npcap 是致力于采用 Microsoft Light-Weight Filter (NDIS 6 LWF) 技术和 Wi ...

  7. python抓取历年特码开奖记录

    背景: 小时候,有种游戏,两个主人公:白XX和曾XX,每个家庭把他俩像活菩萨一样供着,供他们吃,供他们穿 做生意的老板为了这两位活菩萨,关门大吉 农民为了这两位活菩萨卖牛卖田变卖家产 做官的为了这两位 ...

  8. 如何让Python爬虫一天抓取100万张网页

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 王平 源自:猿人学Python PS:如有需要Python学习资料的 ...

  9. Java---网络蜘蛛-网页邮箱抓取器~源码

    刚刚学完Socket,迫不及待的做了这个网页邮箱抓取~~~ 现在有越来越多的人热衷于做网络爬虫(网络蜘蛛),也有越来越多的地方需要网络爬虫,比如搜索引擎.资讯采集.舆情监测等等,诸如此类.网络爬虫涉及 ...

随机推荐

  1. Leecode刷题之旅-C语言/python-69x的平方根

    /* * @lc app=leetcode.cn id=69 lang=c * * [69] x 的平方根 * * https://leetcode-cn.com/problems/sqrtx/des ...

  2. 一个新晋IT行业的努力Duiker

      亲爱的朋友,你好!   我很开心能以这么一篇博客来开始我的IT努力之路.我叫Duiker,是一名软件工程专业的学生,想通过写博客来提升自己,充实自我. 首先,我要确立自己的学习编程目标: 1.将算 ...

  3. [JSOI2007] 建筑抢修 (贪心 + 优先队列)

    小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的入侵者.但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快修复的话,这些建筑设施将会 ...

  4. linux ln 建立软链接-- 基于dubbo-zookeeper服务的 服务jar 引用公共的 lib

    对于ln命令网上有很多的教程,这里不再复述, 其基本目的是:多个文件夹公用一个文件夹的里的文件. 其基本命令格式: ln [option] source_file dist_file (source_ ...

  5. FPGA的嵌入式乘法器

    1. FPGA主要应用在并行处理资源的应用,视频与图像处理,无线通信的中频调制解调器. 嵌入式乘法器可以配置成一个 18 × 18 乘法器,或者配置成两个 9 × 9 乘法器.对于那些大于18 × 1 ...

  6. CentOS修改网卡名称

    转 一.问题说明 测试环境中出现的小问题,因为虚拟机之间经常复制来复制去,导致网卡配置这块的不一致现象. 配置文件的信息: [root@ora10g network-scripts]# catifcf ...

  7. beego orm

    http://beego.me/docs/mvc/model/overview.md go get github.com/astaxie/beego/orm Simple Usage package ...

  8. 给socks-proxy-agent增加认证

    由于需要使用socks代理,查看了nodejs的各种socks库,最终的结论是socks库是其中最完善的,而socks-proxy-agent是以其为基础的封装,可以直接和http模块对接. 不过在尝 ...

  9. 第二十四篇configparser(**)

    configparser模块 config:配置,parser:解析.字面意思理解configparser模块就是配置文件的解析模块. 来看一个好多软件的常见文档格式如下: [DEFAULT] # 标 ...

  10. result returns more than one elements此种错误,解决

    场景:公司产品开发完成后,接入第三方厂商,在进行接口联调的时候出现此问题.此接口报文中的每一个数据都要进行校验,有些是与已经存入产品数据库中的数据进行对比,看是否存在. 问题:在测试中,有些测试没有问 ...