如何与PhantomJS通信PHP以解决Captchas

时间:2015-09-02 20:18:27

标签: phantomjs

我想解决的问题如下:

我需要通过PHP管理外部网页,例如登录,然后在我自己的网站上发送ajax请求后更改外部网站上的个人资料信息。

为此,我从PHP调用PhantomJS来执行这些任务,但在登录外部Web之前,我需要填写验证码输入。因此,我想将Captcha图像发送回我的网站,编写正确的代码并将其发送回PhantomJS的WebPage模块,以便使用该代码登录。

换句话说,我需要一个同步的'程序是这样的:

1)PHP - >发送登录请求并获取验证码图像。

2)PhantomJS - >打开WebPage实例并将验证码代码渲染为图像。

3)PHP - >获取验证码图像,将其显示给用户并将文本输入发送到PhantomJS。

4)PhantomJS - >从PHP获取文本代码,使用' page.evaluate'填充验证码输入。并登录。向PHP发送一些数据('登录成功','登录失败'等)

5)PHP - >获取回调并发送另一个任务或数据。

callback = 'Login successfull' --> Change profile picture or update user info.

callback = 'Login failed' --> Try to login again (like point 1)

等等...

有许多事情我不知道如何处理。例如:

1)如何保持WebPage模块打开并等待验证码的文本代码?如果我关闭它,下次会出现一个新的验证码,我需要一种方法来等待代码并获得它。我需要为此启动服务器吗?

2)从PHP获取验证码图像不是问题(因为' page.render'),但我如何将文本发送回PhantomJS的WebPage实例?我认为最好在两个系统之间双向发送数据。我需要一台服务器吗?

我想在PhantomJS中需要一个套接字服务器(如何做到这一点?)。这个服务器应该有我需要保持打开的WebPage实例,但我对此并不完全确定。

感谢。

1 个答案:

答案 0 :(得分:1)

我最近发布了一个项目,可以让PHP访问浏览器。得到它:https://github.com/merlinthemagic/MTS,引擎盖是PhantomJS的一个实例。

主要问题是在初始执行后保持资源存活。这是我建议你这样做的方式。

下载并设置后,您只需使用以下代码:

开始"设置"会话:

if (isset($_POST['sessionUID']) === false) {

    //set the execution timeout long enough to cover the entire process (setup and working time), it dictates when phantomJS shuts down automatically.
    ini_set('max_execution_time', 300);

    //open the login page:
    $myUrl          = "http://www.example.com";
    $browserObj      = \MTS\Factories::getDevices()->getLocalHost()->getBrowser('phantomjs');

    //allow the page to live after php shuts down.
    $browserObj->setKeepalive(true);
    $windowObj      = $browserObj->getNewWindow($myUrl);

    //find the username input box, here it has id=username
    $windowObj->mouseEventOnElement("[id=username]", 'leftclick');
    //type your username
    $windowObj->sendKeyPresses("yourUsername");

    //find the password input box, here it has id=passwd
    $windowObj->mouseEventOnElement("[id=passwd]", 'leftclick');
    //type your password
    $windowObj->sendKeyPresses("yourPassword");

    //click on the login button, here it has id=login
    $windowObj->mouseEventOnElement("[id=login]", 'leftclick');

    //i assume this is when you encounter the CAPTCHA image

    //find the CAPTCHA image element, here it has id=captchaImage
    $element    = $windowObj->getElement("[id=captchaImage]");
    $loc        = $element['location'];

    //tell the screenshot to only get the CAPTCHA image
    $windowObj->setRasterSize($loc['top'], $loc['left'], ($loc['right'] - $loc['left']), ($loc['bottom'] - $loc['top']));


    $imageData  = $windowObj->screenshot("png");
    $sessionUID  = uniqid();

    $saveWindowObj = serialize($windowObj);

    //save the window object so we can pick it up again
    file_put_contents("/tmp/" . $sessionUID, $saveWindowObj);
}
//now render the CAPTCHA image to the user as part of a form they can resubmit and make sure to keep the $sessionUId as a hidden variable in the form on the page

"设置"结束会话,php在这里关闭。

开始"工作"会议: 我们假设用户提交表单,它是一个包含$ sessionUID和CAPTCHA文本字符串的帖子。

if (isset($_POST['sessionUID']) === true && isset($_POST['captchaTxt']) === true) {
$savedWindow = file_get_contents("/tmp/" . $sessionUID);

//delete the saved object
unlink("/tmp/" . $sessionUID);

//bring back the object to life
$windowObj = unserialize($savedWindow);

//make sure the browser is now shutdown on exit
$windowObj->getBrowser()->setKeepalive(false);

//find the CAPTCHA input box, here it has id=captchaInput
$windowObj->mouseEventOnElement("[id=captchaInput]", 'leftclick');
//type the CAPTCHA string
$windowObj->sendKeyPresses($_POST['captchaTxt']);

//click on the button to accept CAPTCHA, here it has id=captchaOK
$windowObj->mouseEventOnElement("[id=captchaOK]", 'leftclick');

//now use the clickElement() etc functions on $windowObj to do what you need to do.

}

结束"工作"会话,php在这里关闭。