2017-02-02 110 views
2

我试图以编程方式从这个页面上抓取文件:https://olms.dol-esa.gov/query/getYearlyData.do(是的,它可能会更快手动下载它们,但我想学习如何做到这一点)。用WWW保存文件::机械化

我有下面的代码位,试图尝试此上的文件作为测试之一:

#!/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?

+0

在你的浏览器中禁用JavaScript,你会发现没有它的页面是没用的,所以WWW :: Mechanize不在了。不过,使用WWW :: Mechanize :: Firefox,你应该看看数据是否可以通过API获得;这几乎总是比拼凑更好的选择。 [Here](http://developer.dol.gov/)是劳工部API的主页。 – ThisSuitIsBlackNot

+0

是的,我知道页面显示空白没有打开javascript。但是,源代码仍然存在,我很想知道为什么POST请求(包含与请求一起发送的相应字段)不会导致服务器发送文档,尤其是使用WWW :: Mechanize :: Firefox。 – StevieD

+1

查看JS禁用的源代码:没有'

'元素,所以'submit_form'自然不会做任何事情。至于W :: M :: F不工作,你没有设置'submitButton'参数,并且还有其他你可能不需要设置的头文件。但是,这正是API的用途;你不应该在为人类消费而设计的网页的内容上大肆宣传,因为它可能会随时改变,并以一百多种不同的方式破坏你的代码。 – ThisSuitIsBlackNot

回答

1

尽管ThisSuitIsBlackNot的评论很有用,但是有一种相当简单的方式来编程,而不使用JS。你甚至不需要WWW :: Mechanize。

我用Web::Scraper找到所有的文件。正如你所说,表格的价值在那里。这是一个刮掉它们的问题。 WWW ::机械化擅长导航,但不擅长刮削。 Web :: Scraper的界面非常简单。

一旦我们有了这些文件,我们所需要做的就是提交一个带有正确表单值的POST请求。这与WWW :: Mechanize的submit_form非常相似。实际上,WWW :: Mechanize是一个LWP::UserAgent,我们需要的只是一个请求,所以我们可以直接使用它。

post method上的:content_file option指示它将响应放入文件中。它会用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属性。

我会重复一下ThisSuitIsBlackNot said in their comment虽然:刮一个网站总是会带来后来改变的风险!对于一次性无关紧要的事情,如果您希望将其作为一年一次的cronjob运行,它可能会在明年失败,因为他们最终更新了自己的网站以使其更具现代感。

+1

非常巧妙。我对Web :: Scraper很熟悉,但并没有想到用它来拉取必要的表单元素。我也没有考虑像这样使用LWP :: UserAgent。我学到了一些我正在寻找的东西。谢谢! 是的,我很清楚刮擦的局限性。这更像是一次学术练习,所以我可以打磨我的技能。 – StevieD

+0

@StevieD很高兴我能帮上忙。 :) – simbabque