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

Hi All!

I've spent days fighting this problem and have no ideas left. I've tried so many variations that my brain is jello. I need your help.

Background: my buddy does social media posts (Google My Business, Facebook, etc...) for local small businesses. He asked me if I could save him time by automating his postings (he manually submits the same info to multiple social media sites). I'm starting on Google My Business (GMB). Chrome headless doesn't seem to be able to save cookies between sessions (I think this is a bug in Chrome) so it requires a fresh login each time, but I can't get WWW:Mechanize::Chrome past the login screens. This is on CentOS 7.

I'm sending headless Chrome directly to the client's GMB dashboard URL. Because Chrome doesn't have the login cookie, it automatically redirects to a Google login page that asks for the username. I have Mechanize::Chrome typing the username and clicking the "Next" button. This works. Next, the password page loads. For the life of me, I cannot get Mechanize::Chrome to type the password in the password field. Instead, I get the error "No elements found for input with name Passwd".

This is the simplified version of the code I'm using:

... my $response = $mech->get($url); $mech->sleep(3); # Click in Login Email form field $mech->click({ xpath => '//*[@id="Email"]' }); $mech->field( Email => 'email-address@gmail.com' ); $mech->sleep(1); $mech->click_button( name => 'signIn' ); # Give time for password page to load $mech->sleep(5); # Click in Password field $mech->click({ xpath => '//*[@id="Passwd"]' }); $mech->sleep(3); # Enter Password $mech->field( "Passwd" => 'password-for-account' ); $mech->sleep(1); $logger->info("Clicking Sign in button"); $mech->click_button( name => 'signIn' ); ...

At the point where the password should be typed in, I get the error ("No elements found for input with name Passwd").
My first thought was that I mistyped the field id/name. I changed the code so that just before the password is entered, I did a $mech->content and printed it to the screen. It's long and has lots of javascript, but here's the form area part of it:

