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

У меня есть простой сценарий входа в систему, использующий Perl WWW::Mechanize. Я пишу сценарии для входа в Moodle. Когда я просто выполняю шаги входа в систему как процедурные шаги, это работает. Например (предположим, что "$site_url", USERNAME и PASSWORD установлены правильно):

#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. Он просто не входит в систему. Яр! (Да, "ярг" был нужен)

Спасибо!


person JDS    schedule 02.05.2011    source источник
comment
Может что-то с печеньем? Поработайте с cookie_jar   -  person snoofkin    schedule 03.05.2011
comment
Кроме того, просто предложение, если вы хотите использовать OO в Perl, используйте Moose, это творит чудеса.   -  person snoofkin    schedule 03.05.2011


Ответы (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 и предупреждения, которые помогут выявить ваши ошибки.

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

Прагма base имеет некоторые нежелательные эффекты, которые нельзя исправить по соображениям обратной совместимости. Вместо него была разработана прагма parent.

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

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

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

person cjm    schedule 02.05.2011
comment
ОМГ, спасибо. Вы ответили не только на мой основной вопрос, но и на 5 второстепенных вопросов, которые у меня были. Я не использовал Perl какое-то время, и мои мышцы Perl довольно вялые. Извините, получилось неправильно, но вы поняли, я уверен. О, кроме того, я использовал «строгие» и «предупреждения» — я просто не включил это во фрагмент кода вместе с некоторыми другими элементами преамбулы, которые я пропустил. - person JDS; 03.05.2011
comment
Итак, породил несколько новых вопросов. Любая информация/документы/URL-адреса/и т. д. в этой части: $self-›{AutoUpdater} = {... ...И последующее его использование... my $data = $self-›{AutoUpdater}; Я не понимаю, почему я не могу просто использовать $self-›{site_url} напрямую. Спасибо - person JDS; 03.05.2011
comment
@JDS, я расширил свое объяснение того, почему я рекомендую $self->{AutoUpdater}{site_url} вместо $self->{site_url} в своем ответе. - person cjm; 03.05.2011