Selenium Python I am getting an empty string from a text element but there is a value on the GUI - python-2.7

I have some text displayed on the GUI. I have identified the element using it's XPATH from Xpath Checker from Firebug. The element highlights correctly.
In my code i use the text attribute to to print out it's value.
I would like to print the value to the console.
When i walk through the code using PyCharm debugger I can see the variable text attribute is empty.
Why has the variable not got the text value?
My code snippet is:
def is_engine_number_displayed(self):
engine_no_element = self.get_element(By.XPATH, '//a[contains(., "Engine: 5.1.1")]')
print "engine_no_element.text***"
print engine_no_element.text
#return engine_no_element.text in "Engine: 5.1.1"
The HTML is:
<div class="GJPPK2LBKQ">
<a class="gwt-Anchor GJPPK2LBMQ" title="Click for about">Client: 5.1.1.6044</a>
<a class="gwt-Anchor GJPPK2LBMQ" title="Click for about">Engine: 5.1.1.5218</a>
My XPATH to locate the text Engine: 5.1.1
//a[contains(., "Engine: 5.1.1")]
Using the XPATH the text Engine: 5.1.1 is highlighted on the GUI
get_element is in my Base class. It's implementation is:
# returns the element if found
def get_element(self, how, what):
# params how: By locator type
# params what: locator value
try:
element = self.driver.find_element(by=how, value=what)
except NoSuchElementException, e:
print what
print "Element not found "
print e
screenshot_name = how + what + get_datetime_now() # create screenshot name of the name of the element + locator + todays date time. This way the screenshot name will be unique and be able to save
self.save_screenshot(screenshot_name)
raise
return element
Why is my element text value empty?
Thanks,
Riaz

I have encountered this problem when I tried to verify the population of text fields after a selection is made from a dropdown. As you mentioned, the texts are indeed there, but selenium thinks they are empty. If memory serves, it was because the form had not been submitted yet, and I believe the value attribute (not the text attribute) is where the getText() function actually pulls its data. The value attribute does not get set until later. Take a look at the elements' value attribute after you submit the page, and I believe those values will be set, and the getText() will return the correct text values. I was not able to find a work-around, since upon the user clicking the submit button, it was proceeding to the next web page.

Related

Oracle Apex How to display page item as url

I have a page item which stores URL.
How do i change its type to URL so that the link becomes clickable.
As of now, there is page subtype url, but setting it doesn't make any difference.
Apex 21.1
A text field is an html input element, that will display text only, you probably could write some javascript to open whatever is in the page item in an url but that is confusing functionality. What should happen if the user clicks in the input element ? Should it open the link or should the user be editing the value ?
This is a possibility.
Create a page item on your page, say P1_URL
Add the following in the "Post Text" attribute of the page item (style it to your own preference):
<span class="fa fa-external-link" aria-hidden="true"></span>
Add a dynamic action on change of the element P1_URL with a true action of "Execute Javascript Code" and the following code:
$("#myurl").attr("href", apex.item( "P13_URL" ).getValue())
Check "Fire on Initialization" for the true action.
That is all there is to it, now when you add something in the page item P1_URL and click the link, it will open the that url in a new window.
UPDATE: Technique for read only text field.
For a read only text field, the input element is hidden and an additional span element is rendered with an the page item name as id, suffixed by _DISPLAY. The trick is to grab the content of that span element and add an anchor with attributes. This can be done with an onload dynamic action:
Create a page item on your page, say P1_URL, set it to "Read-Only: Always"
Add a dynamic action on Page Load with a true action of "Execute Javascript Code" and the following code:
let itemVal = $("#P1_URL_DISPLAY").text()
$("#PP1_URL_DISPLAY").html(`<a href='${itemVal}' target='_blank'>${itemVal}</a>`)
Make sure that when you copy this, the quotes are exactly the same: the outer quotes are backticks, those are needed for the ES6 syntax.
Note: check the page documentation for the subtype url - it explains exactly what it does.

Extract the HTML from between two HTML tags in BeautifulSoup 4.6

I want to get the HTML between two tags with bs4. Is there a way to do javascript's .innerHTML in Beautiful Soup?
This is code that finds a span with the class "title", and gets the text out of it.
def get_title(soup):
title = soup.find('span', {'class': 'title'})
return title.text.encode('utf-8')
This function incorrectly returns the text of the span without the subscripts. 'Title about H2O and CO2'
The following code is the result of title = soup.find('span', {'class': 'title'}):
<span class="title">Title about H<sub>2</sub>O and CO<sub>2</sub></span>
How do I get the result without the original span?
Desired result: 'Title about H<sub>2</sub>O and CO<sub>2</sub>'?
After finding out that JavaScript has .innerHTML, I was able to google the way to do it in beautiful soup. I found the answer in this question.
After selecting the element with BS4, you can use .decode_contents(formmater='html') to get the innerHTML.
element.decode_contents(formatter="html")

Finding xpath siblings after declaring a variable with find_elements