<form novalidate="" method="post" action="https://accounts.google.com +/signin/challenge/sl/password" id="gaia_loginform"> <input name="Page" type="hidden" value="PasswordSeparationSignIn"> <input type="hidden" name="GALX" value="XCHRh4ZpFTs"> <input type="hidden" name="gxf" value="AFoagUWBRLTpTA7CO8g4iomkNYj8Z +2_Srg:1535077371041"> <input type="hidden" name="continue" value="https://business.google. +com/dashboard/l/05764639469034420312?hl=en"> <input type="hidden" name="followup" value="https://business.google. +com/dashboard/l/05764639469034420312?hl=en"> <input type="hidden" name="service" value="lbc"> <input type="hidden" name="ltmpl" value="gmb"> <input type="hidden" name="hl" value="en"> <input type="hidden" name="flowName" value="GlifWebSignIn"> <input id="profile-information" name="ProfileInformation" type="hidd +en" value="APMTqumPnwp8RwQfcaP7K5ZZkvEM4k9SGAwLqlcvFtpTDSUdYojsxn8jb3 +83MAoLdkhH19NZwY69x9URqtxYlW4c-fuT3SpYTc1qDH10IRj9LotwfGWtglnfVHIQuji +SbWKp5ZlE9I6AArll8PDt7ZFUVHvdWdB4r9Gb0su-Uam7NDMnu5D_UGYE-ZXcBvF8gYDO +NQxKPQaKPlurzRgo6Z_b164OmDZvzboV0HV18nXomOpTlhyC-_PTjqXCgoE6D4YZ9ce3n +NQTupcKhpE34Cm9TQ1U4ZMm9nbbmpvmtkRdzv_ABvnSz-RoG029IZXUitKau05A"> <input id="session-state" name="SessionState" type="hidden" value="A +EThLlyF4GA-jXD2WstIzKGAI0BfuPkitjcMBRlwIUoqykGrJ8kRaqTzKruu8YPuTb344L +Z7ug09_rFlO2tXa6R8LLjE36haRK1e4tfOGscT3FF9CJG1S7Grp3QBpayMsCxNAgsWPfH +T8Ixq4NDl8_bEbj-4b_etXrONPoG1Ijkhj8w1eOLNYF3oppfweXQzuIJ0acVhJlAfFXdM +txQbLSsn7BDfzJqLeYb4VQfRD2P7-ALAENptqvHOPiMIDOjQTqCSUWpuzENh76jG9w3Wi +N8LQ_34onYve2CQb0Zp1nyEXrhchWEYczkZLI3KMOtTSnnXYC_tcIY8uP2m8E3zqaLVcr +bbe3d1mDSuD0siQNCnW-p8XPlnWwozE_AFFe_5vsVm2-sq4a9PWCgQu4s8kC1jasIp0f0 +q0h9xaAKbmXvEoT5yN7ISWaYXMF7mYML1Pi55rC4iB4EDBOK80OsbCgtXm39fBXyD9O9f +C1wGMJW9L3EkvDauvmZ-RR372UDHGjvmbMmrwV1qdFiIjKa_ASoAkF9c2fxD2uXqbNVkd +UREuGir4W_NiLD8EB0uQRCbNrep9xtLTOp1fY3cIHXF10wclZTvu59NAXI70Tu6CdWDft +IcpuGQ80unAv1AoNV0nzHtyt3cdiPvmVxAcNa-xL4"> <input type="hidden" id="_utf8" name="_utf8" value="&#9731;"> <input type="hidden" name="bgresponse" id="bgresponse" value="js_dis +abled"> <a id="back-arrow" href="https://accounts.google.com/ServiceLogin?co +ntinue=https%3A%2F%2Fbusiness.google.com%2Fdashboard%2Fl%2F0576463946 +9034420312%3Fhl%3Den&amp;followup=https%3A%2F%2Fbusiness.google.com%2 +Fdashboard%2Fl%2F05764639469034420312%3Fhl%3Den&amp;service=lbc&amp;l +tmpl=gmb&amp;hl=en&amp;flowName=GlifWebSignIn" class="back-arrow shif +t-form"> <img aria-label="Back" alt="Back" src="https://www.gstatic.com/image +s/icons/material/system/1x/arrow_back_grey600_24dp.png"> </a> <div class="form-panel second"> <div class="slide-in "> <div> <p id="profile-name">(deleted)</p> <span dir="ltr" id="email-display">(deleted)</span> </div> <div> <div id="password-shown"> <div> <input id="Email-hidden" name="Email" type="email" spellcheck="false +" class="hidden" value="vnpagemanager@gmail.com" readonly="" autocomp +lete="off"> <label class="hidden-label" for="Passwd">Password</label> <input id="Passwd" name="Passwd" type="password" placeholder="Password +" class="" autofocus=""> </div> </div> </div> <input id="signIn" name="signIn" class="rc-button rc-button-submit" ty +pe="submit" value="Sign in"> <label class="remember"> <input id="PersistentCookie" name="PersistentCookie" type="checkbox" + value="yes" checked="checked"> <span> Stay signed in </span> <div class="bubble-wrap" role="tooltip"> <div class="bubble-pointer"></div> <div class="bubble"> For your convenience, keep this checked. On shared devices, addition +al precautions are recommended. <a href="https://support.google.com/accounts/?p=securesignin&amp;hl= +en" target="_blank">Learn more</a> </div> </div> </label> <input type="hidden" name="rmShown" value="1"> <a id="link-forgot-passwd" class="need-help" href="https://accounts. +google.com/signin/recovery?continue=https%3A%2F%2Fbusiness.google.com +%2Fdashboard%2Fl%2F05764639469034420312%3Fhl%3Den&amp;service=lbc&amp +;flowName=GlifWebSignIn&amp;Email=vnpagemanager%40gmail.com&amp;ignor +eShadow=0&amp;hl=en"> Forgot password? </a> </div> </div> </form>

I'm using Opera to connect and view the page output using the Chrome remote debugging port. When I inspect the element for the password field, it also shows the field has the name/id 'Passwd'

Does Google have some type of code to block automated logins? Have I simply referenced the password field incorrectly with Mechanize::Chrome?

I'm a pretty mediocre programmer, so be gentle. I'm open to any ideas that will help me get through this.

Thanks!

