4

I've written a script in python in combination with selenium to log in to a website. The thing is my script sometimes successfully gets logged in but most of the times it comes across a slider which is meant to press and slide to the right.

How can I let my script slide that button to the right?

I've tried with:

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

def sign_in():
    driver.get("https://login.aliexpress.com/")
    wait.until(EC.frame_to_be_available_and_switch_to_it(wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "#alibaba-login-box")))))
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "input#fm-login-id"))).send_keys("someEmail")
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "input#fm-login-password"))).send_keys("somePassword")
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "button[class$='password-login']"))).click()

    #the following line is for handling the slider but it doesn't do anything

    item = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".nc_wrapper .btn_slide")))
    ActionChains(driver).move_to_element(item).perform()

if __name__ == '__main__':
    driver = webdriver.Chrome()
    wait = WebDriverWait(driver,10)
    sign_in()

Html elements connected to that slider:

<div id="nc_1_n1t" class="nc_scale">
<div id="nc_1__bg" class="nc_bg" style="width: 0px;"></div>
<span id="nc_1_n1z" class="nc_iconfont btn_slide" data-spm-anchor-id="0.0.0.i1.3f9579f4qCwuHp" style="left: 0px;"></span>
<div id="nc_1__scale_text" class="scale_text slidetounlock"><span class="nc-lang-cnt" data-nc-lang="_startTEXT">Please slide to verify</span></div>
<div id="nc_1_clickCaptcha" class="clickCaptcha" style="top: -118px; height: 235px;">
<div class="clickCaptcha_text">
<b id="nc_1__captcha_text" class="nc_captch_text"></b>
<i id="nc_1__btn_2" class="nc_iconfont nc_btn_2 btn_refresh"></i>
</div>
<div class="clickCaptcha_img"></div>
<div class="clickCaptcha_btn"></div>
</div>
<div id="nc_1_imgCaptcha" class="imgCaptcha" style="top: -118px; min-height: 290px; height: 189px;">
<div class="imgCaptcha_text"><input id="nc_1_captcha_input" maxlength="6" type="text" style="ime-mode:disabled"></div>
<div class="imgCaptcha_img" id="nc_1__imgCaptcha_img"></div>
<i id="nc_1__btn_1" class="nc_iconfont nc_btn_1 btn_refresh" onclick="document.getElementById('nc_1__imgCaptcha_img').children[0].click()"></i>
<div class="imgCaptcha_btn">
<div id="nc_1__captcha_img_text" class="nc_captcha_img_text"></div>
<div id="nc_1_scale_submit" class="nc_scale_submit"></div>
</div>
</div>
<div id="nc_1_cc" class="nc-cc"></div>
<i id="nc_1__voicebtn" tabindex="0" role="button" class="nc_voicebtn nc_iconfont" style="display:none"></i>
<b id="nc_1__helpbtn" class="nc_helpbtn"><span class="nc-lang-cnt" data-nc-lang="_learning">help</span></b>
</div>
MITHU
  • 113
  • 3
  • 12
  • 41
  • Other [action chain](https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains) abilities include mouse down (`click_and_hold()`), mouse move (`move_by_offset()`), and mouse up (`release()`) actions. – Ouroborus Jun 30 '19 at 11:58
  • Is it possible to share the test user name and password for login. – supputuri Jul 04 '19 at 04:00
  • Perhaps you could provide a url to an website I can work with and assure a working solution? – ch0wner Jul 05 '19 at 23:39
  • Never shows the slider for me :( – Ardesco Jul 08 '19 at 10:37
  • That slider shows up when you execute the script couple of times in a row @Ardesco. – MITHU Jul 08 '19 at 11:00
  • I must have run through this about 70~ times now, sometimes with up to 5 threads in parallel and I'm still not getting the slider. There must be something specific you are doing that is triggering additional verification, or you are really hammering the server. – Ardesco Jul 09 '19 at 12:37

3 Answers3

7

I'm unable to get the slider to display on the website linked in the question, so I have provided a solution using another site that has a slider element (I'm assuming the functionality is similar to the one on the aliexpress website).

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait

# Instantiate objects
driver = webdriver.Chrome()
actions = ActionChains(driver)

# Load page and fill in input elements
driver.get("http://kthornbloom.com/slidetosubmit/")
driver.find_element(By.NAME, "name").send_keys("Fred")
driver.find_element(By.NAME, "email").send_keys("fred@example.com")

# Find slider elements
slider_container = driver.find_element(By.CSS_SELECTOR, ".slide-submit")
slider = driver.find_element(By.CSS_SELECTOR, ".slide-submit-thumb")

# Perform sliding action
actions.move_to_element(slider).click_and_hold().move_by_offset(slider_container.size['width'], 0).release().perform()

