请选择 进入手机版 | 继续访问电脑版

SpeedPHP框架

 找回密码
 注册成为新用户

QQ登录

只需一步,快速开始

查看: 13074|回复: 12

分享一个强大的HTTP访问类(可做采集)

[复制链接]
发表于 2011-4-2 00:01:25 | 显示全部楼层 |阅读模式
做采集的时候,可以使用file_get_contents()去获取网页源代码,但是使用file_get_contents采集,速度慢,而且超时时间,不好控制。如果采集的页面不存在,需要等待的时间很长。一般来说,curl的速度最快,其次是socket,最后是file_get_contents。
现在跟大家分享一个很强大的采集类,会根据你的服务器当前的配置,自动选择最快的方式。已经封装了curl和socket,file_get_contents

用法很简单:
1,采用get方法请求
Http::doGet(网址);//超市时间可忽略,默认是5秒
Http::doGet(网址,超时时间);
如echo Http::doGet('http://www.baidu.com');

2,采用post方法请求
Http::doPost(网址,数据,超时时间);


$url='http://www.canphp.com/test.php';
$data['name']='单骑';
$data['email']='admin@canphp.com';
Http::doPost($url,$data,10);

test.php页面接收数据
$_POST['name'];
$_POST['email'];

这个http类不仅可以用来采集,还有一个很强大的作用,模拟php异步多进程。
比如有index.php和a.php,  b.php,  c.php
在index.php中
Http::doGet('http://www.canphp.com/a.php',1);
Http::doGet('http://www.canphp.com/b.php',1);
Http::doGet('http://www.canphp.com/c.php',1);

a.php,  b.php,  c.php程序分别在头部加上ignore_user_abort(true);
那么就可以实现多进程了。

原理:
通过curl或socket发送请求给a.php,  b.php,  c.php,由于超时时间比较短,只是触发了a.php,  b.php,  c.php三个页面,不需要等待数据返回,连接已中断,但是a.php,  b.php,  c.php程序中加上了ignore_user_abort(true);忽略客户端连接,还会继续执行。

