Using Python/Selenium to select checkboxes from an angular website - python

Here's the angular source
Trying to create a simple script that checks/unchecks some boxes with python/selenium.
I've thrown what little book I have at it and can't get it to correctly identify the elements. I've tried (likely incorrectly) css, xpath, label, text.
Any help would be greatly appreciated.
Code trial:
driver.find_elements_by_class_name('list-group-items')[1].click()
HTML:
<div class="col-sm-12">
<fieldset>
<legend>
Step 2: Choose Data fields
</legend>
<div class="col-sm-5 col-lg-4">
<div class="panel minimal minimal-gray">
<div class="panel-title">
<h4>
Standard Fields:
</h4>
</div>
<ul class="list-group scrollable ng-scope" id="standard-fields" ng-class="{error: ctrl.export.errors.columns}">
<!-- ngRepeat: item in ctrl.exportFormats.columns track by item.code --><li ng-repeat="item in ctrl.exportFormats.columns track by item.code" class="list-group-item ng-binding ng-scope list-group-item-success" ng-class="{'list-group-item-success' : item.checked}">
<input type="checkbox" ng-model="item.checked" class="ng-pristine ng-untouched ng-valid">
Date
</li><!-- end ngRepeat: item in ctrl.exportFormats.columns track by item.code --><li ng-repeat="item in ctrl.exportFormats.columns track by item.code" class="list-group-item ng-binding ng-scope list-group-item-success" ng-class="{'list-group-item-success' : item.checked}">
<input type="checkbox" ng-model="item.checked" class="ng-pristine ng-untouched ng-valid">
Time
</li><!-- end ngRepeat: item in ctrl.exportFormats.columns track by item.code --><li ng-repeat="item in ctrl.exportFormats.columns track by item.code" class="list-group-item ng-binding ng-scope list-group-item-success" ng-class="{'list-group-item-success' : item.checked}">

Seems you were pretty close. As per your code trials instead of find_elements_by_class_name('list-group-items')[1], using find_element_by_class_name('list-group-item') would have taken you more closer.
However, as the desired elements are Angular elements so to click the checkboxes associated with the texts e.g. Date, Time etc, you have to induce WebDriverWait for the element to be clickable and you can use either of the following solutions:
Date:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//li[#class='list-group-item ng-binding ng-scope list-group-item-success' and contains(#ng-repeat,'exportFormats')][contains(.,'Date')]/input[#class='ng-pristine ng-untouched ng-valid']"))).click()
Time:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//li[#class='list-group-item ng-binding ng-scope list-group-item-success' and contains(#ng-repeat,'exportFormats')][contains(.,'Time')]/input[#class='ng-pristine ng-untouched ng-valid']"))).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

Related

Click on every element in the catalog with Python + selenium

I only started to study python. I have a problem with my code. I use Python + selenium and I don’t understand how I can click on the first element in this code, then go to products__item, after that return back to catalog and click on the second element, then on the third element using selenium.
This is code from a typical internet shop. I understand I need to use a cycle “for” for it but how to do it I don’t know.
<div class="products__list" style="position: relative">
<div class=" products__item ">
<a href="/catalog/dveri-mezhkomnatnyye/dveri-ekoshpon/bravo/bravo-21-snow-art" class="card">
<div class="card__title"> Product-1 </div>
<div class="card__color"> Snow Art </div>
<div class="card__img"> <div class="card__img-wrapper"> <img src="/storage/products/small/60fa84e2b06096.72907873.jpg"> </div>
<div class="card__img-wrapper"> </div>
<div class=" products__item ">
<a href="/catalog/dveri-mezhkomnatnyye/dveri-ekoshpon/bravo/bravo-21-snow" class="card">
<div class="card__title"> Product-2 </div>
<div class="card__color"> Snow </div>
<div class="card__img"> <div class="card__img-wrapper"> <img src="/storage/products/small/60fa84e2b06096.72907874.jpg"> </div>
<div class="card__img-wrapper"> </div>
<div class=" products__item ">
<a href="/catalog/dveri-mezhkomnatnyye/dveri-ekoshpon/bravo/bravo-21-snow-art-classic" class="card">
<div class="card__title"> Product-3 </div>
<div class="card__color"> Snow Art Classic </div>
<div class="card__img"> <div class="card__img-wrapper"> <img src="/storage/products/small/60fa84e2b06096.72907875.jpg"> </div>
<div class="card__img-wrapper"> </div>
Hope it helps!
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
import time
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome('path/to/chromedriver')
driver.get("https://dveri.com/catalog/dveri-mezhkomnatnyye?page=1")
wait = WebDriverWait(driver, 10)
elements_xpath = '//div[#class=" products__item "]/a[#class="card"]'
# Wait for emelents to load
wait.until(EC.element_to_be_clickable((By.XPATH, elements_xpath)))
num_elements = len(driver.find_elements(By.XPATH, elements_xpath))
ac = ActionChains(driver)
for i in range(num_elements):
# Wait until elements are clickable
wait.until(EC.element_to_be_clickable((By.XPATH, elements_xpath)))
# Get all elements and select only the i-th one
element = driver.find_elements(By.XPATH, elements_xpath)[i]
# Click the element with the offset from center to actually go to the other page
ac.move_to_element(element).move_by_offset(0, 100).click().perform()
# Here do whatever has to be done on a specific webpage
time.sleep(1)
# Go back to the previous page
driver.execute_script("window.history.go(-1)")

