PHP Socket编程 之 抓取数据遇到Transfer-Encoding chunked

今天在干坏事抓取别人页面时候遇到一个问题,平时我们在post数据后,大不了要求提交cookie,但是今天这个测试了N遍不需要coookie都行的,但是抓取到的始终是乱码,怎么解析都不行。于是自己又把cookie和一大堆header给加上,还是同样的问题,于是开始郁闷了。PHP脚本不行,但是同样的提交浏览器上面就行,这个是怎么回事呢?
于是开始分析能看到的数据,终于看到一个特别的地方,我们平时请求数据的时候都会在header里面看到一个

Coontent-Length: xxxx

这个是表示这次发送的数据的长度,说明是一个完整的http数据的发送,但是今天看到的这个却没有这一项,出现的却是

Transfer-Encoding	chunked

于是开始郁闷了,这个到底是啥意思。谷歌了一番终于懂了,也找到对策了。
维基百科上面是这样解释的:

分块传输编码(Chunked transfer encoding)是超文本传输协议(HTTP)中的一种服务器可以发送数据而不需要预先知道发送内容的总大小。通常数据块的大小是一致的,但也不总是这种情况。

终于知道这个是啥了,那边把数据给分段了,怪不得数据一直有问题,于是网上到处找解决办法,终于找到一个很巧妙的方法:使用HTTP 1.0协议,服务器会主动放弃chunked编码,所以在curl里面加个

curl_setopt($curl, CURLOPT_HTTP_VERSION, '1.0');

问题就解决了,就是这么简单


但是,fsockopen呢?

fsockopen获取到的返回头是Content-Encoding: gzip乱码
如果把Accept-Encoding: gzip, deflate改为Accept-Encoding: deflate可以
但是我想直接把gzip解压缩成正常代码

主要是两个问题

#1.返回头Transfer-Encoding: chunked表明是chunked的传输编码,这个意思是,服务器分批把http body返回给你
  比如http body如下 
  2   --表示下一个chunked的长度为2,这个数字是16进制,不是10进制
  ab --  长度为2的串
  3  -- 同上
  abc -- 长度为3的串
  1    -- 同上
  a     -- 长度为1的串
  0  -- 长度为0,这个是结束标识
  所以最终的http body应该是ababca ,长度标识是不需要的。

#2.经过deflate的http body需要忽略前10个字符.

header("content-type:text/html;charset=utf-8");
$host="www.renren.com";
$request="GET / HTTP/1.1
"
        ."Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, */*
"
        ."Accept-Language: zh-cn
"
        ."User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)
"
        ."Accept-Encoding: gzip, deflate
"
        ."Host: www.renren.com
"
        ."Connection:close
"
        ."Cookie: _r01_=1; depovince=GW

";
 
$fp=fsockopen($host,80);
fputs($fp,$request);
$result="";
while(!feof($fp)){
    $result.=fgets($fp,1024);
}
fclose($fp);
$hb         = explode("

",$result);//分隔http head和body
$body        = $hb[1]; //http body
$chunk        = strtok($body,"
");//获取第一个chunked string的16进制串长标识
while( $len = (hexdec($chunk) + 0) ) //最后一个chunked string的串长铁定是0,这是协议规范
{
    $start   = strlen($chunk) + 2;//从chunked标识后读取串, +2是因为还要考虑"
"
    $bd      .= substr($body , $start , $len );//读取真正要decode的http body
    $body      = substr($body , $start + $len + 2); //body把上一个chunked去掉
    $chunk   = strtok($body,"
");//查找下一个chunked长度标识
}
echo gzinflate(substr($bd,10));//忽略前10个字符

当然:发送请求时不发送支持解码信息,这样服务器一般不Response压缩数据。明确告知服务器我不支持压缩,结果服务器就乖乖地不压缩了^_^。屡试不爽。

相在链接:

  https://www.cnblogs.com/zjzhuwenbo/p/4874305.html

  https://bbs.****.net/topics/360000732