Clicking a button using Python Selenium - python-3.x

I am trying to automate something on Facebook using Python selenium. I want to click the post button shown in the second image. When I click the inspect in chrome on this post button, it takes me to the highlighted 'class' element shown in the third image. To click this button, I have tried the following:
#browser.find_element_by_class_name("oajrlxb2 s1i5eluu qu0x051f esr5mh6w e9989ue4 r7d6kgcz rq0escxv nhd2j8a9 pq6dq46d p7hjln8o kvgmc6g5 cxmmr5t8 oygrvhab hcukyx3x cxgpxx05 d1544ag0 sj5x9vvc tw6a2znq oqcyycmt esuyzwwr f1sip0of lzcic4wl l9j0dhe7 abiwlrkh p8dawk7l ehryuci6 bp9cbjyn beltcj47 p86d2i9g aot14ch1 kzx2olss rt8b4zig n8ej3o3l agehan2d sk4xxmp2 lrazzd5p gigivrx4 sf5mxxl7 g0qnabr5 lrwzeq9o iqfcb0g7 lsqurvkf id6903cd jq4qci2q m5l1wtfr taijpn5t sn7ne77z oqhjfihn bwm1u5wc").click()
Following is the error I am getting:

One thing that I noticed is that the div tag contains the text Post, so instead of complicating things with the class name, you can simply click on the element by identifying the text it contains. You can do it like this:
browser.find_element_by_xpath("//div[contains(text(), 'Post')]")

Related

How to get text in dash using dialog box?

