Python Selenium: How to optimise a button selection & submitting process? - python-3.x

I made a bot to play a browser game for me. The bot clicks buttons presented on a web page to continue with a story line. And I require a help with optimising the button selection, checking & submitting process.
How can I make a Python Selenium script to get all the buttons on the page and select a specific one from the available ones.
The bot right now works as follows:
x = 0
while x < 99999:
if x < 99999:
try:
browser.get('https://censoredgame.com/city/adventure/decision/7')
time.sleep(0.4)
browser.get('https://censoredgame.com/city/adventure/')
x = x + 1
except:
pass
try:
browser.get('https://censoredgame.com/city/adventure/decision/25')
time.sleep(0.4)
browser.get('https://censoredgame.com/city/adventure/')
x = x + 1
except:
pass
<a class="btn" title="Вземете решение!" href="/city/adventure/decision/29">Подслушайте</a>
<!-- This is how a button looks, I cant use NAME,ID,CLASS -->
It is pretty simple:
/city/adventure/decision/7 = Some button, /city/adventure/decision/25 = Other button.
The way my bot works is it tries to press a button by entering a link in the browser bar and it does this very slow because it checks 15 buttons on the page.
Could you please advise me on how I could improve this process?

Nikolay, I'm rly want to help you, but I didn't get how you gonna click on the button - " by entering a link in the browser bar"? Anyway, you need to open your page, then find all elements by Xpath driver.find_elements(By.XPATH, "//a[#class='btn' and #title='Вземете решение!']"). Collect all those elements in WebElements list, then do foreach loop(I'm writing code on Java and C#, so u have to do it yourself). This loop gonna be clicking on each "Подслушайте" button on the page. If you have any questions let me know.

I'm so happy to tell you I found my way to approach the problem.
I'm sorry for everyone who didn't understand my problem and wanted to help.
I fixed my code and now its really fast. Here is a little example:
x = 0
while x < 1000:
try:
browser.find_element_by_link_text('Пълна атака').click()
browser.find_element_by_link_text('Продължи').click()
except NoSuchElementException:
pass
try:
browser.find_element_by_link_text('Изправете се срещу врага').click()
browser.find_element_by_link_text('Продължи').click()
except NoSuchElementException:
pass
etc
I feel really stupid right now. The answer was so easy but I didn't get in right away.
First time i tried to find element by link text I forgot to set except NoSuchElementException and i got problems...
Thank you all for help!

Related

Python - Mouse clicks/Keyboard Clicks on window in background

I wanted to create a metin2 bot, nothing complicated. I am new into that so i just started to look for tutorials on youtube to find something that would lead me to world of coding, how does it work, what language is used to write it ect. So I found a tutorial on youtube about open CV Learn Code By Gaming - OpenCV and thought that's awesome thing to start with.
I got to the point where I can easily detect the names of monsters/metins and wont have any problems in finding the right points to click. After detection started working I thought about automating clicking on the window to farm some items etc. Simple things like clicking e.g 50 pixels below the name to auto attack worked just fine but the problem was that I wanted to make more bots to maximalize farming. So when i started to add more clients I got a problem where e.g you have to hold down SPACE in one window to attack from horse and click on another window which was stopping attacking from horse. So I thought about finding some code that can basically send message directly to window without controlling a mouse or keyboard so you can run multiple bots in one time and each will do perfect meanwhile you can do anything else on pc because your mouse and keyboard aren't used.
Let's start from code I found and none worked for windows in background (even with administrator privileges). Pyautogui doesn't work in background (window has to be in foreground to be clicked on and it controls mouse so there is no point in using that.
From that code I learned that I need to find "window ID" to connect to it and send messages. When i print hWnd it shows the numbers in Terminal and code passes without any fails but does nothing except printing the window ID ( Parent Handle ). Ofc I pip installed pywin32
import win32gui
import win32api
import win32con
def click(x, y):
hWnd = win32gui.FindWindow(None, "Client")
print(hWnd)
lParam = win32api.MAKELONG(x, y)
win32api.SendMessage(hWnd, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, lParam)
win32api.SendMessage(hWnd, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, lParam)
click(100, 100)
Than i found another code that looked similar but used different function so first i used
wdname = 'Client'
hwnd = win32gui.FindWindow(None, wdname) # parent handle
print(hwnd)
Which printed me a window ID that i used in parameters in function
def control_click(x, y, handle, button):
l_param = win32api.MAKELONG(x, y)
if button == 'left':
win32gui.PostMessage(handle, win32con.WM_LBUTTONDOWN, win32con.MK_LBUTTON, l_param)
win32gui.PostMessage(handle, win32con.WM_LBUTTONUP, win32con.MK_LBUTTON, l_param)
elif button == 'right':
win32gui.PostMessage(handle, win32con.WM_RBUTTONDOWN, 0, l_param)
win32gui.PostMessage(handle, win32con.WM_RBUTTONUP, 0, l_param)
control_click(200, 200, 329570, button ='left')
But it still did nothing but code passed clear
Anyone have any ideas about how to make clicks/keyboard clicks in python on window in background without taking controll of mouse/keyboard? If you have any experience in automating and know better ways to create automation for clicking ect. and want to share it please do. If that can be done in another programming language also share your toughts about that of course if you want to.
Windows 10 x64
Python used: 3.9.2
All codes i found in topics were out of date that s why i am asking for help there. Thanks in advance :)

Looking for help on how to get started with my first programming project

Step 1:
Open google chrome to the chess.com website
Step 2:
Login into my account via the homepage
Step 3:
Hover mouse cursor over the big “Learn” button on the banner on the left hand side of the web page. This will extend into another menu.
Step 4:
On this menu that has popped up, I will click the button which says “Videos”, which will navigate me to this url: “https://www.chess.com/videos”
Step 5:
Then I click the “Library” button to take me to: “https://www.chess.com/videos/library”
Step 6:
I open up a specific video (out of the many which are in a list) by clicking on the title link.
This is how the list looks like:
https://photos.app.goo.gl/VsxhQH5siigGMMoJA
Step 7:
On the new page, with the video player in plain sight, I right click and then inspect element- in order to enter Chrome development tools
Like so:
https://photos.app.goo.gl/96YgYTfLa58MHSmp7
Step 8:
Then I click the “pointer arrow” button in the top left hand corner of the dev tool box.
Step 9:
Then I “select” on the video player to highlight it.
Cf. this image:
https://photos.app.goo.gl/6wsLFEzmcBJVJTHJ9
Step 10:
Then I open the .mp4 link which has appeared in the elements tab, which will thus open a new tab which only contains the video player on the screen
Step 11 (Final step):
Then I click the button in the bottom right hand corner and then select “Download” in order to get the .mp4 file.
Cf. this image: https://photos.app.goo.gl/gDMxwmNBSwBCq4LP8
I find it very tedious to do this process of downloading all the embedded videos from a website such as this, because I must actually open a new video in order to get a chance to download it.
Thus, I was thinking of making my very first project as a complete novice programmer (to keep myself motivated!) to try and program something which can automate this process.
My questions is: Is it possible to automate this algorithm that I have stated above (perhaps with some kind of bot or web crawler), and what topics should I learn about in order to develop the skills in order to do what is necessary?
Thank you so much for the help everyone! I am very grateful :)
I realize you may not be looking for a code-solution, but I have included one that you can use for inspiration. It downloads all the videos into a directory "chessvideos" (note that there are 123 pages with ~25 videos on each, so it will take a long time to finish).
Building a webcrawler like this is a process. Knowing that you can get the HTML of a url using requests and that you can "query" the DOM to find elements using BeautifulSoup, open your browser and do the inspections as you mention in your question. E.g which HTML-attributes should you be looking for? Classes, Id's, tags etc.
Part of this process is also to realize how the system will respond to your requests, e.g you mention logging in - this may often be a requirement, but it is not actually for this website, making the problem a lot simpler. Hope it is of some use.
import requests
from bs4 import BeautifulSoup
import os
class ChessDownloader():
download_directory = os.path.join(os.path.dirname(os.path.realpath(__file__)), "chessvideos")
def __init__(self):
res = requests.get("https://www.chess.com/videos/library")
if res.status_code == 200:
b = BeautifulSoup(res.text, features='html5lib')
a = b.find('a', text='Last').get('href')
pages = int(a.replace('https://www.chess.com/videos/library?page=', '')) # get the number of pages using the "Last" button
for i in range(pages):
self.download_videos_from_page(i)
def download_videos_from_page(self, page_number):
if page_number == 0:
res = requests.get('https://www.chess.com/videos/library')
else:
res = requests.get('https://www.chess.com/videos/library?page=' + str(page_number))
if res.status_code == 200:
b = BeautifulSoup(res.text, features='html5lib')
links = b.find_all('a', { 'class' : 'content-image' })
links = [a.get('href') for a in links]
for link in links:
r = requests.get(link)
if r.status_code == 200:
b = BeautifulSoup(r.text, features='html5lib')
video_url = b.find('meta', {'property': 'og:video:secure_url'}).get('content')
self.download_video(video_url)
def download_video(self, url):
if not os.path.exists(self.download_directory):
os.mkdir(self.download_directory)
res = requests.get(url)
if res.status_code == 200:
name = url.rsplit('/', 1)[-1]
file_path = os.path.join(self.download_directory, name)
if not os.path.exists(file_path): # Dont download if we already have it
with open(file_path, 'wb+') as f:
f.write(res.content)
c = ChessDownloader()

