ElementNotInteractableException python selenium - python-3.x

buttonfinal = driver.find_element(
By.CSS_SELECTOR,
"button[class = '_2SQ6OPS1CO _3iCncfMaN4'").click()
I tried multiple solutions to click the button but still can't find the solution.
HTML CODE
<button type="submit" class="_2SQ6OPS1CO _3iCncfMaN4"><div class="">Registrati</div></button>

If you only have a single submit button, do this:
button_final = driver.find_element(By.CSS, 'button[type="submit"]')
button_final.click()
If you have multiple buttons with the same class, try this:
button_final = driver.find_element(By.Xpath, 'button[contains(text(), "Registratin")]')
button_final.click()
Tell me if this worked for you or not

Related

Is there a way to refresh HTML dom when Selenium cannot locate an element?

I'm attempting to submit a login form using Selenium and Chromedriver. The form contains a username field, a password field, a checkbox and a log in button. I am able to enter the username, enter the password, and check the checkbox. But I haven't been able to figure out how to click the log in button.
When a user clicks through the form, upon checking the checkbox, the content of the HTML of the Log In button changes from...
<button tabindex="4" step="1" type="submit"
class="btn-primary login disable login-disabled"
id="login-submit" disabled="">Log In</button>
... to:
<button tabindex="4" step="1" type="submit"
class="btn-primary login"
id="login-submit">Log In</button>
This same behavior (the removal of the disable and login-disabled classes) occurs when my script clicks the captcha checkbox.
Here is the problematic code, where I've attempted to handle all possible locator handlers, but have still been unable to locate the button element:
def try_click_with_all_locator_strategies(id=None, xpath=None, link_text=None, partial_link_text=None, name=None, tag_name=None, class_name=None, css_selector=None):
by_fields = []
by_fields.append((By.ID, id)) if id else None
by_fields.append((By.XPATH, xpath)) if xpath else None
by_fields.append((By.LINK_TEXT, link_text)) if link_text else None
by_fields.append((By.PARTIAL_LINK_TEXT, partial_link_text)) if partial_link_text else None
by_fields.append((By.NAME, name)) if name else None
by_fields.append((By.TAG_NAME, tag_name)) if tag_name else None
by_fields.append((By.CLASS_NAME, class_name)) if class_name else None
by_fields.append((By.CSS_SELECTOR, css_selector)) if css_selector else None
found = False
for (by_key, by_value) in by_fields:
try:
time.sleep(0.5)
driver.implicitly_wait(10)
element = driver.find_element(by=by_key, value=by_value)
element.click()
found = True
except NoSuchElementException:
print('unable to find via', by_value)
if not found:
print('Unable to find using any locator strategy')
try_click_with_all_locator_strategies(
id="#login-submit",
xpath="/html/body/div[5]/div[1]/div/div[1]/div/form/button",
link_text='Log In',
class_name="btn-primary",
css_selector="#login-submit"
)
Any help or ideas would be appreciated!
Aha! It turned out the answer was related to frames. To troubleshoot, I ended up printing out all the IDs on the page (referenced Python & Selenium - how do I find all element IDs on a page?), and that ended up printing only a few of the ids that it should have. It turned out that when I clicked the checkbox, it had modified the current frame.
To solve this I just needed to switch out and get to the main frame, then proceed.
driver.switch_to.parent_frame()

IPython.display not showing TextBox in ipywidgets

I'm trying to build such a functionality such that whenever the user clicks in the Add button in my code, it generates a new text box, just under the old one. For example, like this:
Now, if the user were to click on add once again, a 5th text box should appear.
I've tried to achieve the same using this piece of code:
add_button = widgets.Button(description='Add',
disabled=False,
button_style='',
style={'description_width': 'initial', 'button_width': 'auto'},
icon='plus'
)
display(add_button)
add_button.on_click(add_new)
And my add_new function is simply defined as follows:
def add_new(*args):
display(widgets.Text(placeholder='Type something',description='String:'))
But this does not seem to be working nothing happens on clicking the button, any help would be appreciated. Also if there is a better way to do this, please help, I'm new to ipywidgets.
Try like this:
output = widgets.Output()
def add_new(*args):
with output:
display(widgets.Text(placeholder='Type something',description='String:'))
add_button = widgets.Button(description='Add',
disabled=False,
button_style='',
style={'description_width': 'initial', 'button_width': 'auto'},
icon='plus'
)
display(add_button)
add_button.on_click(add_new)
output

