Так что это казалось достаточно простым. Используйте серию вложенных циклов, чтобы пройти через тонну 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') called from file `/usr/lib/perl/5.10/Socket.pm' line 7
$ = Socket::BEGIN() called from file `/usr/lib/perl/5.10/Socket.pm' line 7
$ = eval {...} called from file `/usr/lib/perl/5.10/Socket.pm' line 7
$ = require 'Socket.pm' called from file `/usr/lib/perl/5.10/IO/Socket.pm' line 12
$ = IO::Socket::BEGIN() called from file `/usr/lib/perl/5.10/Socket.pm' line 7
$ = eval {...} called from file `/usr/lib/perl/5.10/Socket.pm' line 7
$ = require 'IO/Socket.pm' called from file `/usr/share/perl5/LWP/Simple.pm' line 158
$ = LWP::Simple::_trivial_http_get('www.aDatabase.com', 80, '/sittings/1987/oct/20.xml') called from file `/usr/share/perl5/LWP/Simple.pm' line 136
$ = LWP::Simple::_get('http://www.aDatabase.com/1987/oct/20.xml') called from file `xmlfetch.pl' line 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 ничего не обнаружил.
Заранее спасибо,
Б.
Обновлено: Официально, он просто навсегда зависает внутри этого метода get, выполняется несколько циклов, а затем снова зависает на некоторое время. Но это все еще проблема. Почему это происходит?
честный звонок. считать их замененными. облом об этом методе все же.
Пожалуйста, предоставьте 1. вывод perl -V, 2. номера версий для LWP :: Simple, Socket и IO :: Socket.
также возможно, что удаленный сайт ограничивает скорость ваших запросов ...
Я поддержу предложение Alnitak (целевой сайт ограничивает скорость, и функция "зависает" до истечения времени ожидания запроса).
Всегда use strict и use warnings





Я еще не использовал Perl, но на первый взгляд мне интересно, возникло ли исключение в результате ошибки 404. Я мог бы предположить, что функция просто вернет undef, если ответ HTTP был 404, 403, перенаправление и т. д., Но, возможно, это не так.
Я могу порекомендовать для этого использовать wget. Что-то вроде `wget $ url`, думаю, подойдет.
В любом случае, как я уже сказал, я не программист Prl, но, поскольку ссылка, которую вы разместили, на самом деле 404, это мое предположение.
Сообщите мне, если вы обнаружите, что это проблема.
Это не так, я просто решил скрыть настоящую ссылку. он работает нормально, как я уже сказал, я тестировал метод get и сохранение отдельно. Когда на сайте нет дневной записи, он возвращает XML точно так же, как значение, которое я проверяю с помощью $ nullXML. Я попробую wget и посмотрю, работает ли он.
wget работает, но он немного более привередлив, так как он сразу сохраняет его, и я не хочу, чтобы каждый файл записывался на диск, пока он не пройдет проверку. Я мог бы проверить после, но ценой большего количества операций ввода-вывода на диск. спасибо, хотя это определенно полезно для других случаев.
Поскольку http://www.adatabase.com/1987/oct/20.xml - это 404 (и не является чем-то, что может быть сгенерировано из вашей программы в любом случае (без `` подзаголовка '' в пути), я предполагаю, что это не настоящая ссылка, которую вы используете, что усложняет нам задачу. для тестирования. Как правило, используйте example.com вместо имени хоста, поэтому он зарезервирован.
Ты действительно должен
use strict;
use warnings;
в вашем коде - это поможет выделить любые проблемы с областью видимости, которые могут у вас возникнуть (я был бы удивлен, если бы это было так, но есть вероятность, что часть кода LWP возится с вашей $ urlBase или чем-то еще). Я думаю, этого должно быть достаточно изменить объявления исходных переменных (и $ newUrl, $ content и $ filename), чтобы поставить «my» впереди, чтобы сделать ваш код строгим.
Если использование strict и warnings не приближает вас к решению, вы можете предупредить ссылку, которую собираетесь использовать, каждый цикл, чтобы, когда он застрял, вы могли попробовать его в браузере и посмотреть, что произойдет, или, альтернативно, используя пакет сниффер (такой как Wireshark) может дать вам некоторые подсказки.
это сработало, добавив эти операторы использования и бросив «я» перед всем, и вот мы. Как я уже сказал, кое-что крошечное, чего я не знал. Большое спасибо, и извините, что я новичок в некоторых конвенциях, запомню на будущее.
@gnomed: example.com - это больше, чем просто соглашение, это RFC 2606.
@gnomed: посмотрите Date :: Format и Date :: Parse; вы можете свернуть все циклы дат в один цикл и одновременно избегать таких дат, как «2005-02-31».
(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
}
}
}
}
Быстрое предупреждение: Perl незаметно преобразует диапазоны min..max в массив, а затем выдает итератор над ним (по крайней мере, ActivePerl в Windows). Сравните поведение min..max с (my $ i = min; $ i <max; ++ $ i), и оно примерно в 10 раз медленнее (по сравнению с моим последним тестом). Медленно переносил все свои скрипты :)
спасибо за аккуратную версию, пока не могу сказать, что нахожусь на таком уровне, это еще мой второй день. но что касается запросов веб-сайтов, я изменил свою программу после того, как заставил ее работать, чтобы установить паузы для немного более разумной скорости запросов.
@kyle: Вы используете старую версию Perl. for $i ($min..$max) быстрее и не потребляет больше памяти, чем for ($i=$min; $i<=$max; ++$i).
LWP имеет функцию getstore, которая выполняет большую часть загрузки, а затем сохраняет работу за вас. Вы также можете проверить LWP :: Parallel :: UserAgent и немного больше контроля над тем, как вы попадаете на удаленный сайт.
Понятия не имею, почему это не удается (ваш код выглядит нормально), но, пожалуйста, замените циклы while на циклы for (т.е. «for ($ year = 1987; $ year <= 2006; $ year ++)» или «for $ year. (1987 .. 2006) ».