I start by trying to find all menu items on a site by selecting them with a .find_elements_by_xpath. This works fine
(The buttons are either text or an image).
Then I want to loop through each of these elements and return either the text between the tags or the src of the image of a span tag which preceeds the tag inbetween which there is text.
Returning the text works fine but I am unable to return the src. I am having trouble building an xpath which roots from the current iteration of the loop. What I am left with is either an 'unable to locate' or I return the first menu image over and over again.
Here is the code I currently have running (note I am unable to give out the URL to the site):
browser = webdriver.Chrome(...)
menu = browser.find_elements_by_xpath('//td[#onmouseover]')
for menu_part in menu:
try:
if len(menu_part.text) < 2:
menu_button = menu_part.find_element_by_xpath(
'/span[#class="ThemeOfficeMainFolderText"]/preceding-sibling::span/img').get_attribute('src')
else:
menu_button = menu_part.text
print menu_button
except Exception as e:
print e
pass
I am unsure if the syntax is completely correct/ if I can use the currently iterated element as the 'root' of my find_element function (menu_part.find_element_by_xpath)
Also, there is no way to further specify the tags with attributes because all menu items have identical attributes.
Lastly, the following code returns the first image in the menu.
menu_button = browser.find_element_by_xpath(
'//span[#class="ThemeOfficeMainFolderText"]/preceding-sibling::span/img').get_attribute('src')
Therfore, I am relatively confident the code following "span[#class... " works fine, the issue is the preceding code.
I am hopeful that there is a simple solution and that I made a mistake while writing the xpath, but I am completely out of ideas at the moment...
EDIT:
here is the basic html structure I am dealing with
<td class="ThemeOfficeMainItem" onmouseover="ItemMouseOverOpenSub ()">
<span class="ThemeOfficeMainFolderLeft">
<img src="img1.png"></span>
<span class="ThemeOfficeMainFolderText">TEXT</span>
<span class="ThemeOfficeMainFolderRight"> </span>
</td>
<td class="ThemeOfficeMainItem" onmouseover="ItemMouseOverOpenSub ()">
<span class="ThemeOfficeMainFolderLeft">
<img src="img2.png"></span>
<span class="ThemeOfficeMainFolderText"></span>
<span class="ThemeOfficeMainFolderRight"> </span>
</td>
If you want to search for span starting from previously defined parent element menu_part, then you should use
./span[#class="ThemeOfficeMainFolderText"]/preceding-sibling::span/img
Note the dot at the beginning of XPath that points to current (menu_part) element
Update
As for the logic of your code, try below:
browser = webdriver.Chrome()
browser.get(URL)
menu = browser.find_elements_by_xpath('//td[#onmouseover]')
for menu_part in menu:
text_span = menu_part.find_element_by_xpath('./span[#class="ThemeOfficeMainFolderText"]')
if not text_span.text:
menu_button = menu_part.find_element_by_xpath('./span[#class="ThemeOfficeMainFolderText"]/preceding-sibling::span/img').get_attribute('src')
else:
menu_button = text_span.text
print menu_button

Scraperwiki scrape query: using lxml to extract links

I suspect this is a trivial query but hope someone can help me with a query I've got using lxml in a scraper I'm trying to build.
https://scraperwiki.com/scrapers/thisisscraper/
I'm working line-by-line through the tutorial 3 and have got so far with trying to extract the next page link. I can use cssselect to identify the link, but I can't work out how to isolate just the href attribute rather than the whole anchor tag.
Can anyone help?
def scrape_and_look_for_next_link(url):
html = scraperwiki.scrape(url)
print html
root = lxml.html.fromstring(html) #turn the HTML into lxml object
scrape_page(root)
next_link = root.cssselect('ol.pagination li a')[-1]
attribute = lxml.html.tostring(next_link)
attribute = lxml.html.fromstring(attribute)
#works up until this point
attribute = attribute.xpath('/#href')
attribute = lxml.etree.tostring(attribute)
print attribute
CSS selectors can select elements that have an href attribute with eg. a[href] but they can not extract the attribute value by themselves.
Once you have the element from cssselect, you can use next_link.get('href') to get the value of the attribute.
link = link.attrib['href']
should work

How can I display extra details in the autosuggest, but only ID in the input field?

I'm using a ColdFusion autosuggest for my UserID field. When a user starts to type in a UserID, a list of user ids and the user names associated with it pop up (populated by a cfc function). Sample code:
<cfinput name="userID" type="text" value="#userID#" autoSuggest="cfc:Utilities.suggestUser({cfautosuggestvalue})" matchcontains="true" />
The suggestions are listed in the format "User Name <userID>". So if the user would start typing 123, a sample suggestion that would pop up would be "Harvey Mann <1234>".
The problem is that if the user chooses that suggestion, I don't want to insert the whole suggested text into the input field - I just want to insert the user id ("1234" in this case). I would also like to be able to insert the user name ("Harvey Mann") into an adjacent field/area if possible. Is there any way to accomplish this?
Since you are using CF's built-in implementation of autosuggest, you are stuck with only having access to one returned value. Thus if the value consists of mutliple 'parts' and you want to insert different 'parts' of the value into different columns, you will have to parse the value and extract appropriate parts from the string. In your example case you could treat the value as a list delimited by <. In this case you can get the name 'part' with
trim(listfirst(form.userID, "<"))
and the id 'part' with
replace(listlast(form.userID, "<"), ">", "")
Alternatively, you can always use jQuery UI Autocomplete implementation - you'll have to write your own javascript for it, but it gives you far more control than the built-in cf's implementation. Check jQuery UI docs for more info: http://jqueryui.com/demos/autocomplete/
UPDATE:
On second thought, if you just want to display selected value's 'name' part in another area on the same page, you may be able to do it using just CF's built-in autosuggest and a bit of javascript. Try adding this code to the HEAD section of your page:
<cfajaxproxy bind="javaScript:showName({userID})">
<script type="text/javascript">
showName = function(strUserId) {
document.getElementById("someID").innerHTML = strUserId.split('<')[0];
}
</script>