Perl WWW ::Mechanize как дочерний класс; не могу оставаться в системе на очищенном сайте

#perl #subclass #mechanize

#perl #подкласс #механизировать

Вопрос:

У меня есть простой скрипт входа с использованием Perl WWW::Mechanize. Я создаю сценарии входа в Moodle. Когда я просто выполняю шаги входа в систему как процедурные шаги, это работает. Например (предположим, что «$site_url», ИМЯ ПОЛЬЗОВАТЕЛЯ и ПАРОЛЬ были установлены соответствующим образом):

 #THIS WORKS
$updater->get("http://".$site_url."/login/index.php");
$updater->form_id("login");
$updater->field('username', USERNAME);
$updater->field('password', PASSWORD);
$updater->click();
$updater->get("http://".$site_url."/");
print $updater->content();
  

Когда я пытаюсь инкапсулировать эти шаги внутри дочернего класса WWW:Mechanize, get () и content () и другие методы, похоже, работают, но вход на сайт — нет. У меня такое чувство, что это связано с областью видимости переменной, но я не знаю, как это решить.

Пример (сбой):

 my $updater = new AutoUpdater( $site_url, USERNAME, PASSWORD );
$updater->do_login();

{
package AutoUpdater;
use base qw( WWW::Mechanize );

sub new {
    my $class = shift;
    my $self = {
        site_url => shift,
        USERNAME => shift,
        PASSWORD => shift,
   };
    bless $self, $class;
    return $self;
}

sub do_login {
    my $self = shift;
    $self->get("http://".$site_url."/");
    $self->get("http://".$site_url."/login/index.php");
    $self->form_id("login");
    $self->field("username", $self->{USERNAME});
    $self->field("password", $self->{PASSWORD});
    $self->click();
    $self->get("http://".$site_url."/");
    print $self->content();
}
}
  

Это не удается. «Сбой» означает, что он не входит в систему. Тем не менее, он захватывает веб-страницу, и я могу манипулировать данными HTML. Он просто не входит в систему. Тьфу! (Да, «yargh» было необходимо)

Спасибо!

Комментарии:

1. Может быть, что-то с файлами cookie? Поработайте с cookie_jar

2. Также, просто предложение, если вы хотите использовать OO в Perl, используйте Moose, это сотворит чудо.

Ответ №1:

Вот исправленная версия:

 use strict;
use warnings;

my $updater = AutoUpdater->new( $site_url, USERNAME, PASSWORD );
$updater->do_login();

{
package AutoUpdater;
use parent qw( WWW::Mechanize );

sub new {
  my $class = shift;

  my $self = $class->SUPER::new();

  $self->{AutoUpdater} = {
    site_url => shift,
    USERNAME => shift,
    PASSWORD => shift,
  };

  return $self;
}

sub do_login {
  my $self = shift;
  my $data = $self->{AutoUpdater};

  $self->get("http://$data->{site_url}/login/index.php");
  $self->form_id("login");
  $self->field("username", $data->{USERNAME});
  $self->field("password", $data->{PASSWORD});
  $self->click();
  $self->get("http://$data->{site_url}/");
  print $self->content();
}
} # end package AutoUpdater
  

Некоторые примечания:

Вы всегда должны использовать strict и warnings, чтобы помочь выявить ваши ошибки.

Синтаксис косвенного объекта не рекомендуется. Используйте Class->new вместо new Class .

Базовая прагма имеет некоторые нежелательные эффекты, которые невозможно исправить по соображениям обратной совместимости. Для его замены была разработана родительская прагма.

Ваша большая проблема заключалась в том, что Perl не инициализирует базовые классы автоматически. При необходимости вы должны явно вызвать $class->SUPER::new .

Другой вашей большой проблемой было понимание того, как обрабатываются данные экземпляра объекта. Большинство объектов Perl являются hashrefs, и вы получаете доступ к данным экземпляра, используя синтаксис hashref. При создании подкласса для класса, который я не писал, мне нравится использовать второй hashref, чтобы избежать конфликтов с родительским классом. Помните, что вы делитесь объектом с базовыми классами. Если ваш подкласс использует site_url поле, а затем более поздняя версия базового класса начнет использовать site_url для чего-то другого, ваш код внезапно сломается без видимой причины. Используя только один ключ в hashref базового объекта (и тот, который базовый класс вряд ли начнет использовать), вы минимизируете вероятность будущей поломки.

Хотя Moose предоставляет некоторые приятные функции для программирования OO на Perl, если вы просто пишете довольно простой подкласс класса, отличного от Moose, вероятно, лучше избегать этого.

Комментарии:

1. Боже, спасибо. Вы ответили не только на мой основной вопрос, но и примерно на 5 второстепенных маленьких вопросов, которые у меня были. Я давно не использовал Perl, и мои возможности Perl довольно вялые. Извините, это прозвучало неправильно, но вы поняли суть, я уверен. О, также, я использовал ‘strict’ и ‘warnings’ — я просто не включил это во фрагмент кода вместе с некоторыми другими элементами преамбулы, которые я опустил.

2. Хорошо, итак, породил несколько новых вопросов. Любая информация / документы / URLS / etc по этой части: «$self->{AutoUpdater} = {…» … И последующее его использование… «my $data = $self->{AutoUpdater};» Мне не ясно, почему я не могу просто использовать «$ self->{site_url}» напрямую. Спасибо

3. @ JDS, я расширил свое объяснение того, почему я рекомендую $self->{AutoUpdater}{site_url} вместо $self->{site_url} в моем ответе.