Variable/Changing ember number in Intercom HTML. Selenium Python - python

I am trying to automate some tasks at work. Requests wont work because I don't have admin access to my works Intercom App. Therefore I use Selenium.
I want to write "Hey" in the chat box of Intercom, and send the message.
** The problem is a changing ember number every time I have a new conversation. It works when I copy the right ember number every time, but when changing the conversation, it doesn't work anymore. **
I am looking for some kind of script to change the ember = XXXXX into the right number each time
Not really relevant to the code problem, but I am using Chrome in debugging mode, to avoid logging in every time I need to test the code, and I am using tkinter to have a button to press, every time I want to write "Hey" in the chat box.
Sorry, I understand it is difficult to replicate this problem.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
#___________
#In order to run Selenium in an already opened browser / session, I need to run this code in CMD:
#cd C:\Program Files (x86)\Google\Chrome\Application
#
#chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\Users\peter\testprogram"
#___________
opt=Options()
opt.add_experimental_option("debuggerAddress","localhost:9222")
driver=webdriver.Chrome(executable_path="
C:\\ProgramFiles\\crromedriver\\chromedriver.exe",options=opt)
def hey():
ember = 32890
hey = driver.find_element_by_xpath('//*[#id="ember'+str(ember)+'"]/div/div[3]/div[1]/div/p')
hey.send_keys("Hey!")
The specific HTML element where I want to write "Hey!": (This is under the big HTML code below)
<p class="intercom-interblocks-align-left embercom-prosemirror-composer-block-selected" style="">Hey! This is where I want my text</p>
One might suggest to use
hey = driver.find_element_by_class_name('intercom-interblocks-align-left embercom-prosemirror-composer-block-selected')
hey.send_keys("Hey!")
But this doesn't work for me.
The HTML element where the ember number is changing:
<div id="ember32890" class="u__relative inbox__conversation-composer__wrapper ember-view"><div>
<div></div>
<div>
</div>
<div data-test-prosemirror-composer="" class="composer-inbox composer-style-basic o__fit conversation__text embercom-prosemirror-composer ">
<style>
.ProseMirror {
outline: none;
white-space: pre-wrap;
}
.ProseMirror .intercom-interblocks-html-block {
white-space: normal;
}
li.ProseMirror-selectednode {
outline: none;
}
.ProseMirror-selectednode.embercom-prosemirror-composer-image img,
.ProseMirror-selectednode.embercom-prosemirror-composer-video iframe,
.ProseMirror-selectednode.embercom-prosemirror-composer-messenger-card
.intercom-interblocks-messenger-card,
.ProseMirror-selectednode.embercom-prosemirror-composer-html-block,
.ProseMirror-selectednode.embercom-prosemirror-composer-button .intercom-h2b-button {
outline: 2px solid #8cf;
}
hr.ProseMirror-selectednode,
.embercom-prosemirror-composer-template.ProseMirror-selectednode,
.embercom-prosemirror-composer-mention.ProseMirror-selectednode {
outline: 1px solid #8cf;
}
</style>
<div>
<!----><div contenteditable="true" role="textbox" dir="auto" data-insertable="true" class="ProseMirror embercom-prosemirror-composer-editor dir-auto"><p class="intercom-interblocks-align-left embercom-prosemirror-composer-block-selected" style="">Hey!Hey!Hey!Hey!Hey!</p><p class="intercom-interblocks-align-left" style=""><br></p></div></div>
<div class="flex flex-row flex-wrap gap-4 embercom-prosemirror-composer-attachment-list">
<!----></div>
<!---->
<!---->
<!---->
<!---->
<!---->
<div></div>
<!---->
<!----></div>
<!---->
<!----></div></div>

If you want to use ember here is a possible solution:
hey = driver.find_element_by_xpath('//*[contains(#id="ember")]/div/div[3]/div[1]/div/p')
hey.send_keys("Hey!")
This will probably fail if there are multiple elements with id="ember[0-9]+".
If you want to access the p tag directly use find_element_by_css_selector, like so:
hey = driver.find_element_by_css_selector('.intercom-interblocks-align-left.embercom-prosemirror-composer-block-selected')
hey.send_keys("Hey!")
Your code with find_element_by_class_name did not work because it's expecting one class name and you are passing two class names (class names are separated by space).

Related

Click event not happening in Python with Selenium web driver

Friends facing challenges again in following scenarios using Python with Selenium web driver:-
Click event not happening on clicking the link name as "Area Rank Web".
HTML Code for MSTR Report is as follows:-
<td class="mstrLargeIconViewItemText" rowspan="1" colspan="1" cx="[2,1,0,5,1,6,7]" cxid="folderAllModes_cmm" oid="600E4BA841AC84797221F7BB5262C3E0" oty="55"><a title="Run Document" class="mstrLargeIconViewItemLink" onclick="return submitLink(this, event);" href="Main.aspx?evt=2048001&src=Main.aspx.2048001&visMode=0&currentViewMedia=1&documentID=600E4BA841AC84797221F7BB5262C3E0" runasexpress="1" alt="Run Document"></a><div class="mstrLargeIconViewItemName"><span sty="nm"><a title="Area Rank Web" class="mstrLink" onclick="return submitLink(this, event);" href="Main.aspx?evt=2048001&src=Main.aspx.2048001&visMode=0&currentViewMedia=1&documentID=600E4BA841AC84797221F7BB5262C3E0" runasexpress="1">Area Rank Web</a></span></div><div class="mstrLargeIconViewItemOwner"><label>Owner:</label><span><div title="Administrator" class="owner">Administrator</div></span></div><div class="mstrLargeIconViewItemModified"><label>Modified:</label><span><div timestamp="1525148536000">5/1/18 4:22:16 AM</div></span></div><div class="mstrLargeIconViewItemDescription"></div><div></div><div class="mstrLargeIconViewItemActions"><span><a class="mstrLink" onclick="if (!mstrFolderActions.checkACL(this, event, '600E4BA841AC84797221F7BB5262C3E0', 55)) return; return submitLink(this, event);" href="Main.aspx?evt=3032&src=Main.aspx.3032&objectType_3032=55&objectID_3032=600E4BA841AC84797221F7BB5262C3E0" ty="sub">Subscriptions</a></span></div></td>
I tried following ways but not getting success:
#driver.find_element_by_xpath(".//*[title='Area Rank Web']").click();
#driver.find_elements_by_class_name (("mstrLargeIconViewItemName") and contains(.,'Area Rank Web')).click()
#driver.find_element_by_id("600E4BA841AC84797221F7BB5262C3E0").click()
#driver.find_element_by_css_selector("600E4BA841AC84797221F7BB5262C3E0").click()
#WebDriverWait(driver, 5).until(EC.element_to_be_clickable((By.XPATH, "//div[#class='mstrLargeIconViewItemText']/span[#class='mstrIcon-lg' and contains(.,'Area Rank Web')]"))).click()
2.
There is a block having two values as:- AREA, DISTRICT. You can select more than value and then click on arrow button which moves selected content to the right side of block and then click on submit button
HTML code:
<div title="AREA" class="mstrListBlockItemSelected" style="margin-top: 0px;"><div class="mstrBGIcon_ae mstrListBlockItemName" style="background-position: 2px 50%; padding-left: 23px;">DSI</div></div>
<div title="DISTRICT" class="mstrListBlockItem" style="margin-top: 0px;"><div class="mstrBGIcon_ae mstrListBlockItemName" style="background-position: 2px 50%; padding-left: 23px;">ONC</div></div>
Tried following ways but click event is not happening
Can you try link_text/ partial_link_text instead?
driver.find_element_by_link_text('Area Rank Web').click()
OR
driver.find_element_by_partial_link_text('Area Rank Web').click()
Also, try having an explicit wait before you click on the link.
WebDriverWait(self.driver, 10).until(expected_conditions.element_to_be_clickable(
(By.LINK_TEXT, 'Area Rank Web')
))
if all the above fails, use execute_script method to invoke a click event on the link
link = driver.find_element_by_link_text('Area Rank Web')
driver.execute_script('arguments[0].click();', link)

Selenium changing html on a page with python

<div id="modalContent" style="opacity: 1; top: 35%;">
</div>
Say I want to delete this on everytime I go to a particular website.
driver = webdriver.Chrome()
driver.get("some url")
#driver.removeelement("""<div id="modalContent" style="opacity: 1; top: 35%;">
#</div>""")
Is there a way to do this?
To do this, you should execute some javascript on the DOM element. Here is how I would do it.
driver.execute_script("document.getElementById('modalContent').remove()")
Should work.

Change Element Attribute Using XPATH / Send_Keys - Selenium Python

I am writing a program to gather data from a website, however at some point in the program I need to enter an email and password into text boxes. The route I am attempting to go is to use driver.execute_script to change the underlying HTML, however I am having difficulty connecting that command with the XPATH value that I use to find the element. I know there are a few threads on here that deal with similar issues, however I have been completely unable to find one that uses XPATH. Any help would be greatly appreciated as I am totally stuck here.
Below is the line of HTML that I am attempting to change, as well as the XPATH value associated with the text box.
XPATH Value
/html/body/center/div[4]/table[2]/tbody/tr/td[4]/table[1]/tbody/tr[2]/td/table/tbody/tr[7]/td[2]/font
HTML:
<input onclick="if (this.value == 'Enter Your Name') this.value='';" onchange="if (this.value == 'Enter Your Name') this.value='';" name="name" type="text" value="Enter Your Name" style="padding-top: 2px; padding-bottom: 6px; padding-left: 4px; padding-right: 4px; width:120px; height:15px; font-size:13px; color: #000000; font-family:Trebuchet MS; background:#FFFFFF; border:1px solid #000000;">
I am attempting to replace value = "Enter Your Name" with value = "Andrew" - or any other name for that matter. Thank you very much for any and all advice, and please let me know there is any additional data / info that is required.
Send_Keys scripts:
name = driver.find_element_by_xpath('//body/center/form/span/table/tbody/tr/td[1]/input')
name.clear()
name.send_keys("Andrew")
Your <input> tag is contained within an <iframe>, so you'll need to switch the context to the <iframe> first:
driver.switch_to.frame(driver.find_element_by_tag_name("iframe"))
Now that you're "inside" the <iframe>, your send_keys script should work:
name = driver.find_element_by_xpath('//body/center/form/span/table/tbody/tr/td[1]/input')
name.clear()
name.send_keys("Andrew")
Lastly, here's how to switch back to the default content (out of the <iframe>):
driver.switch_to.default_content()

Selenium Python, Find element Input box problems

I'm trying to automate some processes at work on our inventory site and I'm having trouble inputing text into a simple search box!
Here is the website code:
<td class="GJCH5BMASD" style="">
<input type="text" class="GJCH5BMD1C GJCH5BME1C" style="font-size: 13px; width: 100%;">
</td>
Here is my code:
opens = driver.find_element_by_css_selector(".GJCH5BMD1C GJCH5BME1C").click()
I keep receiving the error:
ElementNotVisibleException: Cannot click on element
Any thoughts?
Well nevermind!
I fixed it by changing:
opens = driver.find_element_by_css_selector(".GJCH5BMD1C GJCH5BME1C").click()
to:
opens = driver.find_element_by_css_selector(".GJCH5BMASD").click()
You need to provide . with every class name using css_selector, you can also try as below :-
opens = driver.find_element_by_css_selector(".GJCH5BMD1C.GJCH5BME1C").click()

Selenium - get all iframes in a page (even nested ones)?

I am trying to search through all the html of websites that I reach using selenium webdriver. In selenium, when I have an iframe, I must switch to the iframe and then switch back to the main html to search for other iframes.
However, with nested iframes, this can be quite complicated. I must switch to an iframe, search it for iframes, then switch to one iframe found, search IT for iframes, then to go to another iframe I must switch to the main frame, then have my path saved to switch back to where I was before, etc.
Unfortunately, many pages I've found have iframes within iframes within iframes (and so on).
Is there a simple algorithm for this? Or a better way of doing it?
Finding iframes solely by HTML element tag or attributes (including ID) appears to be unreliable.
On the other hand, recursively searching by iframe indexes works relatively fine.
def find_all_iframes(driver):
iframes = driver.find_elements_by_xpath("//iframe")
for index, iframe in enumerate(iframes):
# Your sweet business logic applied to iframe goes here.
driver.switch_to.frame(index)
find_all_iframes(driver)
driver.switch_to.parent_frame()
I was not able to find a website with several layers of nested frames to fully test this concept, but I was able to test it on a site with just one layer of nested frames. So, this might require a bit of debugging to deal with deeper nesting. Also, this code assumes that each of the iframes has a name attribute.
I believe that using a recursive function along these lines will solve the issue for you, and here's an example data structure to go along with it:
def frame_search(path):
framedict = {}
for child_frame in browser.find_elements_by_tag_name('frame'):
child_frame_name = child_frame.get_attribute('name')
framedict[child_frame_name] = {'framepath' : path, 'children' : {}}
xpath = '//frame[#name="{}"]'.format(child_frame_name)
browser.switch_to.frame(browser.find_element_by_xpath(xpath))
framedict[child_frame_name]['children'] = frame_search(framedict[child_frame_name]['framepath']+[child_frame_name])
...
do something involving this child_frame
...
browser.switch_to.default_content()
if len(framedict[child_frame_name]['framepath'])>0:
for parent in framedict[child_frame_name]['framepath']:
parent_xpath = '//frame[#name="{}"]'.format(parent)
browser.switch_to.frame(browser.find_element_by_xpath(parent_xpath))
return framedict
You'd kick it off by calling: frametree = iframe_search([]), and the framedict would end up looking something like this:
frametree =
{'child1' : 'framepath' : [], 'children' : {'child1.1' : 'framepath' : ['child1'], 'children' : {...etc}},
'child2' : 'framepath' : [], 'children' : {'child2.1' : 'framepath' : ['child2'], 'children' : {...etc}}}
A note: The reason that I wrote this to use attributes of the frames to identify them instead of just using the result of the find_elements method is that I've found in certain scenarios Selenium will throw a stale data exception after a page has been open for too long, and those responses are no longer useful. Obviously, the frame's attributes are not going to change, so it's a bit more stable to use the xpath. Hope this helps.
You can nest one iFrame into another iFrame by remembering the simple line of code to position, then re-position, the cursor back to the same area of the screen by using the as in the following COMPLETE code, remembering always to put the larger iFrame FIRST, then define the position of the SMALLER iFrame SECOND, as in the following FULL example:---
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Daneiella Oddie, Austrailian Ballet Dancer, dancing to Bach-Gounod's Ave Maria</title>
</head>
<body bgcolor="#ffffcc">
<DIV style="position: absolute; top:0px; left:0px; width:0px; height:0px"></div>
<DIV style="position: absolute; top:10px; left:200px; width:900px; height:500px">
<iframe width="824" height="472" src="http://majordomoers.me/Videos/DanielaOddiDancingToBack_GounodsAveMaria.mp4" frameborder="0" allowfullscreen></iframe>
</div>
<DIV style="position: absolute; top:0px; left:0px; width:0px; height:0px"></div>
<DIV style="position: absolute; top:10px; left:0px; width:50px; height:50px">
<iframe src="http://majordomoers.me/Videos/LauraUllrichSingingBach_GounodsAveMaria.mp4" frameborder="0" allowfullscreen></iframe>
</div>
<DIV style="position: absolute; top:0px; left:0px; width:0px; height:0px"></div>
<DIV style="position: absolute; top:470px; left:10px; width:1050px; height:30px">
<br><font face="Comic Sans MS" size="3" color="red">
<li><b>Both Videos will START automatically...but the one with the audio will preceed the dancing by about 17 seconds. You should keep
<li>both videos at the same size as presented here. In all, just lean back and let it all unfold before you, each in its own time.</li></font>
</div>
<br>
</body>
</html>
You can use the below code to get the nested frame hierarchy... Change the getAttribute according to your DOM structure.
static Stack<String> stackOfFrames = new Stack<>();
....
....
public static void getListOfFrames(WebDriver driver) {
List<WebElement> iframes = wd.findElements(By.xpath("//iframe|//frame"));
int numOfFrames = iframes.size();
for(int i=0; i<numOfFrames;i++) {
stackOfFrames.push(iframes.get(i).getAttribute("id"));
System.out.println("Current Stack => " + stackOfFrames);
driver.switchTo().frame(i);
getListOfFrames(driver);
driver.switchTo().parentFrame();
stackOfFrames.pop();
count++;
}
}

Categories

Resources