Web Scraping error in while using Search.submit()

I am trying to do web scraping to weather data from:
https://www.wunderground.com/history/daily/us/dc/washington/KDCA
Here is HTML:
<div _ngcontent-app-root-c136="" id="wuForm" class="ui-front wu-form">
<div _ngcontent-app-root-c136="" id="wuSearch-contain" class="wu-search-contain ng-star-inserted"><label _ngcontent-app-root-c136="" for="wuSearch" class="visuallyHidden">Search</label><input _ngcontent-app-root-c136="" type="search" name="query" value="" id="wuSearch" placeholder="Search Locations" aria-label="Search" autocomplete="off" class="wu-search ng-untouched ng-pristine ng-valid"><span _ngcontent-app-root-c136="" class="close-search"><i _ngcontent-app-root-c136="" class="material-icons">close</i></span><span _ngcontent-app-root-c136="" class="geolocate-wrap"><i _ngcontent-app-root-c136="" class="material-icons">gps_fixed</i></span></div>
<!----><!---->
<search-autocomplete _ngcontent-app-root-c136="" _nghost-app-root-c135="">
<ul _ngcontent-app-root-c135="" tabindex="0" class="ui-autocomplete ui-front ui-menu ui-widget ui-widget-content ui-corner-all hide">
<li _ngcontent-app-root-c135="" class="ui-autocomplete-geolocate ng-star-inserted">
<div _ngcontent-app-root-c135="" class="mimic-a menu-geolocate"><i _ngcontent-app-root-c135="" class="material-icons">gps_fixed</i>Find Nearest Station </div>
</li>
<!----><!----><!----><!----><!----><!---->
<li _ngcontent-app-root-c135="" class="ui-autocomplete-last ui-menu-item manage-favorites"><a _ngcontent-app-root-c135="" tabindex="-1" href="/member/favorites" class="ui-corner-all">Manage Favorite Cities</a></li>
</ul>
</search-autocomplete>
</div>
I started with
driver = webdriver.Chrome(r'C:\Users\bno00\Downloads\chromedriver_win32\chromedriver.exe')
driver.get('https://www.wunderground.com/history/daily/us/dc/washington/KDCA')
and it's working fine
then when I trying to send zipcode to search field by using .submit():
zipcode='22202'
xpath='//*[#id="wuSearch"]'
search=driver.find_element_by_xpath(xpath)
search.clear()
search.send_keys(zipcode)
search.submit() #error occurs here
The error is:
NoSuchElementException: Message: no such element: Unable to locate
element:{"method":"xpath","selector":"./ancestor-or-self::form"}
(Session info: chrome=89.0.4389.114)
That <input> tag is not part of a form. You can't submit it. You either need to send a newline, or click the gps_fixed icon that triggers the search.
Try using the following:
input_field = driver.find_element_by_css_selector("input[id=wuSearch]")
input_field.click()
input_field.send_keys("some zip code")
Or just:
input_field = driver.find_element_by_id("wuSearch")
input_field.send_keys("some zip code")
Try to avoid click(). I am not sure it is really required.
After you input a zip code, you should wait for your search result to appear.
wait = WebDriverWait(driver, 10)
driver.get('https://www.wunderground.com/history/daily/us/dc/washington/KDCA')
zipcode='22202'
xpath='//*[#id="wuSearch"]'
search=wait.until(EC.element_to_be_clickable((By.XPATH,xpath)))
search.clear()
search.send_keys(zipcode)
time.sleep(1)
search.send_keys(Keys.ENTER)
Just delay it a bit. Use a webdriver wait to make sure you send the zipcode to the input and then send Keys.Enter.
Import
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.keys import Keys
from time import sleep

