Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

WWW::Mechanize or WWW::Selenium with javascript redirect

by tphyahoo (Vicar)
on Jan 18, 2007 at 12:03 UTC ( [id://595230]=perlquestion: print w/replies, xml ) Need Help??

tphyahoo has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to fetch a web page, follow a javascript redirect, and verify that a string is found at the landing site.

If you copy/paste the url below into a browser

http://xml.pangora.com/scripts/Redirect.php?fid=45&mid=1066&serviceNam +e=idealo-de&serviceType=portal&oid=1066de515358&sid=73&pt=idealo-de.e +xport.1-0&url=http%3A%2F%2Fwww.baur.de%2Fis-bin%2FINTERSHOP.enfinity% +2FWFS%2FBaur-BaurDe-Site%2Fde_DE%2F-%2FEUR%2FBV_ExternalCall-Start%3F +ArticleNo%3D515358%26NUMSArt%3D4443504%26NUMSArtPc%3D4488615%26Affili +ateID%3Dpangora-%2A%26Name%3Dpangora-produktdaten-baur%26ActionID%3Dp +reis-produkt-suche-baur%26WKZ%3D79%26IWL%3D101
you see it redirects to a web page whose page source should match the regex (eg, the price "249,90"). However, WWW::Mechanize cannot follow this redirect -- although in general, mech is usually pretty good about redirects. I think this is a server side redirect.

I realize I could attempt to parse the html on the obtained page, which has some text to the effect of "if you were not redirected, try here." However, I have many groups of such pages I would like to follow redirects with, each of which would require a parse (and some of which might not have a "if didn't redirect, try this" text to parse), and I'm wondering if there is a more general solution

I tried WWW::Selenium, but was unable to get it to work. I suspect this is because selenium is beta-ish, and maybe my environment is just selenium unfriendly. I'm on linux, suse, firefox 2.

Can anyone get this to work, with Mech, Selenium, or something else?

Thanks in advance!

use strict; use warnings; use WWW::Mechanize; my $url = 'http://xml.pangora.com/scripts/Redirect.php?fid=45&mid=1066 +&serviceName=idealo-de&serviceType=portal&oid=1066de515358&sid=73&pt= +idealo-de.export.1-0&url=http%3A%2F%2Fwww.baur.de%2Fis-bin%2FINTERSHO +P.enfinity%2FWFS%2FBaur-BaurDe-Site%2Fde_DE%2F-%2FEUR%2FBV_ExternalCa +ll-Start%3FArticleNo%3D515358%26NUMSArt%3D4443504%26NUMSArtPc%3D44886 +15%26AffiliateID%3Dpangora-%2A%26Name%3Dpangora-produktdaten-baur%26A +ctionID%3Dpreis-produkt-suche-baur%26WKZ%3D79%26IWL%3D101'; my $price = '249,9'; my $mech = WWW::Mechanize->new(); my $response = $mech->get( $url ); my $html = $mech->content; print "price: $price\n"; print "url: $url\n"; print "html: $html\n"; print "ok" if $html =~ $price;

UPDATE: changed "server side redirect" to "javascript redirect"

UPDATE 2 getting closer, but still can't do what I want:

use strict; use warnings; use WWW::Mechanize; use Data::Dumper; my $url = 'http://xml.pangora.com/scripts/Redirect.php?fid=45&mid=1066 +&serviceName=idealo-de&serviceType=portal&oid=1066de515358&sid=73&pt= +idealo-de.export.1-0&url=http%3A%2F%2Fwww.baur.de%2Fis-bin%2FINTERSHO +P.enfinity%2FWFS%2FBaur-BaurDe-Site%2Fde_DE%2F-%2FEUR%2FBV_ExternalCa +ll-Start%3FArticleNo%3D515358%26NUMSArt%3D4443504%26NUMSArtPc%3D44886 +15%26AffiliateID%3Dpangora-%2A%26Name%3Dpangora-produktdaten-baur%26A +ctionID%3Dpreis-produkt-suche-baur%26WKZ%3D79%26IWL%3D101'; my $price = '249,9'; print "price: $price\n"; my $redirect_url = redirect_url($url); my $redirect_url_expected = 'http://www.baur.de/is-bin/INTERSHOP.enfin +ity/WFS/Baur-BaurDe-Site/de_DE/-/EUR/BV_ExternalCall-Start?ArticleNo= +515358&NUMSArt=4443504&NUMSArtPc=4488615&AffiliateID=pangora-bd&Name= +pangora-produktdaten-baur&ActionID=preis-produkt-suche-baur&WKZ=79&IW +L=101'; die "oops" unless $redirect_url eq $redirect_url_expected; my $mech = WWW::Mechanize->new(); $mech->agent('Firefox'); $mech->get( $redirect_url ); my $html = $mech->content; print "html from $redirect_url doesn't match $price\n" unless $html =~ + /$price/ ; print "but paste into browser and view source, and it does\n"; print "final url after firefox redirect (but not www::mech redirect) i +s something like " . 'http://www.baur.de/is-bin/INTERSHOP.enfinity/WF +S/Baur-BaurDe-Site/de_DE/-/EUR/BV_DisplayProductInformation-ArticleNo +;sid=7oVhaTsE5oZsaX6rnON4q25Uv6S6Ixu_PzIwW50ajEGxS04TwoV1a_bGFYiItw== +?ArticleNo=515358&ls=0&firstPage=true&showGewinnspiel=true&showW3B=fa +lse' . "\n"; # uncomment this to print html, which is totally different from what y +ou get from firefox, show source. # print "html: $html"; # works ok sub redirect_url { my $url = shift or die "no url"; my $mech = WWW::Mechanize->new(); $mech->get( $url ); my $links; $links = $mech->links; $mech->get( $links->[1]->url ); $links = $mech->links; my $redirect_url = $links->[0]->base->as_string; }

Replies are listed 'Best First'.
Re: WWW::Mechanize or WWW::Selenium with server side redirect
by shmem (Chancellor) on Jan 18, 2007 at 12:52 UTC
    It seems like the target (Bauer Versand) requires JavaScript for the content to be rendered properly. Without JavaScript, you just get the note:
    Um Ihnen den Online-Einkauf so angenehm wie möglich zu machen, arbeiten wir mit der neuesten Technik.
    Aus diesem Grund sind unsere Seiten für JavaScript-fähige Browser optimiert.
    Leider unterstützt Ihr Browser zur Zeit nicht diese Funktion.
    Damit auch Sie von den vielen Vorteilen profitieren können, müssen Sie in Ihren Einstellungen die Funktion "JavaScript/ActiveScripting" aktivieren.

    In short, it tells you to activate JavaScript.

    As for WWW::Mechanize to follow the redirect link, just say

    my $mech = WWW::Mechanize->new(); my $response = $mech->get( $url ); $mech->follow_link( n => 1 ); # this is the one in the META tag my $html = $mech->content; ...

    Since you use Firefox, you might want to look at JavaScript::SpiderMonkey to evaluate JavaScript. Some time ago, I wrote Re: Handling Javascript with LWP::UserAgent which might serve as an example.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
WWW::Mechanize fetch differs from firefox browser result (was Re: WWW::Mechanize or WWW::Selenium with javascript redirect)
by tphyahoo (Vicar) on Jan 18, 2007 at 15:37 UTC
    With some prodding from shmem, I was able to make progress, culminating in the code post above for "Update 2".

    However, I still can't match the text I want, becuase the page fetched with WWW::Mech differs from the text I get when I open the url in firefox and do view source.

    This is either no longer a javascript issue, or if it is a javascript issue I don't understand how to troubleshoot it.

    At any rate, to simply reiterate the test case for my problem (basically the same as Update 2 above, but shorter and simpler):

    use strict; use warnings; use WWW::Mechanize; use Data::Dumper; my $price = '249,9'; print "price: $price\n"; my $url = 'http://www.baur.de/is-bin/INTERSHOP.enfinity/WFS/Baur-BaurD +e-Site/de_DE/-/EUR/BV_ExternalCall-Start?ArticleNo=515358&NUMSArt=444 +3504&NUMSArtPc=4488615&AffiliateID=pangora-bd&Name=pangora-produktdat +en-baur&ActionID=preis-produkt-suche-baur&WKZ=79&IWL=101'; my $mech = WWW::Mechanize->new(); $mech->agent('Firefox/1.0 (Windows; U; Win98; en-US; Localization; rv: +1.4) Gecko/20030624 Netscape/7.1 (ax)'); $mech->get( $url ); my $html = $mech->content; print "html from $url doesn't match $price\n" unless $html =~ /$price/ + ; print "but paste into browser and view source, and it does\n"; print "final url after firefox redirect (but not www::mech redirect) i +s something like " . 'http://www.baur.de/is-bin/INTERSHOP.enfinity/WF +S/Baur-BaurDe-Site/de_DE/-/EUR/BV_DisplayProductInformation-ArticleNo +;sid=7oVhaTsE5oZsaX6rnON4q25Uv6S6Ixu_PzIwW50ajEGxS04TwoV1a_bGFYiItw== +?ArticleNo=515358&ls=0&firstPage=true&showGewinnspiel=true&showW3B=fa +lse' . "\n"; # uncomment this to print html, which is totally different from what y +ou get from firefox, show source. # print "html: $html";
    Can anyone prod me further in the right direction?

    PS: I'm still wondering if I would get better results with Win32::IE::Mechanize or WWW::Selenium or Mozilla::Mechanize.

    UPDATE: better user agent string after perrin comment.

      If the site is actually sending different content to Firefox, it must be using the User-Agent string. Just set your User-Agent in Mech to be the same as the one Firefox sends.
        I set user agent screen as in update above, but still no dice.
      Okay, I bullied a coworker into letting me use their windows box, and tried out Win32::IE::Mechanize. Unfortunately, I don't think this is going to work either. But I learned some things.

      Reason it won't work: "The internet Explorer automation object does not provide an interface to popup windows generated by security settings or Jscript contained on the page" (from the docu).

      Unless I am mistaken, when I try to open my target page, there is exactly this: a javascript redirect. The effect of my test program (below) is that an empty IE window, with a blank browser bar, gets opened, and separately a second window is opened with the html that I want. But as the docu says, there is no way to get at the second window. (Since the window that I am able to get html from appears to be the blank one.) Unless there is some way to get around this "no way to access popup windows" issue with OLE or something (and I know nothing about OLE) I guess this is a dead end.

      I was next going to try out Mozilla::Mechanize, but I read in the docu for that that it was based on IE::Mechanize, and the docu doesn't even mention popups, so I'm going to save it for last. Finally there is Selenium. Selenium has a function called

      $sel->get_all_window_ids() Returns the IDs of all windows that the browser knows about.
      That seems promising. As I said above, I had troubles getting selenium to work with perl on linux. Maybe I'll have better luck on windows. I'll report my findings when they are in.

      Finally, FWIW, here's my experimentations with mechanize, and my failed attempts to work around the popup window.

      use strict; use warnings; use Win32::IE::Mechanize; my $ie = Win32::IE::Mechanize->new( visible => 1 ); use Data::Dumper; my $price = '249,9'; print "price: $price\n"; my $url = 'http://xml.pangora.com/scripts/Redirect.php?fid=45&mid=1066 +&serviceName=idealo-de&serviceType=portal&oid=1066de515358&sid=73&pt= +idealo-de.export.1-0&url=http%3A%2F%2Fwww.baur.de%2Fis-bin%2FINTERSHO +P.enfinity%2FWFS%2FBaur-BaurDe-Site%2Fde_DE%2F-%2FEUR%2FBV_ExternalCa +ll-Start%3FArticleNo%3D515358%26NUMSArt%3D4443504%26NUMSArtPc%3D44886 +15%26AffiliateID%3Dpangora-%2A%26Name%3Dpangora-produktdaten-baur%26A +ctionID%3Dpreis-produkt-suche-baur%26WKZ%3D79%26IWL%3D101'; # if visible, you get an open IE window. my $mech = Win32::IE::Mechanize->new( visible => 1 ); #$mech->agent('Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.8.1) Gecko +/20061010 (IKDhPmJcdw) Firefox/2.0'); $mech->get( $url ); my $html = $mech->content; unless ( $html =~ /$price/ ) { print "html from $url doesn't match $price\n"; print "even though IE mech opened a visible IE window, and the text +there obviously DOES match.\n"; print "and what the heck is this blank IE window with no url in the +location bar?\n"; print "you don't get that extra blank window if you call IE Mech aga +inst a more normal looking url, like http://www.yahoo.com.\n"; print "aaaaghh!\n"; # uncomment this to print html, which is totally different from what + you get from firefox, show source. # print "html: $html"; } # # need something like # my $ieWindows = getwindows(); # should be two windows. # but ... module docu says "The internet Explorer automation object do +es not provide # an interface to poupp windows generated by security settings or jscr +ipt contained in the page". # So, I guess this won't work. Unless I can get into the IE object wit +h OLE or something, # (which I know nothing about).
        Seriously, there is no need to use Selenium or IE. If you use a logging proxy or the Firefox LiveHTTPHeaders extension, you will see exactly what the browser sends to the server, and then you just have to make your script send the same thing. No actual execution of JavaScript is required, since the server has no way to tell if you ran any client-side code or not.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://595230]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2024-04-16 17:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found