PHP CURL模拟带图片验证码登录并获取数据操作

在PHP手册上对curl的选项配置说明已经很清楚了。  里面有几个知识点我自己亲手写了以后做个笔记。

一个是cookie的存取, 一般我们知道一般网站记录用户是否登录有2种方法, 一个是用户验证后把登录状态存储到服务器端, 一个是存到客户端, 客户端也就意味着cookie的使用, 而且大多情况下程序员对记录密码的功能都会利用cookie做简单的判断, 所以只要能伪造或者获取到登录后的cookie信息, 就差不多可以做一些像灌水机之类的小程序, 或者对网站的爬虫盗窃……  但是有一个登录图片验证码的话, 会麻烦很多, 如果没有强大的实力做图像文字识别的话, 也就只能做手动输入了, 因为通常情况下验证码文字会存在服务端不作为参数返回。 所以咧, CURLOPT_COOKIEFILE和CURLOPT_COOKIEJAR  这2个选项要配置来获取和存COOKIE信息。

第二个是CURLOPT_RETURNTRANSFER选项, 刚开始使用也是很模糊。  不过在注释掉前后比较很容易搞懂, 如果这个选项开启, 就会把对应服务器返回的数据(通常是HTML代码)作为数据流返回, 这时候可用来做赋值或者其他操作, 如果不开启的话就会把数据作为标准输出输出到浏览器中看到显示效果。当然,这个选项可以通过ob_start()打开缓冲区,然后用ob_get_contents()来获取数据达到同样的效果。

第三个是关于CURL并发处理函数的使用, 即 curl_multi_init  ,  culr_multi_add_handle  , curl_multi_getcontent  , curl_multi_remove_handle ,  curl_multi_close几个函数的使用顺序 ,  几个函数在我写的DEMO中可以大概明白使用方法了。

下面是我写的一个DEMO,登录豆瓣,获取豆瓣好友列表的小例子, 这个应该和获取邮箱列表一样的道理, 有些邮箱不需要验证码就会好做很多。  获取好友列表基本上都是正则匹配出来的。

<?php
class douban
{
    var $cookieFile = '/var/www/douban/cookie.tmp';
    var $loginUrl = 'https://www.douban.com/accounts/login';
    var $header = array(
            'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Charset' => 'GBK,utf-8;q=0.7,*;q=0.3',
            'Accept-Encoding' => 'gzip,deflate,sdch',
            'Accept-Language' => 'zh-CN,zh;q=0.8',
            'Cache-Control' => 'max-age=0',
            'Connection' => 'keep-alive',
            'Content-Length' => '160',
            'Content-Type' => 'application/x-www-form-urlencoded',);
    var $loginInfo = array('u' => '', 'p' => '', 'c' => '', 'd' => '');//u:user  p:password  c:captcha
        //d:captcha-id
    public function __construct($u = '', $p = '')
    {
        $this->u = $u;
        $this->p = $p;
    }

    public function setCaptcha($c = '', $d = '')
    {
        $this->c = $c;
        $this->d = $d;
    }
    public function login()
    {
        $this->setCaptcha($_POST['c'], $_POST['d']);
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->loginUrl);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $this->header);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, "source=index_nav&form_email={$this->u}&form_password={$this->p}&captcha-solution={$this->c}&captcha-id={$this->d}");
        curl_setopt($ch, CURLOPT_USERAGENT, "Weizhao curl test");
        //get cookie info
        curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookieFile);
        curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookieFile);
        $html = curl_exec($ch);
        curl_close($ch);

        //if need a captcha ,  I have no idea, so input the code in pic by youself.  what the fuck.......
        if($this->needCaptcha($html))
        {
            $id = $this->getCaptchaId($html);
            $url = "http://www.douban.com/misc/captcha?id=$id&size=s";
            echo "<img src=\"$url\">";
            echo<<<FORM
            <form action="" method="post">
            <input name="c" type="text">
            <input name="d" type="hidden" value="$id">
            <input type="submit" name="realsubmit">
            </form>
FORM;
            exit;
        }
        return true;
    }

    public function getFriends()
    {
        //init curl and du some option
        $ch = curl_init('http://www.douban.com/contacts/list');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_USERAGENT, "Weizhao curl test");
        curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookieFile);
        curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookieFile);
        $result = curl_exec($ch);
        curl_close($ch);

        //get the firends name
        preg_match_all('/<h3>[\s\n]+<a[^>]+title=".*">(.*)<\/a>/Us', $result, $m);
        $firends[] = $m[1];

        //if firends more ,  get the page start
        preg_match_all('/paginator.*start=([0-9]*)"/Us', $result, $p);
        $pag = array_unique($p[1]);

        //more pages, so we do the same thing in parallel
        if(count($pag) > 0)
        {
           $arr = array();
           foreach($pag as $page)
           {
                $c = curl_init("http://www.douban.com/contacts/list?tag=0&start=$page");
                curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($c, CURLOPT_USERAGENT, "Weizhao curl test");
                curl_setopt($c, CURLOPT_COOKIEFILE, $this->cookieFile);
                curl_setopt($c, CURLOPT_COOKIEJAR, $this->cookieFile);
                array_push($arr, $c);
           }

           $mh = curl_multi_init();
           foreach($arr as $k => $h)
           {
               curl_multi_add_handle($mh, $h);
           }

           $running = null;
           do
           {
               curl_multi_exec($mh, $running);
           }while($running > 0);

           foreach($arr as $k => $h)
           {
               $new[$k]['data'] = curl_multi_getcontent($h);
               preg_match_all('/<h3>[\s\n]+<a[^>]+title=".*">(.*)<\/a>/Us', $new[$k]['data'], $t);
               $firends[] = $t;
               curl_multi_remove_handle($mh, $h);
           }

           curl_multi_close($mh);

        }
        return $firends;
    }

    private function getCaptchaId($html)
    {
        //if need a capcha, also a match captcha-id will be pass to server
        preg_match('/captcha\-id.*value="(.*)"/Us', $html, $matches);
        return $matches[1];
    }

    private function needCaptcha($html)
    {
        return (preg_match('/captcha\-id/i', $html)) ? true : false;
    }
}
$douban = new douban('username', 'password');
if($douban->login())
{
    $r = $douban->getFriends();
    echo '<pre>';
    //echo htmlspecialchars($r);
    print_r($r);
    echo '</pre>';
    exit;
}

1 comment

Leave a Reply

Your email address will not be published.