Python to click a button/link in JavaScript - python-3.x

I want to show more page by click a button to run a JavaScript function as below:
<div class="loading" style="display:none;">
<p class="btn blue"><span>さらに表示</span></p>
</div>
I tried the code, it doesn't work, what can I do?
more_info_button = driver.find_element_by_tag_name('a').get('href=javascript:void(0);')
more_info_button.click()

If you want to click link that contains attribute #href equal to "javascript:void(0);", try
more_info_button = driver.find_element_by_xpath('//a[#href="javascript:void(0);"]')
more_info_button.click()
Same with CSS selector:
more_info_button = driver.find_element_by_css_selector('a[href="javascript:void(0);"]')
To locate link by text in preceding paragraph:
more_info_button = driver.find_element_by_xpath('//a[preceding-sibling::p[.="さらに表示"]]')
Update
Try below code to get extended topics list after clicking the button:
from selenium.webdriver.support.ui import WebDriverWait
topics_number = len(driver.find_elements_by_class_name('topics'))
more_info_button.click()
WebDriverWait(driver, 10).until(lambda driver: len(driver.find_elements_by_class_name('topics')) > topics_number)
extended_list = driver.find_elements_by_class_name('topics')

Related

ElementNotInteractableException: Message: element not interactable: [object HTMLDivElement] has no size and location error using Selenium and Python

I am trying to click show results button after selecting filter on linkedin. I have correctly found the button element but it is giving me this error:
selenium.common.exceptions.ElementNotInteractableException: Message: element not interactable: [object HTMLDivElement] has no size and location
Here is my piece of code that I have tried:
element = WebDriverWait(self, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div[class="artdeco-hoverable-content__shell"]')))
box = self.find_element_by_css_selector('div[class="artdeco-hoverable-content__shell"]')
ele = box.find_element_by_css_selector('button[data-control-name="filter_show_results"]')
ActionChains(self).move_to_element(ele).click(ele).perform()
I have also tried:
self.execute_script("arguments[0].click();", ele)
What's the reason behind this?
HTML of the results button:
<div class="reusable-search-filters-buttons display-flex justify-flex-end mt3 ph2">
<button data-test-reusables-filter-cancel-button="true" data-control-name="filter_pill_cancel" aria-label="Cancel Locations filter" id="ember429" class="artdeco-button artdeco-button--muted artdeco-button--2 artdeco-button--tertiary ember-view" type="button"><!---->
<span class="artdeco-button__text">
Cancel
</span></button>
<button data-test-reusables-filter-apply-button="true" data-control-name="filter_show_results" aria-label="Apply current filter to show results" id="ember430" class="artdeco-button artdeco-button--2 artdeco-button--primary ember-view ml2" type="button"><!---->
<span class="artdeco-button__text">
Show results
</span></button>
</div>
Edit 2: Here is the image of the button , I am trying to click.
https://ibb.co/4Y7VN0j
Edit 3: Image with dev tools open : https://ibb.co/CJdtNM1
The desired element is a Ember.js enabled element, so to click on the Show results button instead of presence_of_element_located() you need to induce WebDriverWait for the element_to_be_clickable() and you can use either of the following locator strategies:
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-control-name='filter_show_results'][aria-label='Apply current filter to show results'] span.artdeco-button__text"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//button[#data-control-name='filter_show_results' and #aria-label='Apply current filter to show results']//span[contains(., 'Show results')]"))).click()
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

Using Selenium and Python to Click on a button below searched element

