【问题标题】:Is there a PHP equivalent of Perl's WWW::Mechanize?是否有与 Perl 的 WWW::Mechanize 等效的 PHP?
【发布时间】:2010-09-16 23:25:37
【问题描述】:

我正在寻找一个功能类似于 Perl 的WWW::Mechanize 的库,但适用于 PHP。基本上,它应该允许我使用简单的语法提交 HTTP GET 和 POST 请求,然后解析结果页面并以简单的格式返回所有表单及其字段,以及页面上的所有链接。

我知道 CURL,但它有点太简单了,而且语法很丑(大量的 curl_foo($curl_handle, ...) 语句

澄清:

我想要比目前的答案更高级的东西。例如,在 Perl 中,您可以执行以下操作:

# navigate to the main page
$mech->get( 'http://www.somesite.com/' ); 

# follow a link that contains the text 'download this'
$mech->follow_link( text_regex => qr/download this/i );

# submit a POST form, to log into the site
$mech->submit_form(
    with_fields      => {
        username    => 'mungo',
        password    => 'lost-and-alone',
    }
);

# save the results as a file
$mech->save_content('somefile.zip');

要使用 HTTP_Client 或 wget 或 CURL 来做同样的事情会做很多工作,我必须手动解析页面以查找链接、查找表单 URL、提取所有隐藏字段等等。我要求使用 PHP 解决方案的原因是我没有使用 Perl 的经验,我可能会通过大量工作来构建我需要的东西,但如果我能在 PHP 中完成上述操作会更快。

【问题讨论】:

标签: php automation screen-scraping mechanize www-mechanize


【解决方案1】:

尝试查看 PEAR 库。如果一切都失败了,为 curl 创建一个对象包装器。

你可以这么简单:

class curl {
    private $resource;

    public function __construct($url) {
        $this->resource = curl_init($url);
    }

    public function __call($function, array $params) {
        array_unshift($params, $this->resource);
        return call_user_func_array("curl_$function", $params);
    }
}

【讨论】:

  • 这不是我想要的,我添加了一个澄清,希望能更清楚,谢谢。
【解决方案2】:

尝试以下方法之一:

(是的,它是 ZendFramework 代码,但它不会让你的类使用它变慢,因为它只是加载所需的库。)

【讨论】:

  • 他们仍然比 Mechanize 做更多的工作,请参阅我对问题的澄清。
  • 好问题。我认为他们还没有这样做。但我想我已经做好了构建它的准备,我明天会看看 Mechanize API。
  • 如果你最终做了什么,请发布一个新的答案,我一定会看看它。您可能想将“ScriptableBrowser”的答案作为起点,我认为它只需要更多功能来完成 Mechanize 所做的一切
  • 这需要一段时间,我仍然没有时间深入了解机械。我很惊讶已经没有端口了。
【解决方案3】:

如果您在 *nix 系统上,您可以将 shell_exec() 与 wget 一起使用,它有很多不错的选项。

【讨论】:

    【解决方案4】:

    【讨论】:

    • 看起来很有趣,但它已经很老了(最后一次更新是 2005 年),虽然比 curl/wget 更好,但它缺少一些使它更好的功能。
    【解决方案5】:

    SimpleTest 的ScriptableBrowser 可以独立于测试框架使用。我已经将它用于许多自动化工作。

    【讨论】:

    • 这看起来不错,我得试一试。它几乎有我需要的一切,唯一缺少的是一种列出页面上所有链接/表单的方法,但我想我可以做到。
    • 你可以使用$browser->getUrls()。否则,如果您需要更多控制权,您始终可以使用 $dom = DomDocument::loadHtml($browser->getContent()),然后使用 $dom->getElementsByTagName("a")。
    【解决方案6】:

    Curl 是处理简单请求的方式。它跨平台运行,具有 PHP 扩展,并被广泛采用和测试。

    我创建了一个不错的类,它可以通过调用 CurlHandler::Get($url, $data) || 获取和发布数据数组(包括文件!)到 url CurlHandler::Post($url, $data)。还有一个可选的 HTTP 用户身份验证选项:)

    /**
     * CURLHandler handles simple HTTP GETs and POSTs via Curl 
     * 
     * @package Pork
     * @author SchizoDuckie
     * @copyright SchizoDuckie 2008
     * @version 1.0
     * @access public
     */
    class CURLHandler
    {
    
        /**
         * CURLHandler::Get()
         * 
         * Executes a standard GET request via Curl.
         * Static function, so that you can use: CurlHandler::Get('http://www.google.com');
         * 
         * @param string $url url to get
         * @return string HTML output
         */
        public static function Get($url)
        {
           return self::doRequest('GET', $url);
        }
    
        /**
         * CURLHandler::Post()
         * 
         * Executes a standard POST request via Curl.
         * Static function, so you can use CurlHandler::Post('http://www.google.com', array('q'=>'StackOverFlow'));
         * If you want to send a File via post (to e.g. PHP's $_FILES), prefix the value of an item with an @ ! 
         * @param string $url url to post data to
         * @param Array $vars Array with key=>value pairs to post.
         * @return string HTML output
         */
        public static function Post($url, $vars, $auth = false) 
        {
           return self::doRequest('POST', $url, $vars, $auth);
        }
    
        /**
         * CURLHandler::doRequest()
         * This is what actually does the request
         * <pre>
         * - Create Curl handle with curl_init
         * - Set options like CURLOPT_URL, CURLOPT_RETURNTRANSFER and CURLOPT_HEADER
         * - Set eventual optional options (like CURLOPT_POST and CURLOPT_POSTFIELDS)
         * - Call curl_exec on the interface
         * - Close the connection
         * - Return the result or throw an exception.
         * </pre>
         * @param mixed $method Request Method (Get/ Post)
         * @param mixed $url URI to get or post to
         * @param mixed $vars Array of variables (only mandatory in POST requests)
         * @return string HTML output
         */
        public static function doRequest($method, $url, $vars=array(), $auth = false)
        {
            $curlInterface = curl_init();
    
            curl_setopt_array ($curlInterface, array( 
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => 1,
                CURLOPT_FOLLOWLOCATION =>1,
                CURLOPT_HEADER => 0));
            if (strtoupper($method) == 'POST')
            {
                curl_setopt_array($curlInterface, array(
                    CURLOPT_POST => 1,
                    CURLOPT_POSTFIELDS => http_build_query($vars))
                );  
            }
            if($auth !== false)
            {
                  curl_setopt($curlInterface, CURLOPT_USERPWD, $auth['username'] . ":" . $auth['password']);
            }
            $result = curl_exec ($curlInterface);
            curl_close ($curlInterface);
    
            if($result === NULL)
            {
                throw new Exception('Curl Request Error: '.curl_errno($curlInterface) . " - " . curl_error($curlInterface));
            }
            else
            {
                return($result);
            }
        }
    
    }
    
    ?>
    

    [编辑] 现在才阅读说明...您可能想要使用上面提到的自动化工具之一。您还可以决定使用 ChickenFoot 之类的客户端 firefox 扩展,以获得更大的灵活性。我将把上面的示例类留在这里以供将来搜索。

    【讨论】:

    • 谢谢你的例子,我认为这种包装器可能对其他任务很方便,但是我想我一开始应该更清楚的是我想要一个自动化类型的东西
    【解决方案7】:

    我觉得有必要回答这个问题,尽管它是一个旧帖子......我一直在使用 PHP curl,但它在任何地方都没有像 WWW:Mechanize 这样的东西那么好,我正在切换到(我想我将使用 Ruby 语言实现).. Curl 已经过时了,因为它需要太多“繁重的工作”来自动化任何东西,simpletest 可编写脚本的浏览器对我来说看起来很有希望,但在测试它时,它不会工作在我尝试的大多数网络表单上......老实说,我认为 PHP 在这类抓取、网络自动化方面缺乏,所以最好看看另一种语言,只是想发布这个,因为我在这个主题上花费了无数小时也许它会在未来为其他人节省一些时间。

    【讨论】:

      【解决方案8】:

      如果您在项目中使用 CakePHP,或者如果您倾向于提取相关库,您可以使用他们的 curl 包装器 HttpSocket。它具有您描述的简单页面获取语法,例如,

      # This is the sugar for importing the library within CakePHP       
      App::import('Core', 'HttpSocket');
      $HttpSocket = new HttpSocket();
      
      $result = $HttpSocket->post($login_url,
      array(
        "username" => "username",
        "password" => "password"
      )
      );
      

      ...虽然它没有办法解析响应页面。为此,我将使用 simplehtmldom:http://net.tutsplus.com/tutorials/php/html-parsing-and-screen-scraping-with-the-simple-html-dom-library/,它将自己描述为具有类似 jQuery 的语法。

      我倾向于同意,最重要的是 PHP 没有 Perl/Ruby 所拥有的出色的抓取/自动化库。

      【讨论】:

        【解决方案9】:

        现在是 2016 年,Mink。它甚至支持不同的引擎,从无头纯 PHP“浏览器”(没有 JavaScript)、Selenium(需要像 Firefox 或 Chrome 这样的浏览器)到 NPM 中的无头“browser.js”,它确实支持 JavaScript。

        【讨论】:

        • 这非常有用,而且比本页上提到的所有其他内容都要好得多。感谢您的更新!
        猜你喜欢
        • 1970-01-01
        • 2013-04-18
        • 1970-01-01
        • 2010-11-08
        • 1970-01-01
        • 1970-01-01
        • 2010-09-29
        • 1970-01-01
        • 2011-03-03
        相关资源
        最近更新 更多