Python webdriver switch from main window to popup screen (not Java alert) and login - webdriver

Here is the window I need to enter new password and repeat it again and click 'create'.
My code so far:
createLogin = wait.until(EC.presence_of_element_located((By.XPATH, '//*[#id="Item.MessageUniqueBody"]/div/div/div/div/div[2]/div[2]/a')))
createLogin.click()
time.sleep(10)
try:
newPassword = self.driver.find_elements_by_xpath('//*[#id="editNewUser_newPassword"]')
newPassword1 = self.driver.find_elements_by_xpath('//*[#id="editNewUser_newPasswordRepeat"]')
newPasswordForm = self.driver.find_elements_by_xpath('//*[#id="editNewUserPasswordForm"]/table/tbody/tr[1]/td[1]')
self.driver.switch_to.active_element(newPasswordForm)
time.sleep(3)
newPassword.send_keys('123')
newPassword1.send_keys('123')
time.sleep(2)
# createLog = wait.until(
# EC.presence_of_element_located((By.XPATH, '//*[#id="editNewUserPassword_save"]')))
# createLog.click()
# time.sleep(5)
except NoAlertPresentException as e:
time.sleep(2)
myAccount = wait.until(
EC.presence_of_element_located((By.XPATH, '//*[#id="easMyAccount1"]')))
myAccount.click()
time.sleep(5)

This is the problem.
You are using find_elements_by_xpath rather than find_element_by_xpath
plural vs singular.
find_elements_by_xpath: it gives you a list of web elements with matching identifier.
find_element_by_xpath: it gives you a first web element with matching identifier.
newPassword = self.driver.find_element_by_xpath('//*[#id="editNewUser_newPassword"]')
newPassword1 = self.driver.find_element_by_xpath('//*[#id="editNewUser_newPasswordRepeat"]')
newPasswordForm = self.driver.find_element_by_xpath('//*[#id="editNewUserPasswordForm"]/table/tbody/tr[1]/td[1]')

#gauurang Answer is right, But You have to used find_element_by_xpath, also as your xpath suggested you have id to locate the webelements so it is always better to use id over xpath
Also your xpath are correct
newPassword = self.driver.find_element_by_id('editNewUser_newPassword')
newPassword1 = self.driver.find_element_by_id('editNewUser_newPasswordRepeat')
newPasswordForm = self.driver.find_element_by_xpath('//*[#id="editNewUserPasswordForm"]/table/tbody/tr[1]/td[1]')

Related

django-tables2: linkify, how to make target new window

Using the linkfy argument as so:
def linkify_sale(**kwargs):
record = kwargs.get("record")
if record:
return f"https://...url...#{record.get('order_sale_id')}"
class ASA_Journal_ViewTable(tables.Table):
...
order_sale_nbr = tables.Column(verbose_name="Sales Order Number", linkify=linkify_sale)
works. But how to I specify a target on the link, to open in a new window?
ok, like this
order_sale_nbr = tables.Column(verbose_name="Sales Order Number", linkify=linkify_sale, attrs={"a":{
"target":"_blank"}})

How to build a simple widget or app in jupyter notebook/lab to interactively extract a substring from text?

I want iterate over a list of string, output the string as plain text in jupyter lab then interactively highlight a substring to get easily the start index of the substring and the length. The goal is to do a quick annotation of text and get the coordinates of the substring.
Is it easy or even possible to do something like this with jupyter notebook (lab)? If then How?
I had a look at ipywidgets but couldn't find something for this use case.
Here's an example with the RangeSlider:
import ipywidgets
input_string = 'averylongstring'
widg = ipywidgets.IntRangeSlider(
value = [0, len(input_string)],
min=0, max=len(input_string)
)
output_widg = ipywidgets.Text()
display(widg)
display(output_widg)
def chomp_string(widg):
start,end = tuple(widg['new'])
output_widg.value = input_string[start: end]
widg.observe(chomp_string, names='value')
You can implement this using jp_proxy_widgets. See the following screenshot:
Note that there are warnings about compatibility for selection protocols -- I only tested this on Chrome on a Mac. Also I don't know why the indices are off by one
(select_callback(startOffset+1, endOffset+1);)
Please see https://github.com/AaronWatters/jp_proxy_widget for more information
Edit: Here is the pastable text as requested:
import jp_proxy_widget
select_widget = jp_proxy_widget.JSProxyWidget()
txt = """
Never gonna give you up.
Never gonna let you down.
Never gonna run around and
desert you.
"""
selected_text = None
def select_callback(startOffset, endOffset):
global selected_text
selected_text = txt[startOffset: endOffset]
print ("Selected", startOffset, endOffset, repr(selected_text))
select_widget.js_init("""
// (Javascript) Add a text area.
element.empty()
$("<h3>please select text:</h3>").appendTo(element);
var textarea = $('<textarea cols="50" rows="5">' + txt + "</textarea>").appendTo(element);
// Attach a select handler that calls back to select_callback.
var select_handler = function(event) {;
var target = event.target;
var startOffset = target.selectionStart;
var endOffset = target.selectionEnd;
select_callback(startOffset+1, endOffset+1);
};
textarea[0].addEventListener('select', select_handler);
""", txt=txt, select_callback=select_callback)
# display the widget
select_widget.debugging_display()