I am trying to test downloading a file from a website using selenium on python.
The website has peculiar design where the file name appears as a text element above the button to download the file. There are no specific names or IDs for these buttons. And they are not known to us. So, I can't specify the ID or element name in the code directly.
Here is the HTML snippet:
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 noborderBottom semiBolder-label ">
<span data-bind="text: jurisdictionName, attr: { id: jurisdictionId() + '-guides' }, visible: showInList" id="67-guides">Greece</span>
</div>
<div class="clearfix visible-xs"></div>
<div class="col-xs-6 col-sm-6 col-md-5 col-lg-5 text-center">
<div class="greenPDFIcon cursorPointer align-center" data-bind="event: { click: onHighlightClick.bind($data) }, style: { 'visibility': highLightUrl() ? 'visible' : 'hidden' }" style="visibility: visible;"></div>
<span class="taxGuidesText lg-visible md-visible xs-visible" data-bind="style: { 'visibility': highLightUrl() ? 'visible' : 'hidden' }" style="visibility: visible;">Highlights</span>
<!--<span class="taxGuidesText lg-visible md-visible xs-visible" data-bind="visible:showInList">Highlights</span>-->
</div>
Now, I first need to search for the text "Greece" in the above example.
Get it's location on the webpage:
class="col-xs-12 col-sm-12 col-md-12 col-lg-12 noborderBottom semiBolder-label"
Locate the button right below this text - so in the above example that gives me:
class="col-xs-6 col-sm-6 col-md-5 col-lg-5"
And then click on the button:
class="greenPDFIcon cursorPointer align-center"
The thing is, I do not know this "Greece". That comes through input parameter.
I only know that if the input parameter text is found on the webpage, the button will be right below it. And I have to click it to open the pdf file.
How to do that using selenium on python?
So far I have reached:
s=Service(r"driver_path")
browser = webdriver.Edge(service=s)
browser.get('webpage_url')
country = input('Enter a country name: ')
Also, suggest if I should use anything else rather than selenium to do this, as I understand this is more of web-scrapping than automated testing. I also tried beautifulsoup, but the website is not accessible directly through api. Browser access is required.
To locate the element with the country name e.g. Greece and click on the respective element with text as Highlights you can use the following Locator Strategies:
Using XPATH and "Old Style" String Formatting (% Operator):
browser.get('webpage_url')
country = input('Enter a country name: ')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[contains(#class, 'semiBolder-label')]//span[contains(., '%s')]//following::div[2]//span[contains(., 'Highlights')]" % country))).click()
Using XPATH and "New Style" String Formatting (str.format):
browser.get('webpage_url')
country = input('Enter a country name: ')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[contains(#class, 'semiBolder-label')]//span[contains(., '{}')]//following::div[2]//span[contains(., 'Highlights')]".format(country)))).click()
Using XPATH and String Interpolation / f-Strings (Python 3.6+):
browser.get('webpage_url')
country = input('Enter a country name: ')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, f"//div[contains(#class, 'semiBolder-label')]//span[contains(., '{country}')]//following::div[2]//span[contains(., 'Highlights')]"))).click()
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

How to Click Link Being Covered by Another Element? Python 3.6 and Selenium

Having trouble figuring out how to click the Next button at the bottom of the table on this page:
https://www.zacks.com/stocks/industry-rank/reit-and-equity-trust-other-266/stocks-in-industry
This is what I've tried:
from bs4 import BeautifulSoup
import requests
import csv, random, time
from pandas.io.html import read_html
from selenium import webdriver
from selenium.webdriver.support.ui import Select
url = 'https://www.zacks.com/stocks/industry-rank/reit-and-equity-trust-other-266/stocks-in-industry'
# Open Chrome
driver = webdriver.Chrome()
# Send Chrome to the URL
page = driver.get(url)
# Wait for page to load a few seconds
timeDelay = random.randrange(4, 8)
time.sleep(timeDelay)
# Try to click the darn button
element = driver.find_element_by_xpath('//*[#id="industry_rank_table_next"]')
driver.execute_script("arguments[0].click();", element)
...and
element = driver.find_element_by_xpath('//*[#id="industry_rank_table_next"]')
element.send_keys("\n")
...found from other answers but not working for me. Simply using .click() does not work. I've also tried selecting the button using css_selector, partial_link_text, and class_name but still no success. I've ran into this on a few sites. Any ideas?
To click() on the element with text as Next you have to induce WebDriverWait for the element to be clickable and you can use either of the following solutions:
Using LINK_TEXT:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.LINK_TEXT, "Next"))).click()
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.paginate_button next#industry_rank_table_next"))).click()
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[#class='paginate_button next' and #id='industry_rank_table_next']"))).click()
Note : You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
if the element which you have to click have parent element then you can find parent by findElements method and after than you just need to pass the index of the element like 0 or 1 or so on.. and then you can perform click action on that
Want to click on third li from second ul:
<ul id="select-123" style="width: 1180px; display: none;">
<li class="" style="display:none;">
<li class="">
<li class="">
<li class="">
</ul>
<ul id="select-123" style="width: 1180px; display: none;">
<li class="" style="display:none;">
<li class="">
<li class="">
<li class="">
</ul>
Code I am trying is to select third li from second ul which does not work:
driver.findElements(By.css(ul[id*='select-123'])).then(function(elems) {
elems[2].then(function(lis) {
driver.findElement(By.css("ul[id*='select-123'] li:nth-child(3)")).click();
});
});
Another way if you don't wish to add additional wait(s) to your code and just click the button:
using javascript click:
element = driver.find_element_by_xpath("//a[#class='paginate_button next' and #id='industry_rank_table_next']")
driver.execute_script("arguments[0].click();", element)
UPDATE:
I didn't notice this earlier, but
element = driver.find_element_by_xpath('//*[#id="industry_rank_table_next"]')
driver.execute_script("arguments[0].click();", element)
...works as it clicks the link successfully, but gives me a
selenium.common.exceptions.WebDriverException: Message: unknown error: call function result missing 'value'
...error after it clicks the link. So to get around this, I've just added a try/except to handle the error. ie:
try:
element = driver.find_element_by_xpath('//*[#id="industry_rank_table_next"]')
driver.execute_script("arguments[0].click();", element)
except:
pass
...which seems to work. Seems like such a stupid observation on my part, but thank you to everyone for your help. Hopefully something in here will help someone else in the future.

Python Selenium can't select dropdown (chrome webdriver)

I have a dropdown element, I want to select the All option, the corresponding HTML code is:
<div class="dataTables_length" id="indicators_length">
<label>
<span class="result-mune">
<span>Results </span>per page:
</span>
<select name="indicators_length" aria-controls="indicators" class="jcf-hidden">
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
<option value="200">200</option>
<option value="-1">All</option>
</select>
<span class="jcf-select jcf-unselectable">
<span class="jcf-select-text">
<span class="">25</span>
</span>
<span class="jcf-select-opener"></span>
</span>
</label>
</div>
the select element is not highlighted using the browser Inspect method, looks like this drop down is triggered by js.
I tried to use the Select class described here:
select = Select(self._wait.until(EC.presence_of_element_located_by((By.XPATH, "//div[#id = 'indicators_length']//select[#name = 'indicators_length']")))
select.select_by_value('-1')
not working. and ActionChain method and even execute_script method, all not working. This bothers me a lot, hope somebody can help.
you don't really need to select the option just click the span and it will set the option automatically.
driver = webdriver.Chrome()
driver.get("......")
# click "OK, I Agree" cookies
driver.find_element_by_css_selector('.agree-button.eu-cookie-compliance-default-button').click()
# scroll down to make dropdown option visible
driver.find_element_by_css_selector('h4.pane-title').location_once_scrolled_into_view
select = driver.find_element_by_xpath('//span[#class="result-mune"]/following-sibling::span')
select.click()
# wait until javascript generate fake option element because it actually span
time.sleep(1)
select.find_element_by_css_selector('ul li span[data-index="4"]').click()
try this one:
driver.execute_script('document.getElementsByName("indicators_length")[0].value = 50;
If its created and loaded after page load make sure you add some sleep to let it render;
I tried using the Selenium Select class, it can find the element but it cannot select an option from the element. Not sure whats going on, could be the class "jcf-hidden" on the element.
Having said that, I took a stab at it and below is my approach. Try it out, it worked on my system, you have to handle the clicking of "OK, I Agree" button click, I did that manually.
import time
from selenium.webdriver import Chrome
driver = Chrome()
driver.get('https://www.topuniversities.com/university-rankings/world-university-rankings/2019')
# Remove this nasty time.sleep and implement webdriver wait
# Handle the OK, I Agree
time.sleep(5)
i_agree = driver.find_element_by_css_selector('button[class*="eu-cookie-compliance-default-button"]')
i_agree.click()
time.sleep(5)
# Open the Select
rankings_length = driver.find_element_by_id('qs-rankings_length')
select_opener = rankings_length.find_element_by_class_name('jcf-select-opener')
select_opener.click()
# loop through the list
select_content = rankings_length.find_element_by_class_name('jcf-list-content')
for content in select_content.find_elements_by_tag_name('li'):
if content.text == 'All':
content.click()

How to replace selected string from content editable div?

I'm trying to replace chapter titles from the contenteditable="true" div tag by using python and selenium-webdriver, at first I am searching for the chapter title, which is usually at first line... then I'm replacing it with empty value and saving.. but it's not saving after refreshing browser. But I see that code is working. Here is my code
##getting content editable div tag
input_field = driver.find_element_by_css_selector('.trumbowyg-editor')
### getting innerHTML of content editable div
chapter_html = input_field.get_attribute('innerHTML')
chapter_content = input_field.get_attribute('innerHTML')
if re.search('<\w*>', chapter_html):
chapter_content = re.split('<\w*>|</\w*>', chapter_html)
first_chapter = chapter_content[1]
### replacing first_chapter with ''
chapter_replace = chapter_html.replace(first_chapter, '')
### writing back innerHTML without first_chapter string
driver.execute_script("arguments[0].innerHTML = arguments[1];",input_field, chapter_replace)
time.sleep(1)
## click on save button
driver.find_element_by_css_selector('.btn.save-button').click()
How I can handle this ? It is working when I'm doing manually(I mean it probably can't be site problem/bug)... Please help ...
Relevant HTML is following:
<div class="trumbowyg-editor" dir="ltr" contenteditable="true">
<p>Chapter 1</p>
<p> There is some text</p>
<p> There is some text</p>
<p> There is some text</p>
</div>
As per the HTML you have shared to replace the chapter title with empty value you have to induce WebDriverWait with expected_conditions clause set to visibility_of_element_located and can use the following block of code :
page_number = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.XPATH, "//div[#class='trumbowyg-editor' and #contenteditable='true']/p[contains(.,'Chapter')]")))
driver.execute_script("arguments[0].removeAttribute('innerHTML')", page_number)
#or
driver.execute_script("arguments[0].removeAttribute('innerText')", page_number)
#or
driver.execute_script("arguments[0].removeAttribute('textContent')", page_number)

Resources