使用 WWW::Mechanize 保存文件

Saving files with WWW::Mechanize

我正在尝试以编程方式从此页面抓取文件:https://olms.dol-esa.gov/query/getYearlyData.do(是的,手动下载它们可能会更快,但我想学习如何执行此操作)。

我有以下代码来尝试对其中一个文件进行测试:

#!/usr/bin/perl
use strict;
use warnings;
use WWW::Mechanize; 

my $mech = WWW::Mechanize->new;

$mech->get( 'https://olms.dol-esa.gov/query/getYearlyData.do' );
print $mech->uri();
$mech->submit_form( with_fields => { selectedFileName => '/filer/local/cas/YearlyDataDump/2000.zip' } );

当我运行代码时,没有任何反应。什么都没有下载。认为 javascript 可能是问题所在,我也用 WWW::Mechanize::Firefox 尝试了相同的代码。同样,当我 运行 代码时没有任何反应。

我也没有看到文件的路径。它可能在某些 javascript.

中被遮盖了

那么获取这些文件的最佳方式是什么?没有 javascript 可以得到它们吗?

虽然 ThisSuitIsBlackNot 的评论是正确的,但有一种相当简单的方法可以在不使用 JS 的情况下以编程方式执行此操作。你甚至不需要 WWW::Mechanize。

我用 Web::Scraper 找到了所有文件。正如您所说,表单值就在那里。这是将它们刮掉的问题。 WWW::Mechanize 擅长导航,但不太擅长抓取。另一方面,Web::Scraper 的界面非常简单。

获得文件后,我们需要做的就是提交一个包含正确表单值的 POST 请求。这与 WWW::Mechanize 的 submit_form 非常相似。事实上,WWW::Mechanize 是一个LWP::UserAgent 底层,我们只需要一个请求,所以我们不能直接使用它。

:content_file option on the post method 告诉它将响应放入文件中。它会对 ZIP 文件做正确的事情,并自动将其写入二进制文件。

use strict;
use warnings;
use LWP::UserAgent;
use Web::Scraper;
use URI;

# build a Web::Scraper to find all files on the page
my $files = scraper {
    process 'form[name="yearlyDataForm"]',    'action'  => '@action';
    process 'input[name="selectedFileName"]', 'files[]' => '@value';
};

# get the files and the form action
my $res = $files->scrape( URI->new('https://olms.dol-esa.gov/query/getYearlyData.do') );

# use LWP to download them one by one
my $ua = LWP::UserAgent->new;
foreach my $path ( @{ $res->{files} } ) {

    # the file will end up relative to the current working directory (.)
    ( my $filename ) = ( split '/', $path )[-1];

    # the submit is hardcoded, but that could be dynamic as well
    $ua->post(
        $res->{action},
        { selectedFileName => $path, submitButton => 'Download' },
        ':content_file' => $filename # this downloads the file
    );
}

一旦你运行这个,你将拥有脚本目录中的所有文件。需要一点时间,没有输出,但它有效。

您需要确保在表单中包含提交按钮。

既然你想学习如何做这样的事情,我就让它稍微动态一点。表单操作也会被删除,因此您可以在使用相同表单名称(或将其作为参数)的类似表单上重用它,而不必关心表单操作。同样的事情也可以用提交按钮完成,但是你需要同时获取 namevalue 属性。

不过我会重复一下 抓取一个网站总是伴随着它以后会改变的风险! 对于 one-time 没有的东西没关系,如果你想 运行 每年将其作为 cronjob 一次,它明年可能已经失败了,因为他们最终更新了他们的网站,使其更加现代。