Make python chromedriver script run faster (change send_keys *too slow*)

Hello I have built a program script that goes onto a website and selects a size and auto checks out an Item for me it works very well but I have 2 concerns
1.I want to have this script run faster before the script ran pretty fast (so fast that it basically added to cart and went to the checkout page before the Item could even load into the cart (which resulted in errors) and so I added there script to my code
wait = WebDriverWait(driver, 10) and this one which I mainly used to wait until the item loaded into the cart and all the "add to cart" buttons showed up
wait.until(EC.presence_of_element_located((By.NAME, 'commit')))
but I want this script to run faster I tried changing the
wait = WebDriverWait(driver, 10) into something like
wait = WebDriverWait(driver, 1) and
wait = WebDriverWait(driver, 100) but I see no difference is there anything I can do to make the script run faster?(it doesnt have to do with the wait= thing Ill take any thing I can get to even shave off milaseconds.
I am currently using the send_keys option for autofill which is PAINFULLY SLOW is there anything I can use that will fill all the stuff instanstly alltogether? ik there are some "JAVA-scripts simular to this that can do it but im not sure how to right java script or more importantly how to even combine them
Can anyone help me out I just want my selenium python chromedriver script to run as fast as possible.
Thank you.
(for my script im using select for the size and just .click() and a couple of if statements which depends on how many items they want to cart and lots of def fweuf
fweuf() (i forget what those are called lol) )
For sending values with JS you can do this:
js= "document.getElementById('YOURELEMENT').value = '" + str(YOURVALUE) + "';"
driver.execute_script(js)
Hope this helps.

Gtk Window Non-Responsive During Selenium Automation

Good Afternoon :) Having a problem with my Python3 Gtk3 application and Selenium WebDriver (ChromeDriver). Also, using Linux if it matters.
Basically, the user presses a button to start the Selenium webdriver automation and then as the automation process is going, it 'SHOULD' give feedback to the user in the GUI (See Content.content_liststore.append(list(item)) and LogBox.log_text_buffer).
However, it's not adding anything into the content_liststore until after fb_driver.close() is done. In the meantime, the Gtk window just "hangs".
Now, I've been looking into multithreading in hopes of the GUI being responsive to this feedback but I've also been reading that Selenium doesn't like multithreading (but I presume thats running multiple browsers/tabs (which this is not)).
So, my question is; Is multithreading the go-to fix for getting this to work?
# ELSE IF, FACEBOOK COOKIES DO NOT EXIST, PROCEED TO LOGIN PAGE
elif os.stat('facebook_cookies').st_size == 0:
while True:
try: # look for element, if not found, refresh the webpage
assert "Facebook" in fb_driver.title
login_elem = fb_driver.find_element_by_id("m_login_email")
login_elem.send_keys(facebook_username)
login_elem = fb_driver.find_element_by_id("m_login_password")
login_elem.send_keys(facebook_password)
login_elem.send_keys(Keys.RETURN)
except ElementNotVisibleException:
fb_driver.refresh()
StatusBar.status_bar.push(StatusBar.context_id, "m_login_password element not found, trying again...")
ProblemsLog.text_buffer.set_text("Facebook has hidden the password field, refreshing page...")
else:
query_elem = fb_driver.find_element_by_name("query")
query_elem.send_keys(target)
query_elem.send_keys(Keys.RETURN)
break
m_facebook_url_remove = "query="
m_facebook_url = fb_driver.current_url.split(m_facebook_url_remove, 1)[1] # Remove string before "query="
facebook_url = "https://www.facebook.com/search/top/?q=" + m_facebook_url # Merge left-over string with the desktop url
StatusBar.status_bar.push(StatusBar.context_id, "Facebook elements found")
fb_title = fb_driver.title
fb_contents = [(target_name.title(), "Facebook", facebook_url)]
for item in fb_contents:
Content.content_liststore.append(list(item))
#progress_bar.set_fraction(0.10)
LogBox.log_text_buffer.set_text("Facebook Search Complete")
with open('facebook_cookies', 'wb') as filehandler:
pickle.dump(fb_driver.get_cookies(), filehandler)
fb_driver.close()
I've considered it not working because of the 'while' loop, but another piece of code doesn't have a loop and does the exact same thing, it waits for Selenium to finish before adding content to the GUI.
Additionally, the user can select multiple websites to do this with, so the application can first go to Facebook (do it's business then close), go to LinkedIn (do it's business then close) and so fourth. And it still waits for all the Selenium code to finish before adding anything to the Gtk GUI.
I really hope that makes sense! Thank you :)
Your`s question is the answer you are lookig for. Take a read here https://wiki.gnome.org/Projects/PyGObject/Threading

Multiple Images in EasyGui

Basically I want to create type of quiz in Python 3.4 with EasyGui using multiple images on the button boxes.
How I'd imagine it'd work would be like this:
import easygui as eg
# A welcome message
eg.msgbox ("Welcome to the quiz", "Quiz!")
# A short splash screen this could be looped
Finish = "Start"
while Finish == "Start":
Finish = eg.buttonbox("Do you want to start the quiz or quit?","Welcome",["Start","Quit"])
if Finish == "Quit":
break
#Question 1
image = "mickey.gif"
choices = ["Mickey","Minnie","Daffy Duck","Dave"]
reply=eg.buttonbox("Who is this?",image = image,choices = choices)
if reply == "Mickey":
eg.msgbox("Well done!","Correct")
else:
eg.msgbox("Wrong","Failure")
This works, but if I change the line
reply=eg.buttonbox("Who is this?",image=[image,image2,image3,image4],choices = choices)
But that doesn't seem to work, does anyone know if you can have more than one image per buttonbox?
at the current version of easygui, you can't have multiple images, only one image.
You could either:
use an external tool to create one big merged image out of several smaller images.
try to make the necessary changes direct inside easygui.py (it's all in one single file) if you have knowledge in tkinter
help / contact Robert Lugg as he works on an improved version of easygui https://github.com/robertlugg/easygui
allpic = ("image", "image2", "image3")
reply=eg.buttonbox("Who is this?",image=allpic,choices = choices)

Resources