zoukankan      html  css  js  c++  java
  • PHP使用CURL抓取网页

    CURL是一个非常强大的开源库,支持很多协议,包括HTTP、FTP、TELNET等,我们使用它来发送HTTP请求。它给我 们带来的好处是可以通过灵活的选项设置不同的HTTP协议参数,并且支持HTTPS。CURL可以根据URL前缀是“HTTP” 还是“HTTPS”自动选择是否加密发送内容。

    使用CURL的PHP扩展完成一个HTTP请求的发送一般有以下几个步骤:

        初始化连接句柄;
        设置CURL选项;
        执行并获取结果;
        释放CURL连接句柄。

    一、使用curl模拟GET请求

    $curl=curl_init();  //初始化curl句柄
    $url="http://www.conglinfeng.com/together/detail.php?show_ID=5";  //要请求的url地址
    curl_setopt($curl, CURLOPT_URL,$url);  //设置curl的参数,即要请求的url是$url
    curl_exec($curl);  //执行操作
    curl_close($curl);  //关闭句柄
    

     执行curl_exec()时,成功时会输出网页代码,并且返回值为 TRUE,在失败时返回 FALSE。 然而,如果 CURLOPT_RETURNTRANSFER选
    项被设置,函数执行成功时会返回执行的结果,失败时返回 FALSE 。

    二、使用curl模拟post请求

    $curl=curl_init();
    $url="./register.php";
    curl_setopt($curl, CURLOPT_URL,$url);
    curl_setopt($curl, CURLOPT_POST, true);  //设置请求为post
    $post_data=array('username'=>"嘿嘿",'password'=>'111111','confirm'=>'111111',
    	'email'=>"986992484@qq.com");   //要发送的数据组装成一个数组
    curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);  //post的数据内容
    curl_exec($curl); 
    curl_close($curl);
    

     register.php:

    var_dump($_POST);
    

     三、处理响应的数据

    curl_exec()执行时会直接把响应数据输出,如果不需要直接输出,可以加:curl_setopt($curl, CURLOPT_RETURNTRANSFER, true) ;

    $url="./register.php";
    curl_setopt($curl, CURLOPT_URL,$url);
    curl_setopt($curl, CURLOPT_POST, true);  //设置请求为post
    $post_data=array('username'=>"嘿嘿",'password'=>'111111','confirm'=>'111111',
    	'email'=>"986992484@qq.com");
    curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);  //post的数据内容
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true) ; //请求执行时,不将响应数据直接输出,而是以返回值的形式输出响应数据
    $res=curl_exec($curl); 
    echo $res;  //少了这句就输不出来了
    curl_close($curl);
    

     四、模拟post 文件上传

    $url="./register.php";
    curl_setopt($curl, CURLOPT_URL,$url);
    curl_setopt($curl, CURLOPT_POST, true);  //设置请求为post
    $post_data=array('logo'=>'@D:wampwampwwwczbkphp&mysql1.png'); // logo是$_FILES的name,后面的是图片路径,加@表示这是一个文件而不是字符串
    curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);  //post的数据内容
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true) ; //请求执行时,不将响应数据直接输出,而是以返回值的形式输出响应数据
    $res=curl_exec($curl); 
    echo $res; 
    curl_close($curl);
    

     五、输出响应头

    curl默认是不输出响应头的,如果要输出,则要加:curl_setopt($curl, CURLOPT_HEADER, true); 

    $url="http://www.conglinfeng.com/together/member/index.php";
    curl_setopt($curl, CURLOPT_URL,$url);
    curl_setopt($curl, CURLOPT_HEADER, true);  //将响应头输出,默认是不输出的
    //  HTTP/1.1 200 OK Date: Thu, 15 Sep 2016 14:49:28 GMT Server: Apache/2.4.4 (Win32) PHP/5.4.16 X-Powered-By: PHP/5.4.16 Content-Length: 692 Content-Type: text/html
    curl_exec($curl); 
    curl_close($curl);
    

     六、实例:CURL模拟登陆

    可以简单和有效地抓取网页并采集内容,设置cookie完成模拟登录网页,curl提供了丰富的函数,开发者可以从PHP手册中获取更多关于cURL信息。本文以模拟登录开源中国(oschina)为例,和大家分享cURL的使用。

    PHP的curl()在抓取网页的效率方面是比较高的,而且支持多线程,而file_get_contents()效率就要稍低些,当然,使用curl时需要开启下curl扩展。

    先来看登录部分的代码:

    //模拟登录 
    function login_post($url, $cookie, $post) { 
        $curl = curl_init();//初始化curl模块 
        curl_setopt($curl, CURLOPT_URL, $url);//登录提交的地址 
        curl_setopt($curl, CURLOPT_HEADER, 0);//是否显示头信息 
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 0);//是否自动显示返回的信息 
        curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie); //设置Cookie信息保存在指定的文件中 
        curl_setopt($curl, CURLOPT_POST, 1);//post方式提交 
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post));//要提交的信息 
        curl_exec($curl);//执行cURL 
        curl_close($curl);//关闭cURL资源,并且释放系统资源 
    } 
    

     函数login_post()首先初始化curl_init(),然后使用curl_setopt()设置相关选项信息,包括要提交的url地址,保存的cookie文件,post的数据(用户名和密码等信息),是否返回信息等等,然后curl_exec执行curl,最后curl_close()释放资源。注意PHP自带的http_build_query()可以将数组转换成相连接的字符串。

    接下来如果登录成功后,我们要获取登录成功后的页面信息。

    //登录成功后获取数据 
    function get_content($url, $cookie) { 
        $ch = curl_init(); 
        curl_setopt($ch, CURLOPT_URL, $url); 
        curl_setopt($ch, CURLOPT_HEADER, 0); 
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
        curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie); //读取cookie 
        $rs = curl_exec($ch); //执行cURL抓取页面内容 
        curl_close($ch); 
        return $rs; 
    } 
    

     函数get_content()中也是先初始化curl,然后设置相关选项,执行curl,释放资源。其中我们设置CURLOPT_RETURNTRANSFER为1即自动返回信息,而CURLOPT_COOKIEFILE可以读取到登录时保存的cookie信息,最后将页面内容返回。

    我们的最终目的是要获取到模拟登录后的信息,也就是只有正常登录成功后才能获取的有用信息。接下来我们以登录开源中国的移动版为例,看看如何抓取到登录成功后的信息。

    //设置post的数据 
    $post = array ( 
        'email' => 'oschina账户', 
        'pwd' => 'oschina密码', 
        'goto_page' => '/my', 
        'error_page' => '/login', 
        'save_login' => '1', 
        'submit' => '现在登录' 
    ); 
     
    //登录地址 
    $url = "http://m.oschina.net/action/user/login"; 
    //设置cookie保存路径 
    $cookie = dirname(__FILE__) . '/cookie_oschina.txt'; 
    //登录后要获取信息的地址 
    $url2 = "http://m.oschina.net/my"; 
    //模拟登录 
    login_post($url, $cookie, $post); 
    //获取登录页的信息 
    $content = get_content($url2, $cookie); 
    //删除cookie文件 
    @ unlink($cookie); 
    //匹配页面信息 
    $preg = "/<td class='portrait'>(.*)</td>/i"; 
    preg_match_all($preg, $content, $arr); 
    $str = $arr[1][0]; 
    //输出内容 
    echo $str; 
    

     七、封装CURL

    为了便于日后调用,我们可以把这些操作封装起来。

    1.模拟get或post请求

    /**
     * curl()   curl模拟请求---一个参数是get请求,两个参数是post请求
     *
     * 上传文件$post=array('logo'=>'@D:wampwampwwwczbkphp&mysql1.png'); 
     * logo是$_FILES的name,后面的是图片路径,加@表示这是一个文件而不是字符串
     *
     * @param string $url   模拟请求的url
     * @param array $post   post请求时要提交的数据
     * @param boolean $header  是否要将响应头输出
     * @return string $str   返回响应结果
     */
    function curl($url,$post=array(),$header=false){
      if(!$url)   return;
     
      //设置资源句柄
      $curl=curl_init();
      curl_setopt($curl, CURLOPT_URL,$url);
     
      //如果传$post,则说明是post请求
      if($post && is_array($post) && count($post)>0){
           curl_setopt($curl, CURLOPT_POST, 1);
           curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
           curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); //不验证证书
           curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); //不验证证书
      }
     
      //请求执行时,不将响应数据直接输出,而是以返回值的形式输出响应数据
      curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); 
     
      //决定要不要将响应头输出
      curl_setopt($curl, CURLOPT_HEADER,$header); 
      $str=curl_exec($curl); 
      
      //IGNORE 忽略转换时的错误,如果没有ignore参数,所有该字符后面的字符串都无法被保存。
      $str = iconv("UTF-8","GBK//IGNORE",$str);
      curl_close($curl);
     
      return $str;
    }
    

     2.模拟登陆

    /**
     * curl_login()   curl模拟登陆
     *
     * @param string $logUrl   登陆地址url
     * @param string $desUrl   要访问页面的url
     * @param array $post    要提交的数据
     * @param string $cookie=''  存储cookie的文件路径
     * @return string $str   返回响应结果
     */
    function curl_login($logUrl,$desUrl,$post,$cookie=''){
     /********模拟登陆**********/
        //初始化curl模块 
        $curl = curl_init();
        //登录提交的地址 
        curl_setopt($curl, CURLOPT_URL,$logUrl);
        //是否显示头信息
        curl_setopt($curl, CURLOPT_HEADER, 0); 
        //是否自动显示返回的信息 
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 0);
        //设置Cookie信息保存在指定的文件中 
        if(!$cookie)  $cookie=dirname(__FILE__) . '/cookie.txt';
        if(!file_exists($cookie))}{
          	$fp=fopen($cookie, 'w'); fclose($fp);
        }
        curl_setopt($curl, CURLOPT_COOKIEJAR, $cookie); 
        //post方式提交 
        curl_setopt($curl, CURLOPT_POST, 1);
        //提交信息,http_build_query()可以将数组转换成相连接的字符串。
        curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post)); 
        //执行cURL并关闭cURL资源,并且释放系统资源 
        curl_exec($curl);
        curl_close($curl);
     /********登陆后获取数据**********/
        $ch = curl_init(); 
        curl_setopt($ch, CURLOPT_URL, $desUrl); 
        curl_setopt($ch, CURLOPT_HEADER, 0); 
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 
        //读取cookie 
        curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie); 
        $rs = curl_exec($ch); //执行cURL抓取页面内容 
        curl_close($ch); 
        return $rs; 
    }
    

     也可以把curl的操作封装成一个类 Curl.class.php

    <?php
     
    /**
     *  CURL操作类,可用于模拟请求
     *  @author leshen <986992484@qq.com>
     *  @version 1.1
     *  usage:
     *	1.设置选项
     *  $options=array(
     *    'isReturn'=>true,   //将响应结果返回。如果不想获取源码而是想渲染页面,请设置为false
     *	  'isHeader'=>true,   //将响应头返回
     *   );
     *  $curl=new Curl($options);
     *  2.模拟一般的get请求
     *  $curl=new Curl();
     *  $url="https://www.baidu.com";
     *  var_dump($curl->curl_get($url));
     *  3.模拟需要盗链的get请求(查询四六级为例)
     *  $curl=new Curl();
     *  $url='http://www.chsi.com.cn/cet/query';
     *  $referer="http://www.chsi.com.cn/cet";
     *  $data=array('xm'=>'钟林生','zkzh'=>'360021161218718');
     *  $respn=$curl->curl_get_chain($url,$data,$referer);
     *  var_dump($respn);
     *  4.模拟post请求(查询四六级为例)
     *	 $data=array(
     *	 'name'=>'王勇平',
     *	 'province'=>'江西',
     *	 'school'=>'江西师范大学',
     *	 'type'=>'1'
     *	);
     *	$url='http://cet.zy62.com/query/2';
     *	$curl=new Curl();
     *	var_dump($curl->curl_post($url,$data));
     */
     
    class Curl{
     
    	/**
         * curl资源句柄
         * @var resource
         */
        private $curl;
     
        /*curl选项*/
        private $isReturn;   //是否将响应结果返回
        private $isHeader;   //是否将响应头返回
        private $timeout;    //超时时间
        private $userAgent;  //客户端代理
        private $verifyPeer; //是否终止cURL从服务端进行验证
        private $verifyHost; //检查服务器SSL证书中是否存在一个公用名
     
        /**
         * 构造方法,用于实例化一个curl对象
         */
        public function __construct($options=array()){
            /*初始化资源句柄*/
            $this->curl=curl_init();
            /*初始化curl选项*/
            $this->isReturn=isset($options['isReturn'])?$options['isReturn']:ture;
            $this->isHeader=isset($options['isHeader'])?$options['isHeader']:false;
            $this->timeout=isset($options['timeout'])?$options['timeout']:30;
            $this->userAgent=isset($options['userAgent'])?$options['timeout']:
               isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']: 
            'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0 FirePHP/0.7.4';
            $this->verifyPeer=isset($options['verifyPeer'])?$options['verifyPeer']:false;
            $this->verifyHost=isset($options['verifyHost'])?$options['verifyHost']:2;
        }   
     
    	/**
         * 设置curl选项
         * @param  string   $url  	请求的url
         * @param  boolean  $ssl 	是否以https协议传输
         * @return void 
         */	
        private function setOption($url,$ssl){
    		/*设置curl选项*/
    		curl_setopt($this->curl, CURLOPT_URL, $url);//URL
    		curl_setopt($this->curl, CURLOPT_USERAGENT, $this->userAgent);//userAgent,请求代理信息
    		curl_setopt($this->curl, CURLOPT_TIMEOUT, $this->timeout);//设置超时时间
     
    		/*SSL相关*/
    		if ($ssl) {
    			curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER,$this->verifyPeer);//禁用后cURL将终止从服务端进行验证
    			curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST,$this->verifyHost);//检查服务器SSL证书中是否存在一个公用名(common name)。
    		}
     
    	    /*响应结果*/
    		curl_setopt($this->curl, CURLOPT_HEADER, $this->isHeader);//是否返回响应头
    		curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, $this->isReturn);//curl_exec()是否返回响应结果
        }
     
    	/**
         * 执行curl请求
         * @return string  返回响应内容
         */	
        private function exec(){
    		/*发出请求*/
    		$response = curl_exec($this->curl);
    		if (false === $response) {
    			echo '<br>', curl_error($this->curl), '<br>';
    			return false;
    		}
    		curl_close($this->curl);
    		return $response;
        }
     
    	/**
         * curl模拟post请求,返回响应的内容
         * @param  string   $url  		请求的url
         * @param  array    $data  		发送的数据,数组
         * @param  boolean  $ssl 		是否以https协议传输,默认为true
         * @return string   $response  	返回响应的内容
         */	
    	public function curl_post($url, $data, $ssl=true) {
    		/*设置选项*/
    		$this->setOption($url,$ssl);
     
    		/*处理post相关选项*/
    		curl_setopt($this->curl, CURLOPT_POST, true);// 是否为POST请求
    		curl_setopt($this->curl, CURLOPT_POSTFIELDS, $data);// 设置post的内容
     
    		/*执行curl请求*/
    		if($this->isReturn){
    			return $this->exec();
    		}
    		$this->exec();
    	}
     
    	/**
         * curl模拟一般的get请求,返回响应的内容
         * @param  string   $url  		请求的url,可以带查询参数
         * @param  boolean  $ssl 		是否以https协议传输,默认为true
         * @return string   $response  	返回响应的内容
         */	
    	public function curl_get($url,$ssl=true) {
    		/*设置选项*/
    		$this->setOption($url,$ssl);
     
    		/*执行curl请求*/
    		if($this->isReturn){
    			return $this->exec();
    		}
    		$this->exec();
    	}	
     
    	/**
         * curl模拟需要盗链的get请求,返回响应的内容
         * @param  string   $url  		请求的url
         * @param  array    $data  		查询参数,数组形式,方法内会自动转换为字符串形式
         * @param  string   $referer 	盗链的url
         * @param  boolean  $ssl 		是否以https协议传输,默认为true
         * @return string   $response  	返回响应的内容
         */	
    	public function curl_get_chain($url,$data,$referer,$ssl=true){
    		/*设置选项*/
    		$this->setOption($url,$ssl);
    		$param='';
    		foreach ($data as $k => $v) {
    			$param.= urlencode($k).'='.urlencode($v).'&';
    		}
    		/*设置查询参数*/
        	curl_setopt($this->curl, CURLOPT_POST, 0);
      	    curl_setopt($this->curl, CURLOPT_POSTFIELDS, $param);
     
    		/*设置referer盗链*/
    		curl_setopt($this->curl, CURLOPT_REFERER, $referer);
     
      	    /*执行curl请求*/
    		if($this->isReturn){
    			return $this->exec();
    		}
    		$this->exec();
    	}
    }
    
  • 相关阅读:
    Reactivecocoa初级使用
    javascript中typeof用法
    javascript进阶修炼之二——DOM,事件及定时器
    javascript进阶修炼之一——javascript必备操做
    HttpClient通信
    JSON和JSONP简单总结
    cordova学习-基础篇
    浅析Java虚拟机结构与机制
    HTML5移动Web开发指南-学习笔记(一)
    spring beans 源码解读
  • 原文地址:https://www.cnblogs.com/xwyphp/p/9808919.html
Copyright © 2011-2022 走看看