0

URL: http://bcmprod.brill.com/rsuite-cms/

I am trying to automate downloading of manuscripts from the client site above. I am using selenium phantomjs in C#.

I have the user credentials. But the elements that make up the login form (e.g. username, password) are not existing in the page source, but are existing when you inspect those elements in the browser.

These are the xpaths I'm using to locate them from "Inspect element" (IDs are dynamically assigned that's why I didn't use them):

string xpathUsername = ".//input[@name='user']";
string xpathPassword = ".//input[@name='pass']";
string xpathBtnLogin = ".//button[@type='submit'][@aria-label='Log In']";

How can I successfully login when the source returned by the driver has no login elements thus cannot be found, but yet existing when I inspect them in the browser?

Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.IO;
using OpenQA.Selenium;
using OpenQA.Selenium.PhantomJS;
using OpenQA.Selenium.Support.UI;
using WebCrawler.Helper;

namespace WebCrawler.Webcodes
{
    class RSuite : IWebcode
    {
        List<string> errors = new List<string>();
        string xpathUsername = ".//input[@name='user']";
        string xpathPassword = ".//input[@name='pass']";
        string xpathBtnLogin = ".//button[@type='submit'][@aria-label='Log In']";

        public RSuite()
        { }

        public List<Record> GetRecords()
        {
            Console.WriteLine(string.Format("Crawling:  {0}", Config.Url));
            List<Record> recordList = new List<Record>();
            try
            {
                PhantomJSDriverService service = PhantomJSDriverService.CreateDefaultService();
                service.HideCommandPromptWindow = true;

                using (IWebDriver driver = new PhantomJSDriver(service))
                {
                    driver.Navigate().GoToUrl(Config.Url);
                    Console.WriteLine("\nChecking elements availability ...");

                    // code exception here: I couldn't get all these elements
                    IWebElement username = Element("User ID", GetElement(driver, xpathUsername));
                    IWebElement password = Element("Password", GetElement(driver, xpathPassword));
                    IWebElement btnlogin = Element("Login Button", GetElement(driver, xpathBtnLogin));

                    // input credentials
                    Console.WriteLine("\nAttempting to login ...");
                    if (username != null && password != null && btnlogin != null)
                    {
                        username.Clear();
                        username.SendKeys(Config.Username);
                        password.Clear();
                        password.SendKeys(Config.Password);

                        // is button clicked & loaded a new page? (If true, login is successful)
                        if (IsPageLoaded(driver, btnlogin))
                        {
                            Console.WriteLine("Logged in successfully.");
                            // do some action
                            // download files
                        }
                        else
                        { ErrorHandler("Login failed."); }
                    }
                    else
                    { ErrorHandler("Login failed."); }
                }
                // release
                service.Dispose();
            }
            catch (Exception err)
            { ErrorHandler(err.GetBaseException().ToString()); }

            // generate report for caught errors, if any
            if (errors.Count() > 0)
                Config.ErrorReport(this.GetType().Name.Trim().ToUpper(), string.Join("\n\n", errors));

            return recordList;
        }


        private IWebElement GetElement(IWebDriver driver, string xPath)
        {
            IWebElement element = null;
            try
            {
                // wait for elements to load
                WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
                Func<IWebDriver, IWebElement> waitForElement = new Func<IWebDriver, IWebElement>((IWebDriver d) =>
                {
                    element = d.FindElement(By.XPath(xPath));
                    if (element != null)
                    { return element; }
                    return null;
                });
                return wait.Until(waitForElement);
            }
            catch (Exception err)
            {
                ErrorHandler(err.GetBaseException().ToString());
                return null;
            }
        }


        private IWebElement Element(string label, IWebElement element)
        {
            if (element != null)
            { Console.WriteLine(string.Format("{0}:  Yes", label)); }
            else
            { Console.WriteLine(string.Format("{0}:  No", label)); }
            return element;
        }


        private bool IsPageLoaded(IWebDriver driver, IWebElement element)
        {
            try
            {
                // page redirected? Or is the element still attached to the DOM?
                WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60));
                element.Click();
                return wait.Until(ExpectedConditions.StalenessOf(element));
            }
            catch (Exception err)
            {
                ErrorHandler(err.GetBaseException().ToString());
                return false;
            }
        }

        private void ErrorHandler(string error)
        {
            Console.WriteLine(error);
            errors.Add(error);
        }
    }
}
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
poy
  • 1
  • 3

1 Answers1

1

As per your question the url http://bcmprod.brill.com/rsuite-cms/ is based on Ember.js so you have to induce WebDriverWait inconjunction with ExpectedConditions method ElementToBeClickable() while you look out for the elements.

The Locator Strategies to identify the desired fileds are as follows:

  • User ID:

    string username = "//input[@class='ember-view ember-text-field finput text-field component' and @name='user']";
    
  • Password:

    string password = "//input[@class='ember-view ember-text-field finput text-field component' and @name='pass']";
    
  • Log In:

    string loginbtn = "//label[@class='ui-button-text']";
    
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • I'll try the ElementsToBeClickable(). – poy Aug 17 '18 at 13:13
  • @poy It's `ElementToBeClickable()` (not `ElementsToBeClickable()`) – undetected Selenium Aug 18 '18 at 03:44
  • Doesn't work. I used your xpaths as well as mine, but to no avail. Here's my snippet: `private IWebElement GetElement(IWebDriver driver, string xPath) { try { WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(60)); return wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xPath))); } catch (Exception err) { ErrorHandler(err.GetBaseException().ToString()); return null; } }` – poy Aug 22 '18 at 05:02