Reputation: 5171
I'm using WWW::Mechanize to automate placing 'orders' in our supplier's portal (with permission). It's pretty straight-forward to do so by filling the relevant form fields and submit
ing as normal.
However, the portal has been built with a JavaScript-capable client in mind, and some short-cuts were taken as a result; the most significant short-cut they took is that as you progress through a "wizard" (series of forms) with normal POSTS, they require that you "deallocate" some resources server side for the "previous wizard step" by doing an AJAX POST. In pseudo-code:
GET page #1
fill the fields of page #1
POST (submit the form) --> redirects to page #2.
POST (ajax request to "/delete.do")
fill the fields of page #2
POST (submit the form) --> redirects to page #3.
POST (ajax request to "/delete.do")
fill the fields of page #3.
...
What's the easiest approach to do those ajax request to "/delete.do"
requests?
I've tried...
Appoach (A)
If I inject a new form (referencing /delete.do
in the action
) into the DOM and use submit
then the mech object will no longer have the HTML::Form
object built from the previous redirects to page #X
step.
If I just use back()
from that point, does that make another GET
to the server? (or is it just using the prior values from the page stack?)
Approach (B)
If I just use the post()
method inherited from LWP::UserAgent to send the POST to /delete.do
I get a security error -- I guess it's not using the cookie jar that has been set up by WWW::Mechanize.
Is there some canonical way to make an 'out-of-band' POST that:
UDPATE: For anyone trying to replicate the solution suggested by gangabass, you actually need to:
(1) Subclass
WWW::Mechanize
, overridingupdate_html
such that a new content can be injected into the HTML on demand.This content would normally be parsed by
HTML::Form::parse()
. The override sub needs to alter the first non-self parameter$html
before calling the original implementation and returning the result.package WWW::Mechanize::Debug; use base 'WWW::Mechanize'; sub update_html { my ($self,$html) = @_; $html = $WWW::Mechanize::Debug::html_updater->($html) if defined($WWW::Mechanize::Debug::html_updater); return $self->SUPER::update_html($html); } 1;
(2) In the main program, use
WWW::Mechanize::Debug
as perWWW::Mechanize
use WWW::Mechanize::Debug; my $mech = WWW::Mechanize::Debug->new;
(3) Inject the HTML form which will need to be
submit()
ed.{ my $formHTML = qq| <form action="/delete.do" method="POST" name="myform"> <!-- some relevant hidden inputs go here in the real solution --> </form> |; local $WWW::Mechanize::html_updater = sub { my ($html) = @_; $html =~ s|</body>|$formHTML</body>|; }; # Load the page containing the normal wizard step content. $mech->get($the_url); # This should how have an extra form injected into it. }
(4) In a new scope
clone()
the mechanize object, fill the form and submit it!{ my $other = $mech->clone; my $myform = $separate->form_name('my_form'); $myform->field('foo' => 'bar'); # fill in the relevant fields to be posted $myform->submit; }
(5) Continue using the original mechanize object as if that form submission had never occurred.
Upvotes: 1
Views: 803
Reputation: 10666
You need to clone
your Mech object and make POST from cloned version. Something like:
{
my $mech = $mech->clone();
$mech->post(....);
}
But of course it will be better to make sub for this.
Upvotes: 2