如何使用curl解码“Content-Encoding: gzip, gzip”?

10

我正在尝试使用以下代码通过CURL解码网页www.dealstan.com:

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); // Define target site
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // Return page in string
curl_setopt($cr, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.3 Safari/533.2');
curl_setopt($ch, CURLOPT_ENCODING , "gzip");     
curl_setopt($ch, CURLOPT_TIMEOUT,5); 
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); // Follow redirects

$return = curl_exec($ch); 
$info = curl_getinfo($ch); 
curl_close($ch); 

$html = str_get_html("$return");
echo $html;

但是,它显示了一些垃圾字符。

大约100行的内容是:"��}{w�6����9�X�n���.........."

我尝试在 hurl.it 中寻找响应信息,发现了一个有趣的点,看起来像是 html 被编码两次(根据响应猜测)

以下是响应结果:

GET http://www.dealstan.com/

200 OK 18.87 kB 490 ms View Request View Response HEADERS

Cache-Control: max-age=0, no-cache

Cf-Ray: 18be7f54f8d80f1b-IAD

Connection: keep-alive

Content-Encoding: gzip, gzip ==============>? 怀疑这个,有人知道吗?

Content-Type: text/html; charset=UTF-8

Date: Wed, 19 Nov 2014 18:33:39 GMT

Server: cloudflare-nginx

Set-Cookie: __cfduid=d1cff1e3134c5f32d2bddc10207bae0681416422019; expires=Thu, 19-Nov-15 18:33:39 GMT; path=/; domain=.dealstan.com; HttpOnly

Transfer-Encoding: chunked

Vary: Accept-Encoding

X-Page-Speed: 1.8.31.2-3973

X-Pingback: http://www.dealstan.com/xmlrpc.php

X-Powered-By: HHVM/3.2.0 BODY view raw

H4sIAAAAAAAAA5V8Q5AoWrBk27Ztu/u2bdu2bdu2bdu2bds2583f/pjFVOQqozZnUxkVJ7PwoyAA/qeAb3y83LbYHs/3Hv79wKm/2N5cZyJVtCWu1xyteyzLNqYuWbdtHeELCyIZRRp/1Fe7es3+wL3Vfb

有人知道如何解码带有头部"Content-Encoding: gzip, gzip"的响应吗?

该网站在 Firefox、Chrome 等浏览器中可以正常加载,但是我无法使用 CURL 解码。

请帮忙解决这个问题。


在谷歌上发现了一个错误,该错误在 Mozilla 上报告了类似的问题,https://bugzilla.mozilla.org/show_bug.cgi?id=205156,但我找不到任何修补程序来解决该错误,由于该网站在 Firefox 中正常加载,他们应该已经解决了这个问题。 - stackguy
奇怪,垃圾内容正好返回了——在Safari中也是这样显示的。因此,它基本上是将页面gzipped返回,尽管它声称Content-Type为text/html。(它就是要看起来像那样吗?对我来说,他们的网站就是坏了。如果我在Safari中浏览,它会显示预期的GZIP数据的文本表示形式...)注意:它似乎在传输中进行gzipping,而且还发送了一个压缩过的页面版本,所以我需要解压两次才能看到实际的HTML。 - Matt Gibson
刚刚检查了几个其他浏览器——Firefox和Chrome成功地显示了网页;Opera和Safari则显示了原始的gzip数据。因此,我会说这个网站配置错误,正在对页面进行两次gzip压缩,但某些Web浏览器检测到了这种错误,并为您解码了两次。我不确定我是否应该总是依赖它出现这种故障,因为迟早他们会意识到他们的网站在一些主要浏览器中存在问题,并修复配置... - Matt Gibson
正如您所说,他们已经解决了这个问题,现在我可以顺利地解析它了。不管怎样,如果我们知道 Firefox 如何正确处理它,那么这将有助于我们未来解决类似的问题。 - stackguy
1个回答

8

您可以通过删除头部并使用gzinflate进行解码。

$url = "http://www.dealstan.com"

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); // Define target site
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // Return page in string
curl_setopt($cr, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.3 Safari/533.2');
curl_setopt($ch, CURLOPT_ENCODING, "gzip");     
curl_setopt($ch, CURLOPT_TIMEOUT, 5); 
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); // Follow redirects

$return = curl_exec($ch); 
$info = curl_getinfo($ch); 
curl_close($ch); 

$return = gzinflate(substr($return, 10));
print_r($return);

2
是的,我认为这是正确的方法。这种方法实际上会将内容解压缩两次,因为Curl会解压缩一次,然后您需要手动再次解压缩。但是在手动解压缩之前,您可能需要检查响应(如果仍然是gzipped,则响应中的前两个字节将是1f 8b),因为在某个时候,这个网站肯定会收到来自Safari、Opera等用户的投诉,并修复导致双重编码内容的配置问题... - Matt Gibson
我修改了答案以适应我测试的实际代码段(我没有str_get_html)。print_r($return)是否正确?另请参见https://dev59.com/qnVC5IYBdhLWcg3wYQEp#4841712,其中包含更多功能的函数。 - Nalin Singapuri

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接