python selenium the wait.to_be_clickable() method cannot be clicked immediately

I am writing a test script to click buttons that are dynamically inserted using ajax. However, after the script use the wait.element_to_be_clickable method, the final element turned out to be not able to be clicked.
The code looks something like this:
element1 = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,"#element_1")))
element2 = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,"#element_2")))
element3 = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,"#element_3")))
element4 = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR,"#element_4")))
elements =[element1,element2,element3,element4]
for element in elements:
element.click()
submit_button = wait.until(EC..element_to_be_clickable((By.CSS_SELECTOR,"#element_5")))
submit_button.click()
The terminal jumped out an error message, saying that:
selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element <input id="fsSubmitButton3988487" class="fsSubmitButton" style="" type="submit" value="Submit Form"> is not clickable at point (509, 688). Other element would receive the click: <b>...</b>
I tried using the debugger to run through the script, and it works.
I also tried adding
time.sleep(2)
before the last line of code, and it also worked.
Why is the first method not working?
Element is located but Click is being intercepted, it happens when there pop up look for popup or some notification bar that is blocking the click...

Python Selenium: Select input with dynamic id in form

I want to make a Python program with Selenium to fill out a form. Part of the process involves filling out a title. I used xpath to find the input associated with title, but then found out that it only works sometimes because its id is dynamic and keeps changing. Here is the html code associated with the title input box:
<div class='g5ia77ul buofh1pr d2edcug0 l9j0dhe7'>
<span class="m9osqain t5a262vz a8c37x1j b5fwa0m2 jagab5yi knj5qynh fo6rh5oj d2edcug0 ni8dbmo4 stjgntxs hzruof5a pmk7jnqg re5koujm ltmttdrg fgv6swy9 dd2scrzq ms05siws flx89l3n b7h9ocf4 g0qnabr5">Title</span>
<input dir="auto" aria-invalid="false" id="jsc_c_6" class="oajrlxb2 rq0escxv f1sip0of hidtqoto lzcic4wl g5ia77u1 gcieejh5 bn081pho humdl8nn izx4hr6d oo9gr5id qc3s4z1d knj5qynh fo6rh5oj osnr6wyh hv4rvrfc dati1w0a p0x8y401 k4urcfbm iu8raji3" type="text" value="">
</div>
Other boxes in the form have similar id, they all seem to start with "jsc_c_" like "jsc_c_a" or "jsc_c_8". Here is a picture of what part of the form looks like:
[][1
This is some of the code I have tried to select the title box:
titlePath = '//*[#id="jsc_c_6"]'
titleText = 'myTitle'
titleBox = driver.find_element_by_xpath(titlePath)
titleBox.send_keys(titleText)
I think that perhaps I could select the title input box by checking for the presence of the text "Title" in the box. However, I am not sure how this can be done. Any help or suggestions would be greatly appreciated.
Probably you can give it a try with
//span[text()='Title']/following-sibling::input

How to click "Next" button until it no longer exists - Python, Selenium, Requests

I am scraping data from a webpage that is paginated, and once I finish scraping one page, I need to click the next button and continue scraping the next page. I then need to stop once I have scraped all of the pages and a next button no longer exists. Below contains the html around the "Next" button that I need to click.
<tr align="center">
<td colspan="8" bgcolor="#FFFFFF">
<br>
<span class="paging">
<b> -- Page 1 of 3 -- </b>
</span>
<p>
<span class="paging">
<a href="page=100155&by=state&state=AL&pagenum=2"> .
<b>Next -></b>
</a>
</span>
<span class="paging">
Last ->>
</span>
</p>
</td>
</tr>
I have tried selecting on class and on link text, and both have not worked for me in my current attempts.
2 examples of my code:
while True:
try:
link = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.LINK_TEXT, "Next ->"))).click()
except TimeoutException:
break
while True:
try:
link = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CLASS_NAME, "paging"))).click()
except TimeoutException:
break
All of the solutions I have found online have not worked, and have primarily ended with the following error:
ElementClickInterceptedException: Message: element click
intercepted: Element <a href="?
page=100155&by=state&state=AL&pagenum=2">...</a> is not
clickable at point (119, 840). Other element would receive the
click: <body class="custom-background hfeed" style="position:
relative; min-height: 100%; top: 0px;">...</body>
(Session info: chrome=76.0.3809.132)
If the remainder of the error code would be helpful to review, please let me know and I will update the post with this error.
I have looked at the following resources, all to no avail:
Python Selenium clicking next button until the end
python - How to click "next" in Selenium until it's no longer available?
Python Selenium Click Next Button
Python Selenium clicking next button until the end
Selenium clicking next button programmatically until the last page
How can I make Selenium click on the "Next" button until it is no longer possible?
Could anyone provide suggestions on how I can select the "Next" button (if it exists) and go to the next page with this set of HTML? Please let me know if you need any further clarification on the request.
We can approach this problem through the solution using two major libraries - selenium and requests.
Approach - Scrape the page for page number and next page link every time
Using Selenium (If the site is Dynamic)
We can check if the page we are on is the last page or not, and if it is not the last page, we can check for the next button (assuming the website follows the same html structure for paging in all pages)
stop = False
driver.get(url)
while not stop:
paging_elements = driver.find_elements_by_class_name("paging")
page_numbers = paging_elements[0].text.strip(" -- ").split("of")
## Getting the current page number and the final page number
final = int(page_numbers[1].strip())
current = int(page_numbers[0].split("Page")[-1].strip())
if current==final:
stop=True
else:
next_page_link = paging_elements[-2].find_element_by_name("a").get_attribute('href')
driver.get(next_page_link)
time.sleep(5) # This gap can be changed as per the load time of the page
Using Requests and BS4 (If the site is static)
import requests
r = requests.get(url)
stop = False
while not stop:
soup = BeautifulSoup(r.text, 'html.parser')
paging_elements = soup.find_all('span', attrs={'class': "paging"})
page_numbers = paging_elements[0].text.strip(" -- ").split("of")
## Getting the current page number and the final page number
final = int(page_numbers[1].strip())
current = int(page_numbers[0].split("Page")[-1].strip())
if current==final:
stop=True
else:
next_page_link = paging_elements[-2].find("a").get('href')
r = request.get(next_page_link)
Alternative approaches
One method is using the URL of the website itself instead of the button-clicking process as the button click is intercepted in this case.
Most web pages have a page attribute added to their URL (visible for pages >=2). So, a paginated website might have URLs such as:
www.targetwebsite.com/category?page_num=1
www.targetwebsite.com/category?page_num=2
www.targetwebsite.com/category?page_num=3
and so on.
In such cases, one can simply iterate over the page numbers until the final page number (as originally out in the proposed answer). This approach eliminates the breakage possibility of the target website changing CSS layout/style.
Furthermore, there might be a requirement to create the next_page_link by appending the base URL as done for next_url in the other question (line 40-41):
next_url = next_link.find("a").get("href")
r = session.get("https://reverb.com/marketplace" + next_url)
I hope this helps!
It sounds like you're asking two different questions here:
How to click Next button until it no longer exists
How to click Next button with Javascript.
Here's a solution to #2 -- Javascript clicking:
public static void ExecuteJavaScriptClickButton(this IWebDriver driver, IWebElement element)
{
((IJavaScriptExecutor) driver).ExecuteScript("arguments[0].click();", element);
}
In the above code, you have to cast your WebDriver instance as IJavascriptExecutor, which allows you to run JS code through Selenium. The parameter element is the element you wish to click -- in this case, the Next button.
Based on your code sample, your Javascript click may look something like this:
var nextButton = driver.findElement(By.LINK_TEXT, "Next ->"));
driver.ExecuteJavascriptClickButton(nextButton);
Now, moving onto your other issue -- clicking until the button is no longer visible. I would implement this in a while loop that breaks whenever the Next button no longer exists. I also recommend implementing a function that can check the presence of the Next button, and ignore the ElementNotFound or NoSuchElement exception in case the button does not exist, to avoid breaking your test. Here's a sample that includes an ElementExists implementation:
public bool ElementExists(this IWebDriver driver, By by)
{
// attempt to find the element -- return true if we find it
try
{
return driver.findElements(by).Count > 0;
}
// catch exception where we did not find the element -- return false
catch (Exception e)
{
return false;
}
}
public void ClickNextUntilInvisible()
{
while (driver.ElementExists(By.LINK_TEXT, "Next ->"))
{
// find next button inside while loop so it does not go stale
var nextButton = driver.findElement(By.LINK_TEXT, "Next ->"));
// click next button using javascript
driver.ExecuteJavascriptClickButton(nextButton);
}
}
This while loop checks for the presence of the Next button with each iteration. If the button does not exist, the loop breaks. Inside the loop, we call driver.findElement with each successive click, so that we do not get a StaleElementReferenceException.
Hope this helps.

Resources