I want to ask name of plot by using dialog box in dash like promp function in javascript but when I use {html.Script("prompt('text');", type='text/javascript') I have nothing in return.
I don't want to use text input or text area.
Thank you for your help.
The Dash documentation says the following on html.Script:
CAUTION: is included for completeness, but you cannot execute JavaScript code by providing it to a element. Use a clientside callback for this purpose instead.
https://dash.plotly.com/dash-html-components/script
As the documentation says here one option would be to use a clientside callback instead.
Minimal example to show the idea:
app = dash.Dash(__name__)
app.layout = html.Div(
[
html.Div(id="content"),
html.Button(id="button", children="Show name of plot prompt"),
]
)
app.clientside_callback(
"""
function(n_clicks) {
if (n_clicks) {
nameOfPlot = prompt('name of plot')
return nameOfPlot
}
return "Name of plot placeholder"
}
""",
Output("content", "children"),
Input("button", "n_clicks"),
)
The Button click is the input for this callback. If nothing is clicked I return a placeholder text which sets the children property of a div with id content.
If the button has been clicked we can call prompt and do something with it.
With this approach you need an input and an output for the callback to work. You could also put the Javascript code in a .js file in an assets in your root application directory. For more info on client side callbacks see the documentation here.
Another approach would be to have a .js file in your assets folder and to put your prompt code there. You'd probably also want to set up some event listeners to wait for the page to load and/or to listen for button click events or other events that you could use to trigger the prompt at the right moment.

How to write an html from a remote function using writeDump or writeOutput?

I am coming from Adobe Coldfusion and I'm trying to debug a component in Lucee by writing values to the output. Normally what I do is:
component Sample {
remote Void function spotCheck() {
writeDump(1234);
writeOutput("<br>Test");
return
}
Then hit the page to HTTP://localhost/sample/Sample.cfc?method=spotCheck
But it does not work. I updated the function to have a returnformat="text", but then the output is plain text with HTML tags in its text form. I tried setting it to "html" instead of text but then I get the error below:
This page contains the following errors:
error on line 20 at column 17: xmlParseEntityRef: no name
Below is a rendering of the page up to the first error.
I'm probably doing it the wrong way and I'm happy to learn the Lucee way of how to easily inspect values of variables inside a component function.
PS: I don't have/use step by step debugger.

Button has no ID and no Name, python Selenium

I want to make a little software with python and I have to get to YouTube with Requests-Python, but everytime I have to accept the Cookie-License. So I started with Selenium, but i cant find the button ID and the name or the value,...
The Source Code:
<button class="VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ VfPpkd-LgbsSe-OWXEXe-dgl2Hf nCP5yc AjY5Oe DuMIQc IIdkle" jscontroller="soHxf" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="higCR" aria-label=""><div class="VfPpkd-Jh9lGc"></div><span jsname="V67aGc" class="VfPpkd-vQzf8d" aria-hidden="true"></span><div class="VfPpkd-RLmnJb"></div></button>
Selenium has many options additionally to id.
For example, try to use css locator
locator = driver.find_element_by_css_selector(".VfPpkd-LgbsSe.VfPpkd-LgbsSe-OWXEXe-k8QpJ.VfPpkd-LgbsSe-OWXEXe-dgl2Hf.nCP5yc.AjY5Oe.DuMIQc.IIdkle")
Remove classes that do not make this locator unique to make the locator shorter.

Clickable link in the TreeDataProvider

I have created a plugin whose response are displayed as rows under TreeDataProvider. In that, among other details, i have one child as "Name" and another "url". Is it possible to have "Name" as a link on which when I click, in background it opens the url in a browser?
Updated the image after the fix. Now it's opening the link outside in a browser. Can i make only label clickable? Also, can I underline the label to show that its a link?
Yes.
You can make a tree item clickable by providing it with vscode.open command:
let treeItem: vscode.TreeItem = new vscode.TreeItem(name);
treeItem.command = {
command: 'vscode.open',
arguments: [vscode.Uri.parse(url)]
} as vscode.Command;
Finally figured it out:
element.children[0].command = {
command: 'vscode.open',
arguments: [vscode.Uri.parse('https://www.google.com')]
} as vscode.Command;

Like instagram photo with selenium python

I'm trying to code my own bot python selenium bot for instagram to experiment a little. I succeeded to log in and to search an hashtag in the search bar which lead me to the following web page:
But I can not figure out how to like the photos in the feed, i tried to use a search with xpath and the following path:
"//[#id="reactroot"]/section/main/article/div1/div/div/div1/div1/a/div"
But it didn't work, does anybody have an idea?
First of all, in your case it is recommended to use the official Instagram Api for Python (documentation here on github).
It would make your bot much simpler, more readable and most of all lighter and faster. So this is my first advice.
If you really need using Selenium I also recommend downloading Selenium IDE add-on for Chrome here since it can save you much time, believe me. You can find a nice tutorial on Youtube.
Now let's talk about possible solutions and them implementations. After some research I found that the xpath of the heart icon below left the post behaves like that:
The xpath of the icon of the first post is:
xpath=//button/span
The xpath of the icon of the second post is:
xpath=//article[2]/div[2]/section/span/button/span
The xpath of the icon of the third post is:
xpath=//article[3]/div[2]/section/span/button/span
And so on. The first number near "article" corresponds to the number of the post.
So you can manage to get the number of the post you desire and then click it:
def get_heart_icon_xpath(post_num):
"""
Return heart icon xpath corresponding to n-post.
"""
if post_num == 1:
return 'xpath=//button/span'
else:
return f'xpath=//article[{post_num}]/div[2]/section/span/button/span'
try:
# Get xpath of heart icon of the 19th post.
my_xpath = get_heart_icon_xpath(19)
heart_icon = driver.find_element_by_xpath(my_xpath)
heart_icon.click()
print("Task executed successfully")
except Exception:
print("An error occurred")
Hope it helps. Let me know if find other issues.
i'm trying to do the same)
Here is a working method. Firstly, we find a class of posts(v1Nh3), then we catch link attribute(href).
posts = bot.find_elements_by_class_name('v1Nh3')
links = [elem.find_element_by_css_selector('a').get_attribute('href') for elem in posts]
I implemented a function that likes all the picture from an Instagram page. It could be used on the "Explore" page or simply on an user's profil page.
Here's how I did it.
First, to navigate to a profil page from Instagram's main page, I create a xPath for the "SearchBox" and a xPath to the element in the dropdown menu results corresponding to the index.
def search(self, keyword, index):
""" Method that searches for a username and navigates to nth profile in the results where n corresponds to the index"""
search_input = "//input[#placeholder=\"Search\"]"
navigate_to = "(//div[#class=\"fuqBx\"]//descendant::a)[" + str(index) + "]"
try:
self.driver.find_element_by_xpath(search_input).send_keys(keyword)
self.driver.find_element_by_xpath(navigate_to).click()
print("Successfully searched for: " + keyword)
except NoSuchElementException:
print("Search failed")
Then I open the first picture:
def open_first_picture(self):
""" Method that opens the first picture on an Instagram profile page """
try:
self.driver.find_element_by_xpath("(//div[#class=\"eLAPa\"]//parent::a)[1]").click()
except NoSuchElementException:
print("Profile has no picture")
Like each one of them:
def like_all_pictures(self):
""" Method that likes every picture on an Instagram page."""
# Open the first picture
self.open_first_picture()
# Create has_picture variable to keep track
has_picture = True
while has_picture:
self.like()
# Updating value of has_picture
has_picture = self.has_next_picture()
# Closing the picture pop up after having liked the last picture
try:
self.driver.find_element_by_xpath("//button[#class=\"ckWGn\"]").click()
print("Liked all pictures of " + self.driver.current_url)
except:
# If driver fails to find the close button, it will navigate back to the main page
print("Couldn't close the picture, navigating back to Instagram's main page.")
self.driver.get("https://www.instagram.com/")
def like(self):
"""Method that finds all the like buttons and clicks on each one of them, if they are not already clicked (liked)."""
unliked = self.driver.find_elements_by_xpath("//span[#class=\"glyphsSpriteHeart__outline__24__grey_9 u-__7\" and #aria-label=\"Like\"]//parent::button")
liked = self.driver.find_elements_by_xpath("//span[#class=\"glyphsSpriteHeart__filled__24__red_5 u-__7\" and #aria-label=\"Unlike\"]")
# If there are like buttons
if liked:
print("Picture has already been liked")
elif unliked:
try:
for button in unliked:
button.click()
except StaleElementReferenceException: # We face this stale element reference exception when the element we are interacting is destroyed and then recreated again. When this happens the reference of the element in the DOM becomes stale. Hence we are not able to get the reference to the element.
print("Failed to like picture: Element is no longer attached to the DOM")
This method checks if picture has a "Next" button to the next picture:
def has_next_picture(self):
""" Helper method that finds if pictures has button \"Next\" to navigate to the next picture. If it does, it will navigate to the next picture."""
next_button = "//a[text()=\"Next\"]"
try:
self.driver.find_element_by_xpath(next_button).click()
return True
except NoSuchElementException:
print("User has no more pictures")
return False
If you'd like to learn more feel free to have a look at my Github repo: https://github.com/mlej8/InstagramBot

Resources