Мой первый Perl-скрипт: использование метода "get($url)" в цикле?
Так что это казалось достаточно простым. Используйте серию вложенных циклов, чтобы пройти через тонну URL-адресов, отсортированных по году / месяцу / дню, и загрузить файлы XML. Поскольку это мой первый скрипт, я начал с цикла; что-то знакомое на любом языке. Я запустил его, просто распечатав сконструированные URL, и он работал отлично. Затем я написал код для загрузки контента и сохранения его отдельно, и он отлично работал с примером URL в нескольких тестовых примерах. Но когда я объединил эти два фрагмента кода, он сломался, программа просто застряла и ничего не сделала. Поэтому я запустил отладчик и, пройдя через него, застрял в одной строке:
warnings:: register:: import (/usr/share/perl/5.10/warnings/register.pm:25): 25: vec ($ warnings:: Bits {$ k}, $ warnings:: LAST_BIT, 1) = 0;
Если я просто нажму r, чтобы вернуться из подпрограммы, она сработает и перейдет к другой точке на пути обратно вниз по стеку вызовов, где нечто подобное происходит снова и снова в течение некоторого времени. Трассировка стека:
$ = warnings:: register:: import ('warnings:: register') вызывается из файла `/usr/lib/perl/5.10/Socket.pm'строка 7
$ = Socket:: BEGIN () вызывается из файла `/usr/lib/perl/5.10/Socket.pm'строка 7
$ = eval {...} вызывается из файла `/usr/lib/perl/5.10/Socket.pm'строка 7
$ = require 'Socket.pm' вызывается из файла `/usr/lib/perl/5.10/IO/Socket.pm'строка 12
$ = IO:: Socket:: BEGIN () вызывается из файла `/usr/lib/perl/5.10/Socket.pm'строка 7
$ = eval {...} вызывается из файла `/usr/lib/perl/5.10/Socket.pm'строка 7
$ = require 'IO / Socket.pm', вызванный из файла `/usr/share/perl5/LWP/Simple.pm'строка 158
$ = LWP:: Simple:: _ trivial_http_get ('www.aDatabase.com', 80, '/sittings/1987/oct/20.xml'), вызываемый из файла `/usr/share/perl5/LWP/Simple.pm' линия 136
$ = LWP:: Simple:: _ get (' http://www.aDatabase.com/1987/oct/20.xml') вызывается из файла `xmlfetch.pl'строка 28
Как вы можете видеть, это застревает внутри этого метода "get($url)", и я понятия не имею, почему? Вот мой код:
#!/usr/bin/perl
use LWP::Simple;
$urlBase = 'http://www.aDatabase.com/subheading/';
$day=1;
$month=1;
@months=("list of months","jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec");
$year=1987;
$nullXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<nil-classes type=\"array\"/>\n";
while($year<=2006)
{
$month=1;
while($month<=12)
{
$day=1;
while($day<=31)
{
$newUrl = "$urlBase$year/$months[$month]/$day.xml";
$content = get($newUrl);
if($content ne $nullXML)
{
$filename = "$year-$month-$day.xml";
open(FILE, ">$filename");
print FILE $content;
close(FILE);
}
$day++;
}
$month++;
}
$year++;
}
Я почти уверен, что это что-то крошечное, я просто не знаю, но Google ничего не обнаружил.
Заранее спасибо,
B.
РЕДАКТИРОВАТЬ: Это официально, он просто висит навсегда внутри этого метода get, работает в течение нескольких циклов, а затем снова зависает на некоторое время. Но это все еще проблема. Почему это происходит?
4 ответа
Поскольку http://www.adatabase.com/1987/oct/20.xml представляет собой 404 (и это не то, что может быть сгенерировано из вашей программы в любом случае (нет "подзаголовка" в пути), я предполагаю, что это не настоящая ссылка, которую вы используете, что затрудняет нам тестирование. Как правило, пожалуйста, используйте example.com вместо того, чтобы составлять имена хостов, поэтому он зарезервирован.
Вы должны действительно
use strict;
use warnings;
в вашем коде - это поможет выделить любые проблемы с областями видимости, которые могут у вас возникнуть (я был бы удивлен, если бы это было так, но есть вероятность, что часть кода LWP возится с вашей $urlBase или чем-то еще). Я думаю, что этого должно быть достаточно, чтобы изменить объявления исходных переменных (и $newUrl, $content и $filename), чтобы поставить "my" впереди, чтобы сделать ваш код строгим.
Если использование строгих правил и предупреждений не приближает вас к решению, вы можете предупредить ссылку, которую вы собираетесь использовать в каждом цикле, чтобы, когда она зависла, вы могли попробовать ее в браузере и посмотреть, что произошло, или, альтернативно, использовать пакет. сниффер (например, Wireshark) может дать вам некоторые подсказки.
(2006 - 1986) * 12 * 31
больше 7000. Запрашивать веб-страницы без паузы не приятно.
Чуть более Perl-подобная версия (в стиле кода):
#!/usr/bin/perl
use strict;
use warnings;
use LWP::Simple qw(get);
my $urlBase = 'http://www.example.com/subheading/';
my @months = qw/jan feb mar apr may jun jul aug sep oct nov dec/;
my $nullXML = <<'NULLXML';
<?xml version="1.0" encoding="UTF-8"?>
<nil-classes type="array"/>
NULLXML
for my $year (1987..2006) {
for my $month (0..$#months) {
for my $day (1..31) {
my $newUrl = "$urlBase$year/$months[$month]/$day.xml";
my $content = "abc"; #XXX get($newUrl);
if ($content ne $nullXML) {
my $filename = "$year-@{[$month+1]}-$day.xml";
open my $fh, ">$filename"
or die "Can't open '$filename': $!";
print $fh $content;
# $fh implicitly closed
}
}
}
}
LWP имеет getstore
функция, которая делает большую часть извлечения, а затем сохраняет работу для вас. Вы также можете проверить LWP::Parallel::UserAgent и немного больше контролировать, как вы попадаете на удаленный сайт.
Я еще не использовал Perl, но на первый взгляд мне интересно, если исключение выдается в результате ошибки 404. Я полагаю, что функция просто вернула бы undef, если бы ответ HTTP был 404, 403, перенаправление и т. Д., Но, возможно, это не так.
Я мог бы рекомендовать использовать wget для этого. Что-то вроде `wget $url`, я думаю, будет работать.
В любом случае, как я уже сказал, я не программист на Prl, но поскольку ссылка, которую вы разместили, на самом деле 404, это мое предположение.
Дайте мне знать, если вы обнаружите, что это проблема.