I need to open every new iteration, new browser windows, when I try this code:
class GoogleTest(unittest.TestCase):
def setUp(self):
self.browser = webdriver.Chrome('/home/andrew/Downloads/chromedriver')
self.wait = WebDriverWait(self.browser, 20)
self.browser.implicitly_wait(30)
def test_01_goole(self):
for i in range(3):
browser = self.browser
browser.get('http://www.google.com')
browser.close()
I receive:
WebDriverException: Message: no such session
Related
I want to open several browsers at the same time to perform certain actions at the same time ...
But it performs the action only in the first browser and the 2 does not perform any actions.
What can I do to have both running at the same time?
def selenium_test(profil):
chromeOptions = webdriver.ChromeOptions()
chromeOptions.add_argument(r"user-data-dir=C:\\Users\\name\\AppData\\Local\\Google\\Chrome\\User Data")
chromeOptions.add_argument(r'--profile-directory='+profil)
driver = webdriver.Chrome(options=chromeOptions)
return driver
class BOT:
def __init__(self,selenium_test):
self.driver = selenium_test
def url(self):
driver = self.driver
driver.get("https://www.youtube.com/watch?v=R4P7BSFH_oE")
if __name__ == '__main__':
a = BOT(selenium_test(profil="Profile 2"))
thread1 = a.url()
b = BOT(selenium_test(profil="Profile 3"))
thread2 = b.url()
thread1.start()
thread2.start()
I am currently trying to separate my PyQT5-GUI from my serial communication to prevent a freezing GUI.
Therefore, I tried to implement threading. So when I am pressing a button "Open Port", a new thread starts which handles this incoming and outgoing data of the Port.
Now, this works fine, but I am having problems with a timer not fulfilling its function. Essentially, I want to close the port after a 'no valid' message has been received for x seconds.
I tried to create a minimum example:
Upon starting, the GUI and the thread are created. When pressing "Open", the port is opened and the timer in the thread should start. After 3000 milliseconds, the port should be closed by the timer overflow.
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5 import QtSerialPort
import sys
class AECRobotControl(QMainWindow):
signal_open_port = pyqtSignal(str)
signal_close_port = pyqtSignal(int)
def __init__(self):
super().__init__()
# main-window setup
self.ui = Ui_RobotControls_Main()
self.ui.setupUi(self)
# Port
self.port_gcode_timer_sending = QTimer() # Timer for sending Gcode to prevent robot queue overflow
# END Port
# Threads
self.thread_port = QThread()
self.thread_port_worker = None
# END Threads
# END Variables
# Functions
# Init the ui with standard values
# self.init_ui()
# Init COM-worker
self.init_worker()
# Init signal callbacks
self.init_signals()
# show GUI
self.show()
# END Functions
def init_ui(self):
self.layout.addWidget(self.button_open)
self.layout.addWidget(self.button_close)
self.setLayout(self.layout)
def init_signals(self):
# Button Open Port
self.ui.pushButton_open_port.clicked.connect(self.button_open_comport)
# END Button Open Port
# Button Close Port
self.ui.pushButton_close_port.clicked.connect(self.button_close_comport)
# END Button Close Port
def init_worker(self):
self.thread_port_worker = RobotMessageThread()
self.thread_port_worker.moveToThread(self.thread_port)
self.thread_port.started.connect(self.thread_port_worker.start_thread)
self.thread_port.finished.connect(self.thread_port.deleteLater)
self.thread_port_worker.finished.connect(self.thread_port.quit)
self.thread_port_worker.finished.connect(self.thread_port_worker.deleteLater)
self.signal_open_port.connect(self.thread_port_worker.open_port_slot)
self.signal_close_port.connect(self.thread_port_worker.close_comport)
self.thread_port.start()
def button_open_comport(self):
self.signal_open_port.emit("COM4")
def button_close_comport(self):
if (self.thread_port.isRunning() == True):
self.signal_close_port.emit(0)
def parse_com_message(self, message):
try:
print(message)
except Exception as e:
print(e)
class RobotMessageThread(QObject):
finished = pyqtSignal()
progress = pyqtSignal(int)
com_message_parsed = pyqtSignal(QByteArray)
com_ascii_message_parsed = pyqtSignal(str)
def __init__(self):
super().__init__()
self.port_com_port = QtSerialPort.QSerialPort()
self.port_name = None
self.port_is_alive_timer = QTimer() # Interprets valid received messages as alive-sign from robot.
""" Functions to be called upon start of thread"""
def start_thread(self):
print("Thread started")
self.port_is_alive_timer.timeout.connect(lambda: self.close_comport(1))
""" Inits the port"""
def _init_port(self):
self.port_com_port.setPortName(self.port_name)
self.port_com_port.setBaudRate(QtSerialPort.QSerialPort.BaudRate.Baud115200)
self.port_com_port.setParity(QtSerialPort.QSerialPort.Parity.NoParity)
self.port_com_port.setDataBits(QtSerialPort.QSerialPort.DataBits.Data8)
self.port_com_port.setStopBits(QtSerialPort.QSerialPort.StopBits.OneStop)
#pyqtSlot(bytearray)
def message_slot(self, message: bytearray):
self._write_to_port(message)
#pyqtSlot(str)
def open_port_slot(self, com_name: str):
self.port_name = com_name
self._init_port()
self._open_comport()
#pyqtSlot()
def close_port_slot(self, message: bytearray):
self.close_comport(0)
""" Tries to open the selected comport"""
def _open_comport(self):
# Check whether port is already open
if self.port_com_port.open(QIODevice.ReadWrite) == True:
self.port_com_port.setDataTerminalReady(True)
print("COM Opened")
# Reset message-buffer
self.port_is_alive_timer.start(3000)
else:
print("opening failed")
""" Closes the selected comport"""
def close_comport(self, source):
if self.port_com_port.isOpen() == True:
# Close port and delete queue
self.port_com_port.clear()
self.port_com_port.close()
# Stop timers
self.port_is_alive_timer.stop()
print("Closed by " + str(source))
else:
print("Closing failed")
# GUI
class Ui_RobotControls_Main(object):
def setupUi(self, RobotControls_Main):
RobotControls_Main.setObjectName("RobotControls_Main")
RobotControls_Main.resize(1024, 900)
RobotControls_Main.setMinimumSize(QSize(1024, 900))
RobotControls_Main.setMaximumSize(QSize(1600, 1200))
self.centralwidget = QtWidgets.QWidget(RobotControls_Main)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_12 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_12.setObjectName("gridLayout_12")
self.QGroupBox_port_settings = QtWidgets.QGroupBox(self.centralwidget)
self.QGroupBox_port_settings.setObjectName("QGroupBox_port_settings")
self.gridLayout_15 = QtWidgets.QGridLayout(self.QGroupBox_port_settings)
self.gridLayout_15.setObjectName("gridLayout_15")
self.horizontalLayout_21 = QtWidgets.QHBoxLayout()
self.horizontalLayout_21.setObjectName("horizontalLayout_21")
self.pushButton_open_port = QtWidgets.QPushButton(self.QGroupBox_port_settings)
self.pushButton_open_port.setMaximumSize(QSize(100, 50))
self.pushButton_open_port.setObjectName("pushButton_open_port")
self.horizontalLayout_21.addWidget(self.pushButton_open_port)
self.gridLayout_15.addLayout(self.horizontalLayout_21, 0, 0, 1, 1)
self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
self.horizontalLayout_4.setObjectName("horizontalLayout_4")
self.pushButton_close_port = QtWidgets.QPushButton(self.QGroupBox_port_settings)
self.pushButton_close_port.setObjectName("pushButton_close_port")
self.horizontalLayout_4.addWidget(self.pushButton_close_port)
self.gridLayout_15.addLayout(self.horizontalLayout_4, 0, 1, 1, 1)
self.gridLayout_12.addWidget(self.QGroupBox_port_settings, 0, 0, 1, 1)
RobotControls_Main.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(RobotControls_Main)
self.statusbar.setObjectName("statusbar")
RobotControls_Main.setStatusBar(self.statusbar)
self.retranslateUi(RobotControls_Main)
QMetaObject.connectSlotsByName(RobotControls_Main)
def retranslateUi(self, RobotControls_Main):
_translate = QCoreApplication.translate
RobotControls_Main.setWindowTitle(_translate("RobotControls_Main", "RobotControls"))
self.QGroupBox_port_settings.setTitle(_translate("RobotControls_Main", "Port settings"))
self.pushButton_open_port.setText(_translate("RobotControls_Main", "Open Port"))
self.pushButton_close_port.setText(_translate("RobotControls_Main", "Close Port"))
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = AECRobotControl()
app.exec() # QT main-threadtimer.start(TIME)
I found a solution. In the above code, just one line needs to be added: after moving the worker to the separate thread, the QTimer also has to be moved to the same thread. So, after self.thread_port_worker.moveToThread(self.thread_port), the line self.thread_port_worker.port_is_alive_timer.moveToThread(self.thread_port) needs to be added
This question already has answers here:
WebDriverException: Message: 'chromedriver' executable needs to be in PATH while setting UserAgent through Selenium Chromedriver python
(1 answer)
selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH error with Headless Chrome
(1 answer)
Closed 1 year ago.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import ElementNotInteractableException, NoSuchElementException, StaleElementReferenceException
from random import randint, randrange
#from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
import time
import random
BESTBUY_URL = 'https://www.bestbuy.com/site/sony-playstation-5-digital-edition-console/6430161.p?skuId=6430161'
BESTBUY_TEST_URL = 'https://www.bestbuy.com/site/sony-playstation-5-dualsense-wireless-controller-cosmic-red/6464309.p?skuId=6464309'
WAIT_TIME = 7
PRICE_LIMIT = 500
class Zac:
def __init__(self, username, password):
self.username = username
self.password = password
#binary = FirefoxBinary("/Applications/Firefox.app/Contents/MacOS/firefox-bin")
#self.driver = webdriver.Firefox("Applications/Firefox.app")
driver = webdriver.Chrome(executable_path="Applications/Google Chrome.app")
driver = webdriver.Chrome('/path/to/chromedriver') # Optional argument, if not specified will search path.
def signIn(self):
driver = self.driver
##Username
username_elem = driver.find_element_by_xpath("_____")
username_elem.clear()
username_elem.send_keys(self.username)
time.sleep(randint(int(WAIT_TIME/2), WAIT_TIME))
username_elem.send_keys(Keys.RETURN)
time.sleep(randint(int(WAIT_TIME/2), WAIT_TIME))
##Password
password_elem = driver.find_element_by_xpath("_____")
password_elem.clear()
password_elem.send_keys(self.password)
time.sleep(randint(int(WAIT_TIME/2), WAIT_TIME))
password_elem.send_keys(Keys.RETURN)
time.sleep(randint(int(WAIT_TIME/2), WAIT_TIME))
def findProduct(self):
driver = self.driver
driver.get(BESTBUY_TEST_URL)
time.sleep(randint(int(WAIT_TIME/2), WAIT_TIME))
isAvailable = self.isProductAvailable()
if isAvailable == 'Sold Out':
time.sleep(randint(int(WAIT_TIME/2), WAIT_TIME))
self.findProduct()
elif isAvailable <= PRICE_LIMIT:
buy_now = driver.find_by_name('submit.buy-now')
buy_now.click()
time.sleep(randint(int(WAIT_TIME/2), WAIT_TIME))
self.signIn()
##Place Order
place_order = driver.find_element_by_name('placeYourOrder1').text
time.sleep(randint(int(WAIT_TIME/2), WAIT_TIME))
## place_order.click()
## time.sleep(randict(int(WAIT_TIME/2), WAIT_TIME))
else:
time.sleep(randint(int(WAIT_TIME/2), WAIT_TIME))
self.findProduct()
def isProductAvailable(self):
driver = self.driver
available = driver.find_element_by_class_name('a-color-price').text
if available == 'Currently unavailable.':
print(f'***** AVAILABLE: {available}')
return available
else:
print(f'***** PRICE: {available}')
return float(available[1:]) ## $123.22 -> 123. 22
def closeBrowser(self):
self.driver.close()
if __name__ == '__main__':
shopBot = Zac(username="_____", password="_____")
shopBot.findProduct()
shopBot.closeBrowser()
For some reason, it is saying that Google Chrome.app executable needs to be in PATH. I am trying to make a scalping bot, and this seems to be my biggest mistake area. I am open to using any browser that is easiest. As you can see in the code I first tried this with FireFox. If anybody could help that would be greatly appreciated.
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
path_to_download = '/home/dev/'
options = Options()
options.add_experimental_option("prefs", {
"download.default_directory": path_to_download,
"download.prompt_for_download": False,
"download.directory_upgrade": True,
"safebrowsing.enabled": True
})
options.add_argument('start-maximized')
driver = webdriver.Chrome(executable_path='/home/dev/Downloads/chromedriver_linux64/chromedriver',
options=options)
#long logic
elem2 = WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, "//*[contains(text(), 'Excel')]")))
elem2.click() #downloads the file (export to excel)
for now I am stuck with putting a time.sleep(5) then os.rename(f'{path_to_download}/exported.xlsx',f'{path_to_download}/{my_id}.xlsx')
is there a way of controlling the filename while or before the file is downloaded?
You can achieve that by checking for the file existence in your download directory and loop over and over until the file appears.
You can do someting like that :
# check the size of the file and return 0 if doesn't exist
def getSize(filename):
if os.path.isfile(filename):
st = os.stat(filename)
return st.st_size
else:
return 0
def wait_download(file_path):
current_size = getSize(file_path)
printed = False
start_time = time.time()
# loop over and over until the current_size change
while current_size !=getSize(file_path) or getSize(file_path)==0:
current_size = getSize(file_path)
# print something to the string to know that we are waiting for the file
while printed == False:
print("Downloading file...")
print("Waiting for download to complete...")
printed = True
# Here we add an exit to not loop forever
if (time.time() - start_time) > 15:
return -1
return 0
# In your code you can call the function like that
files = wait_download(f'{path_to_download}/exported.xlsx')
if files == 0:
#do something
else:
# the file didn't download
I am attempting to cache webdriver instances across test case classes. I do not need a "clean" webdriver since I am simply using PhantomJS to query the DOM (I do need JavaScript enabled, which is why I am not simply fetching the source and parsing that).
The cache is a dictionary with the URL as a key and the driver instance as value. The cache is in the base test case, and I call get() which is a method on the base test case. This method instantiates webdriver, and goes to the url if the driver is not in the cache already.
It appears there's some kind of socket issue when trying to access driver properties on the cached instance in the second test case (derivedb.py). I'd appreciate if someone could tell how to get this work.
I am getting the following output:
$ python launcher.py
test_a (deriveda.DerivedTestCaseA) ... Instantiate new driver
Title is: Google
ok
test_b (deriveda.DerivedTestCaseA) ... Retrieve driver from cache
Title is: Google
ok
test_a (derivedb.DerivedTestCaseB) ... Retrieve driver from cache
ERROR
======================================================================
ERROR: test_a (derivedb.DerivedTestCaseB)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/cohenaa/PycharmProjects/sanity/derivedb.py", line 7, in test_a
print "Title is: %s" % self.driver.title
File "/Users/cohenaa/sanity-env/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 185, in title
resp = self.execute(Command.GET_TITLE)
File "/Users/cohenaa/sanity-env/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 162, in execute
response = self.command_executor.execute(driver_command, params)
File "/Users/cohenaa/sanity-env/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 349, in execute
return self._request(url, method=command_info[0], data=data)
File "/Users/cohenaa/sanity-env/lib/python2.7/site-packages/selenium/webdriver/remote/remote_connection.py", line 410, in _request
resp = opener.open(request)
File "/sw/lib/python2.7/urllib2.py", line 404, in open
response = self._open(req, data)
File "/sw/lib/python2.7/urllib2.py", line 422, in _open
'_open', req)
File "/sw/lib/python2.7/urllib2.py", line 382, in _call_chain
result = func(*args)
File "/sw/lib/python2.7/urllib2.py", line 1214, in http_open
return self.do_open(httplib.HTTPConnection, req)
File "/sw/lib/python2.7/urllib2.py", line 1184, in do_open
raise URLError(err)
URLError: <urlopen error [Errno 61] Connection refused>
----------------------------------------------------------------------
Ran 3 tests in 1.271s
FAILED (errors=1)
launcher.py
import unittest
from deriveda import DerivedTestCaseA
from derivedb import DerivedTestCaseB
suite = unittest.TestSuite()
testclasses = [DerivedTestCaseA, DerivedTestCaseB]
testloader = unittest.TestLoader()
classes_to_names = {}
for tc in testclasses:
classes_to_names[tc] = testloader.getTestCaseNames(tc)
for tc in classes_to_names:
for testname in classes_to_names[tc]:
suite.addTest(tc(testname))
unittest.TextTestRunner(verbosity=10).run(suite)
deriveda.py
from basetestcase import BaseTestCase
from unittest import main
class DerivedTestCaseA(BaseTestCase):
def test_a(self):
self.get("http://www.google.com")
print "Title is: %s" % self.driver.title
def test_b(self):
self.get("http://www.google.com")
print "Title is: %s" % self.driver.title
derivedb.py
from basetestcase import BaseTestCase
class DerivedTestCaseB(BaseTestCase):
def test_a(self):
self.get("http://www.google.com")
print "Title is: %s" % self.driver.title
basetestcase.py:
import unittest
from selenium import webdriver
class BaseTestCase(unittest.TestCase):
cache = {}
def get(self, url):
if url not in self.cache:
print "Instantiate new driver"
self.driver = webdriver.PhantomJS()
self.driver.get(url)
self.cache[url] = self.driver
else:
print "Retrieve driver from cache"
self.driver = self.cache[url]
#classmethod
def tearDownClass(cls):
for url in BaseTestCase.cache:
BaseTestCase.cache[url].quit()
Ahhh. I see now. The driver is quitting after each test case. If I quit after the suite is run instead, no error.