мой первый Perl-скрипт: использование метода "get ($ url)" в цикле? - PullRequest
2 голосов
/ 22 января 2009

Так что это казалось достаточно простым. Используйте ряд вложенных циклов, чтобы пройти тонну URL-адресов, отсортированных по году / месяцу / дню, и загрузить файлы XML. Поскольку это мой первый скрипт, я начал с цикла; что-то знакомое на любом языке. Я запустил его, просто печатая сконструированные URL-адреса, и он работал отлично. Затем я написал код для загрузки контента и сохранения его отдельно, и он отлично работал с примером URL для нескольких тестовых случаев. Но когда я объединил эти два фрагмента кода, он сломался, программа просто застряла и ничего не сделала. Поэтому я запустил отладчик и, пройдя через него, застрял в одной строке:

предупреждений :: регистрация :: импорт (/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

$ = требуется '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

$ = требуется 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 ]

3 голосов
/ 22 января 2009

Поскольку http://www.adatabase.com/1987/oct/20.xml - это 404 (и это не то, что может быть сгенерировано из вашей программы в любом случае (без «подзаголовка» в пути), я предполагаю, что это не настоящая ссылка, которой вы являетесь использование, что затрудняет нам тестирование. Как правило, пожалуйста, используйте example.com вместо того, чтобы составлять имена хостов, поэтому он зарезервирован.

Вы должны действительно

use strict;
use warnings;

в вашем коде - это поможет выделить любые проблемы с областями видимости, которые могут у вас возникнуть (я был бы удивлен, если бы это было так, но есть вероятность, что часть кода LWP возится с вашей $ urlBase или чем-то еще ). Я думаю, что этого должно быть достаточно, чтобы изменить объявления начальных переменных (и $ newUrl, $ content и $ filename), чтобы поставить «my» впереди, чтобы сделать ваш код строгим.

Если использование строгих правил и предупреждений не приближает вас к решению, вы можете предупредить ссылку, которую вы собираетесь использовать в каждом цикле, чтобы, когда она залипла, вы могли попробовать ее в браузере и посмотреть, что происходит, или, в качестве альтернативы, использование анализатора пакетов (например, Wireshark ) может дать вам некоторые подсказки.

2 голосов
/ 22 января 2009

(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
            }
        }
    }
}
0 голосов
/ 22 января 2009

LWP имеет функцию getstore, которая выполняет большую часть выборки, а затем сохраняет работу за вас. Вы также можете проверить LWP :: Parallel :: UserAgent и немного больше контролировать, как вы попадаете на удаленный сайт.

0 голосов
/ 22 января 2009

Мне еще предстоит использовать Perl, но на первый взгляд мне интересно, возникло ли исключение в результате ошибки 404. Я полагаю, что функция просто вернула бы undef, если бы ответ HTTP был 404, 403, перенаправление и т. Д., Но, возможно, это не так.

Я мог бы рекомендовать использовать для этого wget. Что-то вроде `wget $ url`, думаю, сработает.

В любом случае, как я уже сказал, я не программист на Prl, но поскольку ссылка, которую вы разместили, на самом деле 404, это мое предположение.

Дайте мне знать, если вы обнаружите, что это проблема.

...