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由网页服务器发送给客户端应用( 通常是网页浏览器)的数据可以分成多个部分。分块传输编码只在HTTP协议1.1版本(HTTP/1.1)中提供。
通常,HTTP应答消息中发送的数据是整个发送的,Content-Length消息头字段表示数据的长度。数据的长度很重要,因为客户端需要知道哪里是应答消息的结束,以及后续应答消息的开始。然而,使用分块传输编码,数据分解成一系列数据块,并以一个或多个块发送,这样服务器可以发送数据而不需要预先知道发送内容的总大小。通常数据块的大小是一致的,但也不总是这种情况。
终于知道这个是啥了,那边把数据给分段了,怪不得数据一直有问题,于是网上到处找解决办法,终于找到一个很巧妙的方法:使用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个字符.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | header( "content-type:text/html;charset=utf-8" ); $host = "www.renren.com" ; $request = "GET / HTTP/1.1\r\n" . "Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, */*\r\n" . "Accept-Language: zh-cn\r\n" . "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)\r\n" . "Accept-Encoding: gzip, deflate\r\n" . "Host: www.renren.com\r\n" . "Connection:close\r\n" . "Cookie: _r01_=1; depovince=GW\r\n\r\n" ; $fp = fsockopen ( $host ,80); fputs ( $fp , $request ); $result = "" ; while (! feof ( $fp )){ $result .= fgets ( $fp ,1024); } fclose( $fp ); $hb = explode ( "\r\n\r\n" , $result ); //分隔http head和body $body = $hb [1]; //http body $chunk = strtok ( $body , "\r\n" ); //获取第一个chunked string的16进制串长标识 while ( $len = (hexdec( $chunk ) + 0) ) //最后一个chunked string的串长铁定是0,这是协议规范 { $start = strlen ( $chunk ) + 2; //从chunked标识后读取串, +2是因为还要考虑"\r\n" $bd .= substr ( $body , $start , $len ); //读取真正要decode的http body $body = substr ( $body , $start + $len + 2); //body把上一个chunked去掉 $chunk = strtok ( $body , "\r\n" ); //查找下一个chunked长度标识 } echo gzinflate( substr ( $bd ,10)); //忽略前10个字符 |
当然:发送请求时不发送支持解码信息,这样服务器一般不Response压缩数据。明确告知服务器我不支持压缩,结果服务器就乖乖地不压缩了^_^。屡试不爽。
相在链接:
https://www.cnblogs.com/zjzhuwenbo/p/4874305.html
https://bbs.csdn.net/topics/360000732
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具