So I've got a selenium python script that occasionally runs into the following error at differing sections in my code:
Exception has occurred: WebDriverException
Message: unknown error: cannot determine loading status
from target frame detached
But when I encounter this error, if I re-run the program without changing anything, everything works again (so I know that it's either a problem with the website or the webdriver). In the meantime, I was wondering if there was a way to tell python to restart the program if a WebDriverException is encountered. Any help would be greatly appreciated, thank you.
You could try os.execv(), according to here, it enables a python script to be restarted, but you need to clean the buffers etc using this C-like function sys.stdout.flush()
try:
<your block of code>
except WebDriverException:
print(<Your Error>)
import os
import sys
sys.stdout.flush()
os.execv(sys.argv[0], sys.argv)
You could simply use the os module to do this: os.execv(sys.argv[0], sys.argv)
Use a main() function as a starting point for your program, and trigger that function again whenever you need to restart. Something like
def foo1():
return
def foo2():
try:
...
except:
main()
def main():
foo1()
foo2()
if __name__ == "main":
main()
If the error occurs because it does not find a certain tag, you could put a wait
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
or worst case
browser.implicitly_wait(5)
or
time.sleep(5)
which waits 5 seconds for the element to appear
Related
Whenever I run the following file (and main encounters the WebDriverException exception) my program ends instead of restarting. Would anyone know why that's happening? Any help would be greatly appreciated – thank you.
from uploadToBeatstars import main
from selenium.common.exceptions import WebDriverException
try:
main()
except WebDriverException:
print("Dumb target error happened. Restarting program.")
from uploadToBeatstars import driver
driver.close()
import sys
import os
os.execv(sys.executable, ['python'] + sys.argv)
You don't need to respawn the interpreter after a failure in general, just retry in a loop:
from uploadToBeatstars import main, driver
from selenium.common.exceptions import WebDriverException
while True:
try:
main()
except WebDriverException:
print("Dumb target error happened. Restarting program.")
driver.close() # Not sure if it is needed, can driver be alive after an exception?
# Try again
else:
break # Stop if no exception occurred.
on windows, the os.exec* family of functions do not operate as they do on posixlikes -- instead of replacing the current process, they spawn a new one in the background and os._exit(1)
more on this here: https://github.com/python/cpython/issues/53394
on Windows, exec() does not really replace the current process. It creates a new process (with a new pid), and exits the current one.
you're probably best to either write a loop or use some sort of process manager
I am using selenium to scrape some data.
This is my code, simplified:
def get_usrs():
#DO SOMETHING
def scroll_down():
#SCROLL UNTIL ARRIVES TO THE BOTTOM OF THE PAGE
#CONTINUE WITH GET_USRS()
The problem is that when the code gets to scroll_down() it doesn't wait until it finishes but continues with get_usrs() and obviously encounters an error.
How can I solve this? Thanks in advance!
So, my code was running with:
try:
get_usrs()
except Exception as e:
print(e)
Now it's running with:
if __name__ == '__main__':
get_usrs()
Works fine.
I am having a main program which is defined like this:
main.py
def main():
try:
registry.start_server()
except:
print("Shutting down the program")
pass
if __name__ == '__main__':
main()
registry.start_server() is the method in another module which looks like this:
def start_server():
t_server = threading.Thread(target=server.start)
t_server.start()
try:
t_server.join()
except KeyboardInterrupt:
print("Error")
raise ValueError
finally:
fp.close()
server.start is the method in another module which does some listening work in a while(True) manner. I am not sure how to stop the whole program when clicking Stop in PyCharm which is Ctrl + C (Signal). I tried with Event but without success. I get to the main.py by raising an exception when the signal gets caught but that does not terminate the whole program. It shows Waiting for program to detach. The only way is to use SIGKILL. I don't understand where does the program keeps hanging? I have also tried calling sys.exit(0) when the signal gets caught and creating the thread as Deamon but that didnt help either.
EDIT
While True method in another module
def start(self, event):
try:
while True:
if event.is_set():
if self.pubsub.channels:
print("It enters here")
message = self.pubsub.get_message(True)
if message:
.
.
.
else:
return
To solve the problem, all you need to do is:
let the child-thread exit, and
let main thread join the child-thread.
Given this code:
from time import sleep
class TemporaryFileCreator(object):
def __init__(self):
print 'create temporary file'
# create_temp_file('temp.txt')
def watch(self):
try:
print 'watching tempoary file'
while True:
# add_a_line_in_temp_file('temp.txt', 'new line')
sleep(4)
except (KeyboardInterrupt, SystemExit), e:
print 'deleting the temporary file..'
# delete_temporary_file('temp.txt')
sleep(3)
print str(e)
t = TemporaryFileCreator()
t.watch()
during the t.watch(), I want to close this application in the console..
I tried using CTRL+C and it works:
However, if I click the exit button:
it doesn't work.. I checked many related questions about this but it seems that I cannot find the right answer..
What I want to do:
The console can be exited while the program is still running.. to handle that, when the exit button is pressed, I want to make a cleanup of the objects (deleting of created temporary files), rollback of temporary changes, etc..
Question:
how can I handle console exit?
how can I integrate it on object destructors (__exit__())
Is it even possible? (how about py2exe?)
Note: code will be compiled on py2exe.. "hopes that the effect is the same"
You may want to have a look at signals. When a *nix terminal is closed with a running process, this process receives a couple signals. For instance this code waits for the SIGHUB hangup signal and writes a final message. This codes works under OSX and Linux. I know you are specifically asking for Windows but you might want to give it a shot or investigate what signals a Windows command prompt is emitting during shutdown.
import signal
import sys
def signal_handler(signal, frame):
with open('./log.log', 'w') as f:
f.write('event received!')
signal.signal(signal.SIGHUP, signal_handler)
print('Waiting for the final blow...')
#signal.pause() # does not work under windows
sleep(10) # so let us just wait here
Quote from the documentation:
On Windows, signal() can only be called with SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, or SIGTERM. A ValueError will be raised in any other case.
Update:
Actually, the closest thing in Windows is win32api.setConsoleCtrlHandler (doc). This was already discussed here:
When using win32api.setConsoleCtrlHandler(), I'm able to receive shutdown/logoff/etc events from Windows, and cleanly shut down my app.
And if Daniel's code still works, this might be a nice way to use both (signals and CtrlHandler) for cross-platform purposes:
import os, sys
def set_exit_handler(func):
if os.name == "nt":
try:
import win32api
win32api.SetConsoleCtrlHandler(func, True)
except ImportError:
version = “.”.join(map(str, sys.version_info[:2]))
raise Exception(”pywin32 not installed for Python ” + version)
else:
import signal
signal.signal(signal.SIGTERM, func)
if __name__ == "__main__":
def on_exit(sig, func=None):
print "exit handler triggered"
import time
time.sleep(5)
set_exit_handler(on_exit)
print "Press to quit"
raw_input()
print "quit!"
If you use tempfile to create your temporary file, it will be automatically deleted when the Python process is killed.
Try it with:
>>> foo = tempfile.NamedTemporaryFile()
>>> foo.name
'c:\\users\\blah\\appdata\\local\\temp\\tmpxxxxxx'
Now check that the named file is there. You can write to and read from this file like any other.
Now kill the Python window and check that file is gone (it should be)
You can simply call foo.close() to delete it manually in your code.
How can you have a function or something that will be executed before your program quits? I have a script that will be constantly running in the background, and I need it to save some data to a file before it exits. Is there a standard way of doing this?
Check out the atexit module:
http://docs.python.org/library/atexit.html
For example, if I wanted to print a message when my application was terminating:
import atexit
def exit_handler():
print 'My application is ending!'
atexit.register(exit_handler)
Just be aware that this works great for normal termination of the script, but it won't get called in all cases (e.g. fatal internal errors).
If you want something to always run, even on errors, use try: finally: like this -
def main():
try:
execute_app()
finally:
handle_cleanup()
if __name__=='__main__':
main()
If you want to also handle exceptions you can insert an except: before the finally:
If you stop the script by raising a KeyboardInterrupt (e.g. by pressing Ctrl-C), you can catch that just as a standard exception. You can also catch SystemExit in the same way.
try:
...
except KeyboardInterrupt:
# clean up
raise
I mention this just so that you know about it; the 'right' way to do this is the atexit module mentioned above.
If you have class objects, that exists during the whole lifetime of the program, you can also execute commands from the classes with the __del__(self) method:
class x:
def __init__(self):
while True:
print ("running")
sleep(1)
def __del__(self):
print("destructuring")
a = x()
this works on normal program end as well if the execution is aborted, for sure there will be some exceptions:
running
running
running
running
running
Traceback (most recent call last):
File "x.py", line 14, in <module>
a = x()
File "x.py", line 8, in __init__
sleep(1)
KeyboardInterrupt
destructuring
This is a version adapted from other answers.
It should work (not fully tested) with graceful exits, kills, and PyCharm stop button (the last one I can confirm).
import signal
import atexit
def handle_exit(*args):
try:
... do computation ...
except BaseException as exception:
... handle the exception ...
atexit.register(handle_exit)
signal.signal(signal.SIGTERM, handle_exit)
signal.signal(signal.SIGINT, handle_exit)