如何使用Perl脚本从网址下载.zip文件?

3
我想下载一个.zip文件,该文件可以通过单击“以csv格式下载文件”位于URL http://www.nseindia.com/content/equities/cmbhav.htm来获取。
如果右键单击“以csv格式下载文件”,并选择复制链接位置,则URL模式将类似于http://www.nseindia.com/content/historical/EQUITIES/2012/MAR/cm23MAR2012bhav.csv.zip
我想编写一个Perl脚本,从URL下载.zip文件。
以下代码无效。
#!/usr/bin/perl
use warnings;
use strict;
use LWP::Simple;

my $url = 'http://www.nseindia.com/content/historical/EQUITIES/2012/MAR' ;
my $file = 'cm23MAR2012bhav.csv.zip'    ;
getstore($url, $file) ;
2个回答

6
如果您需要更改用户代理并仍希望使用 LWP::Simple,则可以使用导出的$ua
use File::Basename;
use LWP::Simple qw($ua getstore);
use URI;

my $url = URI->new( 'http://www.nseindia.com/content/historical/EQUITIES/2012/MAR/cm23MAR2012bhav.csv.zip' );

$ua->default_headers( HTTP::Headers->new(
    Accept => '*/*', 
    )
    );

$ua->agent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.54.16 (KHTML, like Gecko) Version/5.1.4 Safari/534.54.16");

my $rc = getstore( $url, basename( $url->path ) );
say "Result is $rc";

事实证明,用户代理字符串和接受标头的组合可以做到这一点。通常,这些问题归结为使您的LWP请求看起来就像您的浏览器发送的请求一样。我使用HTTPScoop观察浏览器交易,但有很多程序可以为您完成同样的操作。
但是,如果事情变得更加复杂,我更喜欢使用Mojo::UserAgent。这更容易处理交易。
use File::Basename;
use Mojo::UserAgent;
use URI;

my $url = URI->new( 'http://www.nseindia.com/content/historical/EQUITIES/2012/MAR/cm23MAR2012bhav.csv.zip' );
my $file = basename( $url->path );
printf "URL: %s\nFile: %s\n", $url, $file;

my $response = Mojo::UserAgent->new->name(
    '"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/534.54.16 (KHTML, like Gecko) Version/5.1.4 Safari/534.54.16"'
    )->get( $url->as_string, { Accept => '*/*' } )->res;

open my $fh, '>', $file or die "Could not open [$file]: $!";
print $fh $response->body;
printf "Status: %d\n", $response->code;

自从我及时尝试以来,它对我完美地起作用。如果你没试过,你怎么知道它能工作呢?我从 http://www.user-agents.org/ 获取了用户代理字符串... 如果我像许多 Q/A 网站上的用户一样傻,我会为此给予-1 的答案。此外,这不会获取 zip 文件,而是包含指向 zip 文件链接的页面。这是 OP 的错误,在我的“-1”答案中已经悄悄修复了。虽然 OP 必须做出一点努力来重定向输出或稍微更改代码以将文件保存在他想要的位置。 - ShinTakezou
1
我怎么知道我可以更改用户代理?我经常这样做。我也直接查看了HTTP请求和响应。我不知道你在评论中想说什么。 - brian d foy
不,你怎么知道它会解决问题!(我曾经遇到过仅仅改变用户代理并不足以解决问题的情况)。这是关于“逻辑判断过程”的观点,我经常不理解。 - ShinTakezou
1
我认为您错过了我第一个版本中的一部分,即我无法确定它是否解决了问题。今天早上我尝试过后,我可以获取资源,因此修改了我的答案。然而,我对用户代理的特定更改并不重要,重要的是您可以影响用户代理。 - brian d foy
是的,我错过了那部分,抱歉! - ShinTakezou

2

如果您使用

       print getstore($url, $file);

当你看到403错误(禁止)时,说明出现了问题。

添加内容:

经过使用curl进行试验,发现他们会检查用户代理,因此你不能使用LWP::Simple,因为你必须设置一个像真正的浏览器一样的用户代理。

添加内容2:

以下方法有效:

#! /usr/bin/perl -w

use warnings;
use strict;

use LWP::UserAgent;
my $url = 'http://www.nseindia.com/content/historical/EQUITIES/2012/MAR/cm23MAR2012bhav.csv.zip';
#my $file = 'cm23MAR2012bhav.csv.zip';
#my $url = 'http://localhost:11000';

my $ua = LWP::UserAgent->new;
$ua->agent("Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (FM Scene 4.6.1)");
my $req = HTTP::Request->new(GET => $url);
$req->header(Accept => "*/*");
# $req->remove_header('Connection');  # does not work
# $req->remove_header('TE');          # does not work
my $res = $ua->request($req);
if ($res->is_success)
{
    print $res->content;
}
else
{
    print $res->status_line, "\n";
}

移除头部信息的代码 remove_header 不会移除 TE 和 Connection 头部信息,因为它们是在协议层级插入的,所以移除它们需要不同的过程(我不知道该怎么做)。

总之这已经足够让它工作了。

(编辑:我的 UserAgent 字符串最后有一个空格,导致 LWP 添加了 libwww-perl,这就是服务器给出 403 错误的原因)

重要提示

你需要重定向输出或稍微修改代码来将内容保存到文件中。另外请注意,要下载 zip 文件,你需要提供正确的 URL,而不是包含链接的页面的 URL。


1
您可以更改LWP::Simple使用的用户代理。 - brian d foy
我一直以最简单的方式使用::Simple,从未检查过可以定制什么!好知道,谢谢。 - ShinTakezou
再次我想知道为什么有人在一个正确的答案上打了-1,而且这个答案还给出了正确的解决方案。还有一种更简单的方式仍然使用::Simple吗?不要紧,答案仍然是正确的,而且是有效的。有时候,我忘记了它可能会浪费时间,即使只有几分钟。代码中多余的行只是(个人)尝试让LWP发送与cURL完全相同的请求。 - ShinTakezou
1
为什么你会认为因为有人踩了你喜欢的答案,时间就被浪费了呢?提问者仍然可以看到你的回答,你也学到了一些东西,并且这个回答仍然对全世界可用。这些都不会因为一个踩而被否定。你只需要得到赞同即可。 - brian d foy
不,这是一个哲学(可以这么说)的问题。它不完全涉及投票或反对,而是关于人们决定投赞成、反对或不投票的过程和判断,以及这如何影响知识较少、缺乏“工具”来判断答案的人的判断。这个争论很广泛,完全与主题无关,我只是有时喜欢挑起争端! - ShinTakezou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接