Finding related fields / iterating through Selenium browser results

I am trying to iterate through a set of results, similar to the below, so to select that I perform the below:
for a in browser.find_elements_by_css_selector(".inner-row"):
What I then want to do is return:
a. The x in the class next to time-x (e.g. 26940 in the example)
b. filter to bananas only
c. Grab the suffix to "row-x" in the id
For each result. I can then iterate through the results for each of these that meets the parameters.
I have tried the get attribute function but this doesn't return any results, and .text is out of the question due to no real information between the tags.
<div id="bookingResults bookingGroup-111">
<div id="row-1522076067"
class="row row-time group-111 time-26940 amOnly bananas groupOnly rule-1252"
style="display: block;">
<div class="lockOverlay lock-row-124" style="display: none;"><div class="lockInfoCont"><p class="lockedText">Locked <span class="miclub-icon icon-lock"></span></p></div><div class="lockTimer"></div></div>
<div class="col-lg-3 col-md-4 col-sm-4 col-xs-4 row-heading " id="heading-1522076067" >
<div class="row">
<div class="col-lg-4 col-md-4 col-sm-5 col-xs-5 row-heading-inner">
<h3>07:29 am</h3>
<h4>
Choose Me
<br/>
<span id="rule-name-row-1522076067" style="display: none">
</span>
</h4>
</div>
<div class="col-lg-8 col-md-8 col-sm-7 col-xs-7 row-heading-inner">
<button id="btn-book-group-1522076067"
class="btn btn-book-group hide"
title="Book Row" >
<span class="btn-label">BOOK GROUP</span>
</button>
<div class="row-information">
</div>
</div>
</div>
</div>
I guess this html is the each of the a in your code then you can exract the id and time with following code:
for a in browser.find_elements_by_css_selector(".inner-row"):
try:
el = a.find_element_by_css_selector("div.bananas")
print("id: %s", el.get_attribute("id").split("-")[1])
print("time: %s", [s for s in el.get_attribute("class")(" ") if "time-" in s][0].split("time-")[1])
except NoSuchElementException as e:
pass
You can get the ids like so
print([e.get_attribute('id') for e in driver.find_elements(By.CSS_SELECTOR, 'div.bananas')])
Prints ['row-1522076067']
To handle dynamic element Induce WebDriverWait() and wait for visibility_of_all_elements_located() and following css selector.
Then use regular expression to get the value from element attribute.
Code
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import re
driver=webdriver.Chrome()
driver.get("URL here")
elements=WebDriverWait(driver,10).until(EC.visibility_of_all_elements_located((By.CSS_SELECTOR,"div[id^='bookingResults']>div.bananas")))
for element in elements:
print(re.findall("row-(\d+)",element.get_attribute("id"))[0])
classatr=element.get_attribute("class")
print(re.findall("time-(\d+)",classatr)[0])

How to click on a Radio Button as per the HTML using Selenium and Python

