PHP cURL实现模拟登录与采集使用方法详解教程

 本文将通过案例,整合浏览器工具与PHP程序,教你如何让数据 唾手可得 

对于做过数据采集的人来说,cURL一定不会陌生。虽然在PHP中有file_get_contents函数可以获取远程链接的数据,但是它的可控制性太差了,对于各种复杂情况的采集情景,file_get_contents显得有点无能为力。因此,本文将为你介绍采集神器cURL的使用。

 

  • Firebug

    1. 箭头图标是“元素选择”工具,单击一次会高亮图标,同时,鼠标在页面内的移动会同时在HTML菜单中选定相应的内容,此时单击内容则表示选定了该元素,图标高亮取消。如图(二)所示: 
      Firebug查看元素

    2. 控制台 
      JS里面的console.log系列函数的打印就是在这里输出。

    3. HTML 
      HTML内容,注意这里看到的不一定是采集要解析的内容,采集时候对内容的分析,一律以查看源码(Ctrl+U)为准,这里只是能快速定位元素的结构,然后再选择一个比较特殊的参照,在源码中定位相应的位置。 
      比如,你在HTML里面看到一个标签是<div id="demo" class="demo">Demo</div>,但是你查看源码时候看到的内容可能是<div class="demo" id="demo">Demo</div>,如果你对采集内容按照前者去做正则匹配,那么你会得不到结果。
    4. CSS 
      这里是CSS文件内容
    5. 脚本 
      这里是Javascript文件内容
    6. DOM 
      Dom节点内容
    7. 网络 
      每一个请求链接的数据,这里是我们采集要关注和分析的地方,它能够显示每一个请求的参数、请求头、Cookie数据等。在页面提交会刷新的情况下,需要使用保持,使得页面请求内容在刷新后仍然留着控制台中,如图(三)所示: 
      Firebug网络保持
      另外,火狐还有一款 Tamper data 扩展也能得到请求数据,必要时可以安装使用。
    8. Cookies 
      Cookie数据

    图(一)中还看到下面有很多可选的小菜单项,其中保持是我们要关注的,当选择它的时候,即使提交表单刷新了页面,下面内容区域的数据还是会保留,这个对于分析提交数据特别关键。

     

    总结

    我们在分析采集请求的时候,主要关心“网络”菜单里的请求数据,必要时候使用“保持”以查看刷新页面的请求数据,请求前可以使用“清除”先清除下面的内容。

     

    案例解析

     

    一、简单的采集

    这里所指的简单采集,是指一个单一页面GET请求的采集,它简单得即使通过file_get_contents函数也能轻松获得页面返回结果。


    • 代码片段之file_get_contents
     
    1. <?php
    2. $url = 'upload/201704101114577826.jpg" class="popupImg" style="color: rgb(0, 136, 204); text-decoration: none;">cURL POST 参数分析

      然后下面是我们的代码:

       
      1. <?php
      2. $keyword = 'PHP cURL';
      3. //参数方法一
      4. // $post = 'wd=' . urlencode($keyword);
      5.  
      6. //参数方法二
      7. $post = array(
      8. 'wd' => urlencode($keyword),
      9. );
      10. $url = 'upload/201704101115013055.jpg" class="popupImg" style="color: rgb(0, 136, 204); text-decoration: none;">cURL 乱码 解决
        还好最后功夫不负有心人,还是找到了,它就是CURLOPT_ENCODING参数。 
        比如,采集搜狐的新闻时候就遇到gzip压缩问题,下面是示例:

         
        1. <?php
        2. $url = 'upload/201704101115053346.png" class="popupImg" style="color: rgb(0, 136, 204); text-decoration: none;">curl 302跳转

          这个时候,可以使用:

           
          1. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);

          关于CURLOPT_FOLLOWLOCATION,手册说明是:

          启用时会将服务器服务器返回的"Location: "放在header中递归的返回给服务器,使用CURLOPT_MAXREDIRS可以限定递归返回的数量。 

          我个人理解,通俗点讲就是后面的跳转会继续跟踪访问,而且cookie在header里面被保留了下来。

           

          十、模拟上传文件

          (一)基于本地文件上传

          在PHP手册的curl_setopt函数中,关于CURLOPT_POSTFIELDS有如下描述:

           
          1. 全部数据使用HTTP协议中的"POST"操作来发送。要发送文件,在文件名前面加上@前缀并使用完整路径。这个参数可以通过urlencoded后的字符串类似'para1=val1&para2=val2&...'或使用一个以字段名为键值,字段数据为值的数组。如果value是一个数组,Content-Type头将会被设置成multipart/form-data

          对于上传文件,这句话包含两个信息: 
          1. 要上传文件,post的数据参数必须使用数组,使得Content-Type头将会被设置成multipart/form-data。 
          2. 要上传文件,在文件名前面加上@前缀并使用完整路径。 
          注意:PHP 5.5.0起,文件上传建议使用CURLFile代替@

          因此,模拟文件上传可以按照如下实现:

           
          (1)单文件上传
           
          1. //上传D盘下的test.jpg文件,文件必须存在,否则curl处理失败且没有任何提示,Windows下中文文件名上传失败时,可使用iconv('UTF-8', 'GBK//IGNORE', $filename)转码下文件名再上传。
          2. $data = array('name' => 'Foo', 'file' => '@d:/test.jpg');
          3. 注: PHP 5.5.0起,文件上传建议使用CURLFile代替@
          4.  
          5. $ch = curl_init('upload/201704101115067834.png" class="popupImg" style="color: rgb(0, 136, 204); text-decoration: none;">ajax发送json的控制台信息
            第一条发送的是json格式的数据, 
            第二条发送的是以\n分割的数据, 
            第三条发送的是以&分割的数据。 
            这个在ajax请求的时候,只需要添加contentType参数即可,如:

             
            1. var data = ["name:Zjmainstay", "website:http://www.zjmainstay.cn"];
            2. $.ajax({
            3. url: 'http://test.com/curl/testPostJsonData.php',
            4. type: 'post',
            5. data: data.join("\n"),
            6. contentType: 'text/plain',
            7. success: function(result) {
            8. console.log(result);
            9. },
            10. error: function(msg) {
            11. console.log(msg);
            12. }
            13. });

            对于这类发送json数据的请求,复制cURL命令时,你会发现其中根本没有发送数据,如:

             
            1. curl 'http://test.com/curl/testPostJsonData.php' -X POST -H 'Accept: */*' -H 'Accept-Encoding: gzip, deflate' -H 'Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3' -H 'Cache-Control: max-age=0' -H 'Connection: keep-alive' -H 'Content-Length: 48' -H 'Content-Type: text/plain' -H 'Cookie: __utma=99889051.942646074.1467634856.1467634856.1467636947.2' -H 'Host: test.com' -H 'Referer: http://test.com/curl/ajaxJsonData.html' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:47.0) Gecko/20100101 Firefox/47.0' -H 'X-Requested-With: XMLHttpRequest'

            对于这种数据,我们要用PHP cURL模拟发送的话,需要发送相应的header参数,示例:

             
            1. <?php
            2. #json数据
            3. $url = 'http://test.com/curl/testPostJsonData.php';
            4. $data = '{"a":"b"}';
            5. $length = strlen($data);
            6. $header = array(
            7. 'Content-Length: ' . $length, //不是必需的
            8. 'Content-Type: text/json',
            9. );
            10. $ch = curl_init($url); //初始化curl
            11. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            12. curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
            13. curl_setopt($ch, CURLOPT_POST, 1);
            14. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            15. $content = curl_exec($ch); //执行并存储结果
            16. curl_close($ch);
            17. echo $content;
            18.  
            19. #\n分割数据
            20. $data = [
            21. 'name:Zjmainstay',
            22. 'website:http://www.zjmainstay.cn',
            23. ];
            24. $data = implode("\n", $data);
            25.  
            26. #&分割数据
            27. $data = 'name:Zjmainstay&website:http://www.zjmainstay.cn';

            对于$.ajax我们常常会使用这种写法来指定返回json格式数据:

             
            1. $.ajax({
            2. url: url,
            3. dataType: 'json',
            4. ...
            5. });

            我们会发现,cURL请求头Accept:部分会多出一些参数:

             
            1. -H 'Accept: application/json, text/javascript, */*; q=0.01'

            因此,如果需要指定返回内容作为json格式,我们就需要指定application/json格式。

            那么,对于这种给服务器端发送json数据的程序,服务器端是怎么得到请求数据的呢? 
            如果你们做过尝试,一定会发现此时$_POST是空的,我们要使用php://input进行数据获取,示例:

             
            1. $postData = file_get_contents('php://input');
             

            十二、POST提交大数据(超过1024字节)异常解决方法

            在使用cURL做POST的时候,当要POST的数据大于1024字节的时候,cURL并不会直接就发起POST请求, 而是会分为俩步:

             
            1. 1. 发送一个请求, 包含一个Expect:100-continue, 询问Server是否愿意接受数据
            2. 2. 接收到Server返回的100-continue应答以后, 才把数据POSTServer

            解决:

             
            1. curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
             

            总结

            通用curl页面采集函数:PHP通用curl页面采集函数

            简易解析cURL命令得到PHP代码程序:简易解析cURL命令得到PHP代码程序

            PHP cURL是一个很强大的采集工具,curl_setopt里面还有很多参数,读者可以抽空整体看一遍,虽然平时未必用得上,但是至少做到心里有底,知道都有哪些参数,必要时还能找出来使用。 
            采集是一项大工程,使用过程中遇到的问题还会不少,但是只要学会分析和资料搜索,一切都会迎刃而解的,大家加油!哈哈~~


            原文地址:PHP cURL实现模拟登录与采集使用方法详解教程,首发自 Zjmainstay学习笔记