具体案例可以观看很邪恶很强大的av程序(http://www.canphp.com/bbs/thread-295-1-1.html)
  1. <?php
  2. //数据采集,doGET,doPOST
  3. class Http
  4. {//类定义开始
  5. //通过get方式获取数据
  6. static public function doGet($url,$timeout=5)
  7. {
  8. $code=self::getSupport();
  9. switch($code)
  10. {
  11. case 1:return self::curl($url,'',$timeout);break;
  12. case 2:return self::socketGet($url,$timeout);break;
  13. case 3:return @file_get_contents($url);break;
  14. default:return false;
  15. }
  16. }
  17. //通过POST方式发送数据
  18. static public function doPost($url,$data,$timeout=5)
  19. {
  20. $code=self::getSupport();
  21. switch($code)
  22. {
  23. case 1:return self::curl($url,$data,$timeout);break;
  24. case 2:return self::socketPost($url,$data,$timeout);break;
  25. default:return false;
  26. }
  27. }

  28. //获取支持读取远程文件的方式
  29. static public function getSupport()
  30. {
  31. if(function_exists('curl_init'))//curl方式
  32. {
  33. return 1;
  34. }
  35. else if(function_exists('fsockopen'))//socket
  36. {
  37. return 2;
  38. }
  39. else if(function_exists('file_get_contents'))//php系统函数file_get_contents
  40. {
  41. return 3;
  42. }
  43. else if(ini_get('allow_url_fopen')&&function_exists('fopen'))//php系统函数fopen
  44. {
  45. return 4;
  46. }
  47. else
  48. {
  49. return 0;
  50. }
  51. }
  52. static public function GetHttpContent($fsock=null) {
  53. $out = null;
  54. while($buff = @fgets($fsock, 2048)){
  55. $out .= $buff;
  56. }
  57. fclose($fsock);
  58. $pos = strpos($out, "\r\n\r\n");
  59. $head = substr($out, 0, $pos); //http head
  60. $status = substr($head, 0, strpos($head, "\r\n")); //http status line
  61. $body = substr($out, $pos + 4, strlen($out) - ($pos + 4));//page body
  62. if(preg_match("/^HTTP\/\d\.\d\s([\d]+)\s.*$/", $status, $matches)){
  63. if(intval($matches[1]) / 100 == 2){
  64. return $body;
  65. }else{
  66. return false;
  67. }
  68. }else{
  69. return false;
  70. }
  71. }
  72. static public function socketGet($url,$timeout=5){
  73. $url2 = parse_url($url);
  74. $url2["path"] = isset($url2["path"])? $url2["path"]: "/" ;
  75. $url2["port"] = isset($url2["port"])? $url2["port"] : 80;
  76. $url2["query"] = isset($url2["query"])? "?".$url2["query"] : "";
  77. $host_ip = @gethostbyname($url2["host"]);
  78. $fsock_timeout = $timeout; //超时时间
  79. if(($fsock = fsockopen($host_ip, $url2['port'], $errno, $errstr, $fsock_timeout)) < 0){
  80. return false;
  81. }
  82. $request = $url2["path"] .$url2["query"];
  83. $in = "GET " . $request . " HTTP/1.1\r\n";
  84. $in .= "Accept: */*\r\n";
  85. // $in .= "User-Agent: Payb-Agent\r\n";
  86. $in .= "Host: " . $url2["host"] . "\r\n";
  87. $in .= "Connection: Close\r\n\r\n";
  88. if(!@fwrite($fsock, $in, strlen($in))){
  89. @fclose($fsock);
  90. return false;
  91. }
  92. return self::GetHttpContent($fsock);
  93. }

  94. static public function socketPost($url,$post_data=array(),$timeout=5){
  95. $url2 = parse_url($url);
  96. $url2["path"] = ($url2["path"] == "" ? "/" : $url2["path"]);
  97. $url2["port"] = ($url2["port"] == "" ? 80 : $url2["port"]);
  98. $host_ip = @gethostbyname($url2["host"]);
  99. $fsock_timeout = $timeout; //超时时间
  100. if(($fsock = fsockopen($host_ip, $url2['port'], $errno, $errstr, $fsock_timeout)) < 0){
  101. return false;
  102. }
  103. $request = $url2["path"].($url2["query"] ? "?" . $url2["query"] : "");
  104. $post_data2 = http_build_query($post_data);
  105. $in = "POST " . $request . " HTTP/1.1\r\n";
  106. $in .= "Accept: */*\r\n";
  107. $in .= "Host: " . $url2["host"] . "\r\n";
  108. // $in .= "User-Agent: Lowell-Agent\r\n";
  109. $in .= "Content-type: application/x-www-form-urlencoded\r\n";
  110. $in .= "Content-Length: " . strlen($post_data2) . "\r\n";
  111. $in .= "Connection: Close\r\n\r\n";
  112. $in .= $post_data2 . "\r\n\r\n";
  113. unset($post_data2);
  114. if(!@fwrite($fsock, $in, strlen($in))){
  115. @fclose($fsock);
  116. return false;
  117. }
  118. return self::GetHttpContent($fsock);
  119. }

  120. static public function curl($url, $data=array(), $timeout=5)
  121. {
  122. $ch = curl_init();
  123. if (is_array($data) && $data)
  124. {
  125. $formdata = http_build_query($data);
  126. curl_setopt($ch, CURLOPT_POST, true);
  127. curl_setopt($ch, CURLOPT_POSTFIELDS, $formdata);
  128. }
  129. curl_setopt($ch, CURLOPT_URL, $url);
  130. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  131. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  132. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  133. $result = curl_exec($ch);
  134. curl_close($ch);
  135. return $result;
  136. }

  137. }//类定义结束
  138. ?>
复制代码
Http.class.zip (3.92 KB, 下载次数: 143)
头像被屏蔽
发表于 2011-4-2 00:08:38 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
发表于 2011-4-2 00:40:46 | 显示全部楼层
谢谢分享
发表于 2011-4-2 08:50:30 | 显示全部楼层
回复 1# 单骑闯天下

谢谢分享



   不过提议一下:这个只能说是HTTP访问类,不好直接说成采集类。采集涉及更多的应该是规则,帖子标题最好改一下——HTTP访问类。这是为了方便网友寻找和使用。


另外,补充一下,file_get_contents也可以通过stream_context_create来定义超时等方面的设置。
 楼主| 发表于 2011-4-2 09:16:22 | 显示全部楼层
谢谢你的提议,标题我修改一下,
file_get_contents也可以通过stream_context_create来定义超时等方面的设置,这个是可以设置,但是对php版本有要求,而且会经常不起作用。设定10秒超时,程序还是运行到30秒,超时退出。

file_get_contents延时可以用resource $context的timeout参数:
  $opts = array(
    'http'=>array(
    'method'=>"GET",
    'timeout'=>60,
  )
);
//创建数据流上下文
$context = stream_context_create($opts);

$html =file_get_contents('http://www.canphp.com/test.php', false, $context);
 楼主| 发表于 2011-4-2 09:58:04 | 显示全部楼层
附件中的http.class.php还带了下载方法download
用法Http::download('文件路径','显示的文件名');
注意:显示的文件名,需要自行转成gb编码,如果文件名带有空格的,用其他字符替换一下。
发表于 2011-4-2 10:17:05 | 显示全部楼层


本贴将转移到扩展认证区,感谢单骑兄的分享
发表于 2011-4-9 17:57:30 | 显示全部楼层
其实Snoopy的HTTP访问累页不错
发表于 2011-4-12 11:34:31 | 显示全部楼层
很强大,谢谢分享!
头像被屏蔽
发表于 2011-5-5 06:41:31 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
您需要登录后才可以回帖 登录 | 注册成为新用户

本版积分规则

手机浏览|简版|中文PHP框架|开源协议|SpeedPHP.com ( 粤ICP备08008671号

GMT+8, 2019-11-19 23:03

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表