I am trying to click on element with following html code:
<div class="delivery-pseudo-table">
<div class=" i-popup-lk user-address" id="userAddress">
<div class="address-container">
<div class="titlebar">
<h1 class="title"></h1>
</div>
<div id="userAddressContent"></div>
</div>
<div class="hide j-map map" id="addressMap"></div>
<div class="hide j-map-pickpoint postamat-map" id="pickpointMap"></div>
<div class="added-addres-loader"></div>
</div>
<ul class="delivery-method" data-jsv-df=""><li class="selfDelivery selectDeliveryWay active" data-jsv="#34_#35_" title="">
<script type="jsv#37_"></script>
<label><input autocomplete="off" checked="checked" data-id="2" name="orderDetails.DeliveryWay_q" type="radio" value="Self"/>Самовывоз</label>
<script type="jsv/37_"></script>
</li><li class="courierDelivery selectDeliveryWay" data-jsv="/35_#38_" title="">
<script type="jsv#39_"></script>
<label><input autocomplete="off" data-id="1" name="orderDetails.DeliveryWay_q" type="radio" value="Courier"/>Доставка курьером</label>
<script type="jsv/39_"></script>
</li><li class="wbpostamatDelivery selectDeliveryWay" data-jsv="/38_#40_" title="">
<script type="jsv#41_"></script>
<label><input autocomplete="off" data-id="16" name="orderDetails.DeliveryWay_q" type="radio" value="WbPostamat"/>Постамат</label>
<script type="jsv/41_"></script>
</li></ul>
I need to click on button with value "Courier"
And I am trying to do it with following Python code:
elem = browser.find_element_by_css_selector("input[type='radio'][#value='Courier']")
elem.click()
(I've also tried to find by xpath)
But it says that the element is invisible. Are the any ways to click on such element?
Try to use this xPath:
//input[#type='radio' and #value='Courier']
also try to use WebDriverWait:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//input[#type='radio' and #value='Courier']"))).click()
Note: you have to add some imports:
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.by import By
WebDriverWait statement is for waiting at least 10 seconds until element will be clickable and only then clicks on it.
PS: more information about WebDriverWait can be found here.
EDIT: try to execute JavaScript:
radio_btn = driver.find_element_by_xpath("//input[#type='radio' and #value='Courier']")
driver.execute_script("arguments[0].click();", radio_btn)
As per the HTML you have shared the <ul> tag contains a lot of JavaScripts so to invoke click() on the desired element you have to induce WebDriverWait for the element to be clickable and you can use either of the following solutions:
CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "ul.delivery-method li.courierDelivery.selectDeliveryWay input[value='Courier']"))).click()
XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//ul[#class='delivery-method']//li[#class='courierDelivery selectDeliveryWay']//input[#value='Courier']"))).click()

NoSuchElementException in Selenium Webdriver in python

div class="row-fluid">
<div id="sfx" class="span12">
<ui-view>
<div class="row-fluid fa-rep-nav">
<div id="test"></div>
<div class="row-fluid">
<div id="sfx" class="span12">
<ui-view>
<div class="row-fluid">
<div class="span12">
<div class="ledger-btn-block clearfix">
<form class="ng-pristine ng-valid" name="reportGenForm">
<span class="input-append ledger-date-block fa-block-pull-left">
<label class="ledger-label">Select‌·Report:‌· </label>
<select class="select_report_type ng-pristine ng-untouched ng-valid" ng-model="selectedReport" ng-options="str.name for str in reportType">
<label class="ledger-label"> ‌·Date‌·Range:‌· </label>
<input class="date-picker report-date-input ng-pristine ng-untouched ng-valid" date-range-picker="" readonly="" ng-model="sfxReportModel.date" options="selectedReport.opts" min="selectedReport.opts.minDate" max="selectedReport.opts.maxDate" type="text">
<i class="icon-calendar add-on no-border-radius"></i>
</span>
I have used all the method of locating an element which are applicable here. I have also used time.sleep() function so that the page on which I am locating element can load successfully before finding, but even then also location is not appearing.Here is the pic of html code. Highlighted is the one I want to locate.
I have used methods like find_element_by_xpath and find_by_class_name where i get xpath using Firebug but getting the same errorenter image description here. I need help in locating "select" tag.
As far as I understood you want to select the dropdown. Use the following code in python to select a dropdown value
from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_xpath("//select[#class='select_report_type ng-pristine ng-untouched ng-valid']"))
select.select_by_index(1)
// OR
select.select_by_visible_text("text")
// OR
select.select_by_value(value)
Let me know if still facing same issue or any further things

Categories