# Browser intentionally left open so that you can see what happened when the test was run!

The key part here, is the Perform sliding action line. We have to identify two specific elements:

  1. The element that we are going to slide
  2. The container that holds this element

Once we have found both of these elements, we use the actions class to click and hold the element we need to slide and then we slide it the width of the containing element along the x axis (as shown using slider_container.size['width']), without changing the y axis.

This should fix your sliding problem, however you will have another problem, you need to work out if the slider was displayed, or you were logged into the website. To do that you are going to need an Expected condition that checks for the existence of 2 elements:

  1. The slider.
  2. An element you would expect to see when you have successfully logged in.

If the element you would expect to see when you log in is shown, you don't need to do anything. If the slider is shown, you will need to perform the above logic to slide the bar across.

*Edit*

To improve on this a bit more you can put the sliding code into an ExpectedCondition like so:

class wait_for_element_while_verifying_slider(object):

    def __init__(self, locator, slider_container_locator, slider_locator):
        self.locator = locator
        self.slider_container_locator = slider_container_locator
        self.slider_locator = slider_locator

    def __call__(self, _driver):
        try:
            return _driver.find_element(*self.locator)
        except (NoSuchElementException, StaleElementReferenceException):
            container = _driver.find_elements(*self.slider_container_locator)
            slider = _driver.find_elements(*self.slider_locator)
            if len(container) > 0 and len(slider) > 0:
                actions = ActionChains(_driver)
                actions.move_to_element(slider[0]).click_and_hold().move_by_offset(container[0].size['width'], 0).release().perform()

        return False

This will search for an element that you expect to be shown when you log in. If the element that you would expect to see when you have successfully logged in is not shown, it will then try and locate the slider elements and interact with them to process the slide verification. Note that once it tries to perform the slide verification the Expected Condition will return False which will force it to check to see if the expected logged in element is displayed again.

You can use it in your code like this:

# Instantiate objects
driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)

# Load page and fill in input elements
driver.get("http://kthornbloom.com/slidetosubmit/")
driver.find_element(By.NAME, "name").send_keys("Fred")
driver.find_element(By.NAME, "email").send_keys("fred@example.com")

# Define slider elements and element that will be shown when you successfully log in
SLIDER_CONTAINER = (By.CSS_SELECTOR, ".slide-submit")
SLIDER = (By.CSS_SELECTOR, ".slide-submit-thumb")
ELEMENT_TO_FIND = (By.XPATH, "//div[.=\"Looks Like You're Human!\"]")

# Invoke the explicit wait that will deal with the slider if it is displayed
wait.until(wait_for_element_while_verifying_slider(ELEMENT_TO_FIND, SLIDER_CONTAINER, SLIDER))

The example above uses the same example website as above. To make it timeout you can change ELEMENT_TO_FIND to something that doesn't exist. To make it pass without sliding you can modify ELEMENT_TO_FIND to be:

ELEMENT_TO_FIND = (By.XPATH, "//div[.=\"Slide To Submit\"]")

Using the code you have provided in your comment I would expect the following to work on the aliexpress website:

# Define slider elements and element that will be shown when you successfully log in
SLIDER_CONTAINER = (By.CSS_SELECTOR, ".nc-lang-cnt")
SLIDER = (By.CSS_SELECTOR, ".nc_wrapper .btn_slide")
ELEMENT_TO_FIND = (By.ID, "search-key")

# Invoke the explicit wait that will deal with the slider if it is displayed
wait.until(wait_for_element_while_verifying_slider(ELEMENT_TO_FIND, SLIDER_CONTAINER, SLIDER))
Ardesco
  • 7,281
  • 26
  • 49
  • Question updated to try and help you out with that. You could probably make it cleaner still, but I'll leave that up to you :) – Ardesco Jul 10 '19 at 15:58
1

Try using Actions Below is c# code for reference

//following code will click and hold the slider
string Xpath=""; //set xpath for desired element to be click and hold
Actions clickHold = new Actions(driver);
IWebElement element = driver.FindElement(By.XPath(Xpath));
clickHold.ClickAndHold(element).Perform();

once you have held on slider try to move it to the desired offset value

int x = 100; 
int y = 100;
Actions moveOffset = new Actions(driver);
moveOffset.MoveByOffset(x,y).Perform(); //set your suitable (x,y) offset value
Krunal Patel
  • 257
  • 3
  • 10
1

The sample code (in java) for slider operation from left to right is below.

Actions slider=new Actions(driver);
slider.clickAndHold("xpath of slider");
slider.movebyoffset(x,y).build.perform(); 

in place of 'x' &'y' you can give actual offset value as per your application.

Navsony
  • 21
  • 3