I am logging into a website using my own credentials, but 2FA is active. Therefore, I need a way to "pause" the script until I manually click the button with my mouse.
Note that the button is always clickable, so using an explicit wait like element_to_be_clickable obviously will not work.
I know how to do this with input() via command prompt, but I would rather deal with the browser manually since the rest of the script also requires manual browser interaction.
I also know that I could wait until the script detects a certain number of inputted characters, but I do not like this approach because typos.
I know I could use an explicit wait in order to detect something on the following page, but I want to avoid this way in case I ever need to step away from the keyboard before submitting the data. However, I could set an unreasonably long wait period e.g. WebDriver(driver, 999999999), but this approach seems super hacky.
Any ideas?
Here is a solution that may not work for everybody. Poll the URL...
poll_rate = 1
current_url = driver.current_url
while driver.current_url == current_url:
time.sleep(poll_rate)
Can anybody come up with a better solution?!
I am shocked that it is almost impossible to detect user input in a practical manner.
Related
I have a selenium script that runs a loop on a process that prints text into my python IDLE to get a list of data, which I then copy and paste to excel - which is great. But not optimal.
I am currently using sleep at the start of the loop to give me time to change parameters on my trading view strategy tester, which gives me a different result to be printed as intended. However, I would like more or less time on most occasions. Waiting for the path to change does not work as the path never changes, it just gets looped again with a different text output based on the changes I would have made manually on the strategy settings.
Also worth noting that I am using firefox geckobrowser as opposed to chrome and that the purpose of the script is to automate a tedious manual task of data collection.
Is it at all possible to create a pop-up button or something of the like via selenium that says "Next" for example, that I can click and let the script know its okay for the loop to continue? Can I simply replace sleep with click "Next" or something of the like for example?
for i in range(20):
time.sleep(10)
netProfit = driver.find_element("xpath", '/html/body/div[2]/div[7]/div[2]/div[4]/div/div[2]/div/div[1]/div[1]/div[2]/div[2]')
numberTrades = driver.find_element("xpath", '/html/body/div[2]/div[7]/div[2]/div[4]/div/div[2]/div/div[1]/div[2]/div[2]')
winRate = driver.find_element("xpath", '/html/body/div[2]/div[7]/div[2]/div[4]/div/div[2]/div/div[1]/div[3]/div[2]')
print(netProfit.text, numberTrades.text, winRate.text)
This works for now, but it's a pain waiting for timer on occasions I don't need it and even more of a pain on occasions when it's not enough time.
I am expecting something like this to replace time.sleep(10)
WebDriverWait(driver, 180).until("Next" button is clicked)
Ideally I would like a solution that can be done in selenium as my experience is limited, but any workarounds would be appreciated all the same.
I do not have an error nor have one inside the selenium command prompt but for whatever reason sometimes whenever I get to a website (any website), selenium seems to get stuck on which ever random action (like get(), click(), send_keys() and such) its supposed to do making my shell process never end or progress but when I restart it manually, it seems to finally do what its supposed to do. I want to make my script as autonomous as possible and preset certain time window for each action so whenever this problem gets around, I do not need to come over and restart my script manually. I do not want to fix the long time it needs to process because it would probably mean sizing down on my proxies and arguments I gave which are crucial. I have a clue that this would probably work with the time.time() feature but implementing it seems hard.
This is a code that I use to register my courses for semester. I want this code to run fastest as possible so that I can select my preferred courses faster than other students who select them manually, the seats and section of desired classes fill-up fast. My concern is that if my code runs faster and the browser cant keep up with it then it will cause issue. For example I will be running on google chrome browser. And what should I change to make this code faster without risking Thanks in advance.
import pyautogui
import time
import webbrowser
pyautogui.FAILSAFE = False
time.sleep(1)
pyautogui.hotkey('alt', 'tab')
##Subject choose
time.sleep(0.5)
pyautogui.hotkey('ctrl', 'f')
pyautogui.write('PHY182.1')
pyautogui.press('enter')
pyautogui.press('esc')
pyautogui.hotkey('shift', 'tab')
pyautogui.press('space')
I did something similar I while ago, not exactly your case but I believe it would help. If you want it to be as fast as possible while making sure that the browser if keeping up with you, you should make your script recognize that the page you are going to be on has fully loaded, for this I would use selenium, so when the page is fully loaded it does the thing really fast, but not before. I think that if you did it like that it would work.
You have to setup selenium first, it's a bit long so I won't explain here, I'll just give you an example of it being used.
Selenium example:
driver.maximize_window()
driver.get(url) # goes to url and waits till it's loaded #
einput = driver.find_element_by_id("identifierId") # find the element you want through it's name #
einput.send_keys(email) # what you want to write #
einput.send_keys(Keys.RETURN) # enter #
I used this code for a script I made that logged people into google really fast in incognito. But I believe you could adapt it to your case. It's not perfect though because some pages 'never finish loading' but give it a try.
Im having this code, if there's the time.sleep(2) it clicks and if it's not there it doesnt click on the elements. It doesn't even wait a second
time.sleep(2)
WebDriverWait(self.broswer, 30).until(EC.element_to_be_clickable((By.CLASS_NAME, 'something')))
self.browser.find_element_by_class_name('something').click()
I tried to use the following instead
self.browser.implicitly_wait(2)
but it doesnt wait and I cant use time.sleep()
Time.Sleep() is counting time in milliseconds, therefore Time.Sleep(2) is 2 milliseconds, maybe if you try,
Time.Sleep(2000);
it may work for you.
time.sleep() and WebDriverWait() are different methods of waiting. It's best practice to avoid use of time.sleep() and prefer WebDriverWait.
In another comment you said that you don't even want to wait, you just want to click the button. If that's the case, you should be able to just use this
self.browser.find_element_by_class_name('something').click()
but you said that you get an error. What is the error that you get if you only run that one line?
Side note...
WebDriverWait.until() should return the WebElement specified so if you decide you want to keep the wait, you can do this
WebDriverWait(self.broswer, 30).until(EC.element_to_be_clickable((By.CLASS_NAME, 'something'))).click()
I come from a Java background and don't know python so I may have some typos here and there... but this should get you headed in the right
what is the problem with time.sleep()
If you don't want to user time.sleep() and still if you want to force web driver to wait for specific time then you can give condition also.
you can go through with below url for java
http://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html#invisibilityOfElementLocated-org.openqa.selenium.By-
1)
Use the time.sleep() (which is in seconds "Suspend execution of the current thread for the given number of seconds")only when you really need it.
2)
Learn, deeply, the differences between IMPLICIT WAIT and EXPLICIT WAIT
Sometimes,I had the need to force the "physical" hard-ware wait, the I used the time.sleep(), but I really suggest you to comprehend the difference between the two waiting method which selenium provides you.
#Dor Alt: Remember that the (from documentation) "An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code." If you get any kind of error, please write it here and tell us which browser you're using for your test, because different browsers have (very, very and very) different behaviours! :)
I mean, if you are using Chrome and IE (as far as I know) if the webdriver doesn't have the visualization of the element you want to click, it does not click! In this case, for example, you should move/scroll the page with a script like this: driver.execute_script('window.scrollTo(0, {0})'.format(element.location['y']))
I'm testing a django app with selenium, and one of my pages uses the jquery ui tabs element. One of the tabs contains a simple table listing some users, and is loaded via ajax. When using the app, the tab works just fine, but when automating the test with selenium, the tab doesn't appear to load it's content!
I'm writing the tests myself in python. At first, I was using the click method of selenium RC, but as I -painfully- learned from a previous test, that is rather buggy when it comes to anchor tags, so I resorted to the solution I used before: the wait_for_condition method and explicitly called the tab click event (and even the load event!) and nevertheless the tab was still not working!
I'm in despair here, the majority of my tests depend on that page and almost half of them are on that table, but, alas, it seems selenium is screwing up the javascript!
(I have other tests in the class, and they run just fine, so nothing weird is going on at the server level, it seems to be a problem caused by selenium in the client side)
My test code is similar to this:
class TestMyApp(TransactionTestCase):
urls = 'myapp.test_urls'
def setUp(self):
self.verificationErrors = []
self.selenium = selenium("localhost", 4444, "*chrome", "http://localhost:8000/")
self.selenium.start()
#self.selenium.set_speed(2000)
self.selenium.window_maximize()
def test_users_list(self):
"""Test that an app's users are correctly listed"""
sel = self.selenium
users = []
for u in range(settings.FREE_USER_LIMIT/2):
users.append(self.app.users.create(name="testUser_%s"%uuid4()))
sel.open("/")
sel.wait_for_page_to_load("30000")
sel.wait_for_condition('selenium.browserbot.getCurrentWindow().jQuery("#tabs").tabs("select",1);\
selenium.browserbot.getCurrentWindow().jQuery("#tabs").tabs("load",1);',
3000)
for user in users:
try: self.failUnless(sel.is_text_present(user.name))
except AssertionError, e: self.verificationErrors.append(str(e))
try: self.failUnless(sel.is_text_present(str(user.added.date())))
except AssertionError, e: self.verificationErrors.append(str(e))
def tearDown(self):
self.selenium.stop()
self.assertEqual([], self.verificationErrors)
This could be a few things. It could be that Selenium is having trouble clicking the anchor but I actually haven't heard of that trouble and it sounds less likely. It sounds like the click() method returns OK, it doesn't give you "element not found", right? When you do the click the jquery tab javascript just isn't doing what's expected. In my experience this usually comes down to the same issue -- since Selenium executes very quickly, when javascript is rendering portions of the page and effecting the DOM continuously sometimes when Selenium goes to interact with dynamically generated parts of the page (say to click this tab), the piece it's interacting with depends on some other piece that actually hasn't fully loaded yet. It's probably microseconds away from fully loading in fact, but selenium is too fast. You already understand this of course, you have the right idea with the wait_for condition looking for the tabs to be loaded. My guess would be it's probably just not long enough. You have to find some evaluation to make that says the whole UI tabs thing is loaded and rendered. Does the tabs API have some callbacks you can add to set a "done loading" variable or does it expose a variable like that? Barring figuring out what the proper expression is to find the point in time when the UI tabs are actually ready to be clicked, which possibly could be tricky, you can resort to outright pauses to make sure the part of the page is ready to go before you interact with it. I see no problem in sleep(2), or even sleep(5), etc. in the code if it's necessary to get it to work. One way you can test that this is really what's going on is by firing up the scenario in the interactive interpreter (gotta love Python, beats the pants off of doing this in Java). Paste the code in line by line to get to the trouble point, or comment out the selenium.stop() call in your teardown method and any test code after the trouble point, so it leaves the selenium window open and exits. Then instantiate a selenium object in the interactive interpretter and hijack the open session:
selenium = selenium("localhost", 4444, "*chrome", "http://localhost:8000/")
selenium.sessionId = "0asdd234234023424foo" #Get this from the Se window
...to get interactive control of the window. Then you can see about making the selenium.click() or make selenium.get_eval('...js...') calls to investigate the javascript landscape at that point in time. My guess is when you do this, the click() will actually work fine when you type it in, because by the time you get the session loaded and get around to typing in selenium.click('blah_tab_locator'), the tab guts will all be loaded and ready to go. It's just that when Python is making the calls it does it way too fast for the browser when there are these dynamic renderings going on. If the click works fine when you do it manually through selenium like this, then you know it's a timing issue. Find that proper wait_for_condition or condescend to a python sleep(). Otherwise, if the click continues to not work when you do this, then it's probably a problem with the locator being used. The tab UI has a click or a mouseup or a focus or some kind of event handler on some part of the tab structure, maybe it's just about finding the right part of the tab to click or the right event to fire. If it isn't that then it perhaps could be as you mention some kind of strange interaction between Selenium and Jquery UI, but that would surprise me and I'd be curious to know. Poke around with get_eval() to see what's going on in the javascript if so. It sounds like a timing issue to me though.