使用 WWW::Mechanize 登录

con*_*con 3 perl

我正在考虑 使用以下内容登录https://imputationserver.sph.umich.edu/index.html#!pages/login

#!/usr/bin/env perl

use strict;
use warnings FATAL => 'all';
use feature 'say';
use autodie ':all';
use WWW::Mechanize;
use DDP;

my $mech = WWW::Mechanize->new();
$mech->get( 'https://imputationserver.sph.umich.edu/index.html#!pages/login' );
my $username = '';
my $password = '';
#$mech->set_visible( $username, $password );
#$mech -> field('Username:', $username);
#$mech -> field('Password:', $password);

my %data;
@{ $data{links} } = $mech -> find_all_links();
@{ $data{inputs}    } = $mech -> find_all_inputs();
@{ $data{submits} } = $mech ->find_all_submits();
@{ $data{forms} } = $mech -> forms();
p %data;

#$mech->set_fields('Username' => $username, 'Password' => $password);
Run Code Online (Sandbox Code Playgroud)

但似乎没有任何有用的信息,通过打印显示:

{
    forms     [],
    inputs    [],
    links     [
        [0] WWW::Mechanize::Link  {
            public methods (9) : attrs, base, name, new, tag, text, URI, url, url_abs
            private methods (0)
            internals: [
                [0] "favicon.ico",
                [1] undef,
                [2] undef,
                [3] "link",
                [4] URI::https,
                [5] {
                    href   "favicon.ico",
                    rel    "icon"
                }
            ]
        },
        [1] WWW::Mechanize::Link  {
            public methods (9) : attrs, base, name, new, tag, text, URI, url, url_abs
            private methods (0)
            internals: [
                [0] "assets/css/loader.css",
                [1] undef,
                [2] undef,
                [3] "link",
                [4] var{links}[0][4],
                [5] {
                    href   "assets/css/loader.css",
                    rel    "stylesheet"
                }
            ]
        }
    ],
    submits   []
}
Run Code Online (Sandbox Code Playgroud)

我查看了 Firefox 的工具 -> 页面信息,但没有任何有价值的信息,我在此页面上看不到用户名和密码的来源。

我试过了

$mech -> submit_form(
    form_number => 0,
    fields      => { username => $username, password => $password },
);
Run Code Online (Sandbox Code Playgroud)

但后来我得到 No form defined

在链接、输入、字段方面,我没有看到任何内容,我不知道如何继续。

我在https://metacpan.org/pod/WWW::Mechanize::Examples上没有看到任何可以帮助我解决这种情况的内容。

如何使用 Perl 的 WWW::Mechanize 登录此页面?

Joe*_*hon 6

正如 Dave 所说,许多现代网站将通过 Javascript 驱动的(私有)API 处理登录。您需要在浏览器中打开“网络”选项卡,像往常一样手动登录,然后观察 GET、PUT、POST 等的顺序,了解完成登录所需的交互,然后使用Mech或自己执行该序列LWP

页面上的 Javascript 可能会创建 JSON 甚至 JWT 来进行交互;你必须在你的代码中复制它才能工作。

特别是,检查 cookie 的标头,以及设置的身份验证和 CSRF 令牌;您需要捕获它们并通过请求重新发送它们(POST 请求将需要 CSRF 令牌)。这可能需要与站点进行更多交互以捕获操作序列并复制它们。HTTP::Cookies应该自动为您处理 cookie,但更复杂的标头用法将要求您使用HTTP::Headers提取数据并可能以这种方式重新提交。

本质上,这些过程都非常简单;这只是准确复制它们的问题,以便您可以自动化它们。

您应该检查该站点是否已经有程序员的 API,如果有就使用它;这样的 API 几乎总是会为您提供更简单、直接的站点功能接口和更易于使用的返回数据格式。如果站点是高度动态的,比如一个沉重的 React 站点,那么站点中的其他页面可能会加载一个骨架 HTML 页面,然后也使用 Javascript 来填充它;随着页面的发展,您的代码也必须如此。如果您使用的是已定义的程序员 API,那么只要 API 版本不更改,您就可能能够依赖于交互和返回的数据保持不变。

最后一点:您应该使用自动化来验证您没有违反用户协议。某些站点明确禁止使用自动登录方法。


Dav*_*oss 5

该页面来源的有趣部分是:

<body class="bg-light">

  <div id="main">
    <div class="spinner">
        <div class="bounce1"></div>
      <div class="bounce2"></div>
      <div class="bounce3"></div>
    </div>
  </div>

  <script src="./dist/bundles/cloudgene/index.js"></script>


</body>
Run Code Online (Sandbox Code Playgroud)

因此,构成该页面的 HTML 中没有登录表单。这就解释了为什么 WWW::Mechanize 什么也看不到——那里什么也看不到。

似乎该页面都是由该 Javascript 文件构建的 - index.js.

现在,您可以花几个小时阅读该 JS 并准确了解页面的工作方式。但这将是一项艰巨的工作,并且有一种更简单的方法。

无论客户端(浏览器或您的代码)如何工作,实际登录都必须由 HTTP 请求和响应处理。客户端发送请求,服务器响应,客户端根据该响应执行操作。您只需要弄清楚请求和响应是什么样的,然后在您的代码中重现它。

您可以使用浏览器内置的工具检查 HTTP 请求和响应(在 Chrome 中,它是点菜单 -> 更多工具 -> 开发人员工具)。这将使您能够准确地看到 HTTP 请求的样子。

完成此操作后,您“只需要”使用您的 Perl 代码制作一个类似的响应。您可能会发现使用LWP::UserAgent及其相关模块比使用 WWW::Mechanize更容易。

  • WWW::Mechanize 是 LWP::UserAgent 的子类。如果您可以使用 LWP::UA 做到这一点,那么您也可以使用 WWW::Mech 进行完全相同的操作。但是,使用 LWP::UA 将避免 WWW::Mech 的页面解析开销。 (2认同)