Replies are listed 'Best First'.
Re: Can't get past Google login with WWW::Mechanize::Chrome
by Corion (Patriarch) on Aug 24, 2018 at 16:19 UTC

    After some trying, I think there is at least a smallish bug with WWW::Mechanize::Chrome that doesn't let it recognized when pushing a button doesn't result in navigation (fixed on Github).

    Other than that, it seems that simply filling the Password field doesn't set the value in the way that the Google login application expects it. I've worked around this in my working example code by sending the keystrokes to the password entry manually. Most likely this "send keystrokes" method will find its way into WWW::Mechanize::Chrome soonish.

    #!perl use strict; use warnings; use Log::Log4perl ':easy'; use WWW::Mechanize::Chrome; use File::Temp 'tempdir'; Log::Log4perl->easy_init($TRACE); # Set priority of root logger to ER +ROR my $mech = WWW::Mechanize::Chrome->new( headless => 1, data_directory => tempdir(CLEANUP => 1), #profile => tempdir(CLEANUP => 1), ); my $url = 'https://keep.google.com'; my( $user, $pass) = @ARGV; my $response = $mech->get($url); $mech->sleep(3); # Click in Login Email form field $mech->form_number(1); #warn $mech->current_form->get_attribute('innerHTML'); my $username = $mech->xpath('//input[@type="email"]', single => 1 ); $username->set_attribute('value', "$user"); # For headless, it's "next" $mech->click({ xpath => '//*[@id="next"]' }); #$mech->click({ xpath => '//*[@id="identifierNext"]', synchronize => 0 + }); #$mech->sleep(1); #$mech->sleep(60); #$mech->click_button( name => 'signIn' ); # Give time for password page to load $mech->sleep(5); #my @f = $mech->xpath('//FORM'); #for my $form ( @f ) { # print $form->get_attribute('innerHTML'), "\n"; #print "---\n"; #}; # Click in Password field my $password_field = $mech->xpath('//input[@type="password"]', single +=> 1 ); #my $password_html = $mech->selector('#password', single => 1 ); #$mech->click( $password_html ); # html "field" to enable the real fie +ld $mech->click( $password_field ); # when headless #$password_field->set_attribute('value', "$pass"); #$password_field->set_attribute('data-initial-value', "$pass"); #$password_field = $mech->xpath('//input[@type="password"]', single => + 1 ); for my $key (split //, $pass) { # "type" in the password $mech->driver->send_message('Input.dispatchKeyEvent', type => 'cha +r', text => $key)->get; }; $mech->sleep(1); #$logger->info("Clicking Sign in button"); #$mech->click({ selector => '#passwordNext', single => 1 }); # for hea +dful $mech->click({ selector => '#signIn', single => 1 }); # for headless warn $mech->title; undef $mech; sleep 5;

      Hi Corion,

      Thanks so much for the reply and for the module. Your response at least gives some understanding and hope that there is a way to make this work. It's much appreciated!

Re: Can't get past Google login with WWW::Mechanize::Chrome
by hippo (Archbishop) on Aug 24, 2018 at 14:09 UTC

    Hello, lpowers. Is there some reason why you are choosing not to use the API? That would seem the simpler approach.

      Hi,

      I actually looked at their API info before starting down this road. I would definitely prefer to go the API route for multiple reasons.

      I was doubtful that we would qualify for access to the API based on how I read their requirements (it appeared to me that to qualify, a public project/app must be created). The biggest reason I didn't think I could use the API was that it appeared they only had clients for Java, C#, and PHP. I only program Perl and am pretty shaky at that.

      From looking at your link, are you suggesting that it might be possible to interface with their API using a Perl REST module? I've never done REST before, but would definitely give it a try if this is a possibility. Do you have a particular module or site that you might suggest for getting started?

      Thanks!

        Note that I have never used this API nor the web front end which you are currently using, so most of this is just general discussion. Using a web API instead of trying to interface with an HTML GUI front end would be better on many counts: supportability, efficiency, documentation (of the interface) and, so long as you adhere to the terms you shouldn't get arbitrarily blocked by the provider.

        I was doubtful that we would qualify for access to the API based on how I read their requirements (it appeared to me that to qualify, a public project/app must be created).

        That may well be the case, but why not make your code (at least some of it) public anyway?

        The biggest reason I didn't think I could use the API was that it appeared they only had clients for Java, C#, and PHP.

        The CPAN is chock-full of clients for APIs where the API provider hasn't seen fit to provide a Perl client. Don't let this put you off. And ask Google for a client anyway - if they realise there's a market they might be more inclined to supply it.

        are you suggesting that it might be possible to interface with their API using a Perl REST module?

        The document certainly implies that, yes. I tend to use REST::Client but there are other modules available.

        If I were in your shoes I would definitely at least attempt to use the API before dismissing it out of hand. Good luck.