Unable to scrape all photos even after using selenium to automate scroll

I am a newbie to web scraping. I am currently working on a project where I want to scrape all the photos of an instagram user. The user has 521 posts in total due to which I had used selenium to scroll down till the bottom of the profile. But I am still able to scrape only the first 37 photos. After further inspecting, I found that as the browser scrolls up or down, only the first few rows of img tags are visible in the source code. As I scroll more, the previously visible img tags disappear and only the next rows are visible. So only a certain no. of rows are visible in the html code at any instant. I doubt it to be the reason why I am able to scrape only the first 37 photos.
I want to know how I can scrape all the photos of the profile. Below I have mentioned my current code using Beautiful Soup and Selenium. Here, "scroll_down" function uses selenium to scroll down till the bottom of the profile. I am trying to scrape all the 'img' tags in the function "downloading_images", but as already mentioned, I am able to scrape only first 37 photos.
def downloading_images(self):
soup = BeautifulSoup(self.driver.page_source,'html.parser')
self.all_images = soup.findAll('img')
print(len(self.all_images))
for index,image in enumerate(self.all_images):
filename = "image_" + str(index) + ".jpg"
image_path = os.path.join(self.path,filename)
link = image['src']
print("Downloading image ", index)
response = requests.get(link,stream = True)
try:
with open(image_path,'wb') as file:
shutil.copyfileobj(response.raw,file)
except Exception as e:
print(e)
print('Could not download image no.', index)
print('Image link',link)
def scroll_down(self):
sleep(3)
try:
num_posts = self.driver.find_element_by_xpath('//span[text()[contains(.," posts")]]/span[#class="g47SY "]')
str_num_posts = str(num_posts.text).replace(',','')
self.int_num_posts = int(str_num_posts)
if self.int_num_posts > 12:
num_scrolls = int(self.int_num_posts/12) + 3
print(num_scrolls)
sleep(3)
try:
for win in range(num_scrolls):
print(win)
self.driver.execute_script('window.scrollTo(0,document.body.scrollHeight);')
sleep(3)
except Exception as e:
self.error = True
print(e)
except Exception as e:
self.error = True
print(e)
I searched for all relevant questions here, but none of them could help me understand how I can fetch those images from the code which keeps disappearing upon scrolling.
Hope my question is clear. Thanks in advance.
Edit: Ok, I tried to scrape upon every scroll and it seems to work. Here is my new code.
def downloading_images(self):
print(len(self.all_images))
for index,image in enumerate(self.all_images):
filename = "image_" + str(index) + ".jpg"
image_path = os.path.join(self.path,filename)
link = image['src']
print("Downloading image ", index)
response = requests.get(link,stream = True)
try:
with open(image_path,'wb') as file:
shutil.copyfileobj(response.raw,file)
except Exception as e:
print(e)
print('Could not download image no.', index)
print('Image link',link)
def scroll_down(self):
sleep(3)
try:
num_posts = self.driver.find_element_by_xpath('//span[text()[contains(.," posts")]]/span[#class="g47SY "]')
str_num_posts = str(num_posts.text).replace(',','')
self.int_num_posts = int(str_num_posts)
if self.int_num_posts > 12:
num_scrolls = int(self.int_num_posts/12) + 1
else:
num_scrolls = self.int_num_posts
print(num_scrolls)
sleep(3)
try:
soup = BeautifulSoup(self.driver.page_source,'html.parser')
images = soup.findAll('img')
self.all_images = images
last_height = self.driver.execute_script("return document.body.scrollHeight")
for win in range(num_scrolls):
print(win)
self.driver.execute_script('window.scrollTo(0,document.body.scrollHeight);')
sleep(3)
new_height = self.driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
soup = BeautifulSoup(self.driver.page_source,'html.parser')
images = soup.findAll('img')
self.all_images.extend(images[-12:])
last_height = new_height
print(len(self.all_images))
except Exception as e:
self.error = True
print(e)
except Exception as e:
self.error = True
print(e)
def search_target(self):
try:
search_bar = self.driver.find_element_by_xpath('//input[#class="XTCLo x3qfX "]')
search_bar.send_keys(self.target_username)
taget_profile_url = self.main_url + '/' + self.target_username + '/'
self.driver.get(taget_profile_url)
except Exception as e:
self.error = True
print(e)
def close_notify_box(self):
try:
sleep(3)
not_now_button = self.driver.find_element_by_xpath('//button[#class="aOOlW HoLwm "]')
not_now_button.click()
except Exception:
pass
def log_in(self):
try:
log_in_button = self.driver.find_element_by_xpath('//p[#class="izU2O"]/a')
log_in_button.click()
sleep(3)
user_name_input = self.driver.find_element_by_xpath('//input[#aria-label="Phone number, username, or email"]')
user_name_input.send_keys(self.username)
password_input = self.driver.find_element_by_xpath('//input[#aria-label="Password"]')
password_input.send_keys(self.password)
password_input.submit()
except Exception as e:
self.error = True
print(e)
I would like to know if there are any alternative solutions to this. And whether it is an efficient solution. Thank you.

xpages view panel display computed icon

I'm trying to display an icon in a view panel based on a column value. This page will display if I only display the column value and/or use a static database image. If however I try to compute the image based on the column value I get an Http Code 500 error. Looking at the error-log I see two errors, the first is CLFAD0211E: Exception thrown and the second CLFAD0246E: Exception occurred servicing request for .
I have reviewed this simple explanation on how to add a dynamic icon (https://www.youtube.com/watch?v=27MvLDx9X34) and other similar articles and still not working. Below is the code for the computed icon.
var urlFull:XSPUrl = new XSPURL(database.getHttpURL());
var url = urlFull.getHost();
var path = "/icons/vwicn";
// var idx = rowData.getColumnValues().get(1); Removed for testing
var idx = "82.0"; //Hard coded the value for testing
if (idx < 10){
path += ("00" + idx).left(3);
}else if (idx < 100){
path += ("0" + idx).left(3);
}else {
path += idx.left(3);
}
path += ".gif";
//path = "/icons/vwicn082.gif"; I have also tried hard coding the path value - still a no go
url = setPath(path);
url.removeAllParameters();
return url.toString();
The view panel is configured as xp:viewPanel rows="40" id="viewPanel1" var="rowData".
Any suggestions on what to look for or a better option to compute a view panel icon would be appreciated.
Cheers!!!
You have a typo: url = setPath(path);should be url.setPath(path);

Conditional classname and text (Rails)

I'm pretty new to Rails and trying some basic stuff like conditional classes.
On the 'show' view I have an element that changes styling depending on the stock availability, but also the text changes accordingly.
People keep saying the controller should be as small as possible, but placing this conditional in the view also feels dirty. Is this really the best way?
Current controller:
def show
#tyre = Tyres::Tyre.find_by_id(params[:id])
if #tyre.in_stock
#availability = I18n.t("products.filter.other.in_stock")
#availability_class = 'i-check-circle color--success'
else
#availability = I18n.t("products.filter.other.not_in_stock")
#availability_class = 'i-cross-circle color--important'
end
end
Edit:
Controller:
def show
#tyre = Tyres::Tyre.find_by_id(params[:id])
if #tyre.in_stock
#availability_append = ".in_stock"
else
#availability_append = ".not_in_stock"
end
#availability = I18n.t("products.filter.other#{#availability_append}")
end
View:
.xs-12.description__status
%i{class: (#tyre.in_stock? ? 'i-check-circle color--success' : 'i-cross-circle color--important')}
= #availability
You can clean your controller tyres_controller.rb (i suppose) method,
def show
#tyre = Tyre.find(params[:id]) # I believe you have a model named 'tyre'
end
Then, there will be a file named tyres_helper.rb in your myproject/app/helpers/. Put the following code there,
def tyre_availability(tyre) # it'll return an array with two values, first one is class name, second one is localized value
if tyre.in_stock
return 'i-check-circle color--success', I18n.t("products.filter.other.in_stock")
else
return 'i-cross-circle color--important', I18n.t("products.filter.other.not_in_stock")
end
end
and, in the view you can use,
.xs-12.description__status
%i{:class => tyre_availability(#tyre)[0]}
= tyre_availability(#tyre)[1]

Resources