Да sleep это зло, согласен )
Тут более подробно:
Да sleep это зло, согласен )
Тут более подробно:
В общем делаю так
s = self.driver.window_handles
print(s)
b = self.driver.current_window_handle
print(b)
time.sleep(10)
self.driver.switch_to.window(b)
Но меня не перекидывает на первую вкладку(
А где код выбора нужной вкладки?
Смотри код, который arturk писал, как вариант:
b = self.driver.current_window_handle
for handle in driver.window_handles:
if driver.switch_to.window(handle).current_window_handle != b
.....
driver.close()
self.driver.switch_to.window(b)
вот еще вариант:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
#....
#....
wait = WebDriverWait(driver, 10)
current_window = driver.current_window_handle
old_windows = driver.window_handles
#open new window here...
#.....
wait.until(ec.new_window_is_opened(old_windows))
new_window = [i for i in driver.window_handles if i not in old_windows]
driver.switch_to.window(new_window[0])
#do something in new window
#....
driver.close()
driver.switch_to.window(current_window)
Я не совсем понял зачем мне выбирать нужную вкладку. Вот как только появились новые вкладки и мой фокус сменился на новую вкладку я тут же хочу перейти на первую, а новые можно и не трогать, а можно и закрыть.
Спасибо за несколько примеров, буду пробовать сейчас.
Фокус сменился у браузера, а у селениума нет. надо явно сказать куда переключить и что закрыть.
Если делаю так
current_window = self.driver.current_window_handle
for handle in self.driver.window_handles:
if self.driver.switch_to.window(handle) != current_window:
self.driver.close()
То замечаю в самом конце, что закрывается первая вкладка - именно так, что мне нужна.
Вот так попробовал
from selenium.webdriver.common.keys import Keys
self.driver.find_element_by_tag_name("body").send_keys(Keys.ALT + Keys.NUMPAD1)
self.driver.switch_to.window(current_window)
Не сработало. Просто не реагирует и все(
Немного непонятно чего именно вы добиваетесь этим кодом )
Из всех команд, работает только закрытие. Хоть фокус и находится на вкладке с pdf документом, но при вызове команды
self.driver.close()
Закрывается именно 1 вкладка (которая нужна), хотя она даже не в фокусе.
У меня есть подозрение, что проблема из-за страниц с pdf. Они может какие-то другие.
Значит так… для селениума нет понятия “вкладка” это в браузере она может выглядеть как вкладка, но селениум видит это как отдельное окно. Посему, когда открывается браузер в первый раз, то селениум начинает работать с ним как с первым окном. Потом, если каким-то образом, вручную или по нажатию на кнопки, открываются другие “вкладки”, то в браузере это выгладит как смена контекста, фокуса или чего угодно еще, но селениум по прежнему видит то, самое первое, окно. Соответственно все команды отправляются именно в него, в том числе и close(). Что бы переключится в другие окна, нам надо узнать как их зовут. Для этого используют driver.window_handles - эта команда вернет список имен всех открытых окон (“вкладок”) включая и нашу текущую. Соответственно, что бы переключится в другое окно, нам надо из этого списка выбрать имя, которое отличается от имени текущего окна, а текущее окно можно узнать по driver.current_window_handle. Важно понимать, что окна (вкладки) открываются не мгновенно, потому перед тем, как искать имена открытых окон, надо подождать. Подождали, нашли новое окно, переключились, закрыли, переключились обратно. Селениум не переключается между окнами сам, это задача программиста.
Спасибо. Уж разжевали дальше некуда. Получается, что я запоминаю свою вкладку, потом нажимаю кнопку и у меня открывается еще 2 вкладки, но фокус остается на первой (именно поэтому close закрывает именно первую вкладку, хотя я вижу содержимое третьей). затем я получаю имена всех вкладок/окон. переключаюсь например на третью (которую вижу сейчас) и закрываю ее, то же самое делаю и со второй вкладкой и в итоге остаюсь на своей первоначальной и фокус перевожу тоже на нее.
Отсюда вопрос - как мне переключаться по вкладкам, если хэндлы каждый раз называются по новому?
Не думаю что хендлы меняются. Они постоянные для каждого открытого окна. Хотя в ОС хендл - это обычно целое число, а вот вебдрайвер их как-то по своему формирует и они больше на guid какого-то com+ обьекта похожи.
Вобщем, выколите себе глаза, или завяжите… да, наверное так лучше будет. Забудьте что вы видите. Ваш драйвер не видит ничего, он просто делает.
Хэндлы не меняются. Или это не хендлы. Они постоянные на время жизни обьекта. Когда окно, процесс, обьект закрываются (уничтожаются), хендл затирается. Если создастся новое окно, у него уже будет другой хендл.
PS: Хендл вебдрайвера для окон выглядит как compound кизяк из 90-х годов, че нельзя просто было обычный ОС хендл использовать, нет надо какого-то своего гов**а намутить и главное ниодно руководство не описывает, как они формируют свой хендл ИД и кроме меня этим вопросом по ходу задался только программист который писал эту часть вебдрайвера.
Спасибо вам большое. Я понял всю логику работы. Я понял как это работает и при помощи каких инструментов.
Мне это нужно было, чтоб я просто видел что делает selemium в окне. но в дальнейшем тесты будут запускаться на гриде. Поэтому я забил. Раз фокус находится в том окне где мне нужно, хотя и вижу я другое окно, то пусть так и будет. Там selenium продолжает делать какие-то действия.
Но перемещение по вкладкам у меня так и не получилось сделать.
Нашел такой пример
import unittest
import time
from selenium import webdriver
import selenium.webdriver.support.ui as ui
from selenium.webdriver.common.keys import Keys
class SwitchHandleTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(30)
self.driver.set_page_load_timeout(30)
def autister_login_test(self, ):
time.sleep(3)
self.driver.get('http:/reddit.com')
time.sleep(3)
window_before = self.driver.window_handles[0]
time.sleep(3)
self.driver.find_element_by_tag_name('body').send_keys(Keys.CONTROL + 't')
time.sleep(3)
window_after = self.driver.window_handles[1]
time.sleep(3)
self.driver.switch_to.window(window_after)
time.sleep(3)
self.driver.get('http://bing.com')
def tearDown(self):
self.driver.quit()
Но оказалось, что sendkeys в хромдрайвере не работает.
Немного поменял и все получилось. В зависимости от того, что мы ставим в switch_to.windows(after или before) мы перемещаем фокус либо на 1 вкладку, либо во вторую.
import unittest
import time
from selenium import webdriver
import selenium.webdriver.support.ui as ui
from selenium.webdriver.common.keys import Keys
class SwitchHandleTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(30)
self.driver.set_page_load_timeout(30)
def autister_login_test(self, ):
self.driver.get('http:/reddit.com')
time.sleep(3)
window_before = self.driver.window_handles[0]
self.driver.execute_script("window.open('http://youtube.com/');")
time.sleep(3)
window_after = self.driver.window_handles[1]
self.driver.switch_to.window(window_after)
self.driver.get('http://bing.com')
time.sleep(3)
self.driver.close()
def tearDown(self):
self.driver.quit()
Спасибо всем .что помогли. Задачу решил. Потратил на это 2 дня. Ужасное решение, но самое главное, что работает.
Смоделировал ситуацию, как у меня. 3 вкладки, мне нужно переместиться на первую и продолжить в ней работу, а остальные можно закрыть.
Вот код.
import unittest
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
class SwitchHandleTest(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(30)
self.driver.set_page_load_timeout(30)
def autister_login_test(self, ):
self.driver.get('http:/ya.ru',)
window_before = self.driver.window_handles[0]
self.driver.execute_script("window.open('http://youtube.com/');")
self.driver.execute_script("window.open('http://bing.com/');")
window_after = self.driver.window_handles[1]
self.driver.switch_to.window(window_after)
time.sleep(3)
self.driver.close()
window_after1 = self.driver.window_handles[1]
self.driver.switch_to.window(window_after1)
self.driver.close()
self.driver.switch_to.window(window_before)
self.driver.find_element(By.XPATH, "//input[@id='text']").send_keys('Какой же позорный костыль')
self.driver.find_element(By.XPATH, "//button[@type='submit']").click()
time.sleep(3)
def tearDown(self):
self.driver.quit()
Все же закрыть другие окна нужно, так как есть определенные действия на странице, которые могут не сработать, если окно не в фокусе, например всяческие обработчики, навешанные на события перерисовки, браузер просто не будет их взвывать, если окно не в фокусе.
Такое решение будет работать в большинстве случаев, но не всегда. Так как список окон, который возвращает window_handles это неупорядоченный список (set), и в нем совсем не гарантируется то, что новые окна будут отсортированы в порядке появления и иметь соответствующие индексы, особенно в ситуациях, когда уже есть открытые окна. Но такие ситуации к счастью довольно редки.
А это надо заменить на явное ожидание:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
wait = WebDriverWait(driver, 10)
wait.until(ec.new_window_is_opened(old_windows))
#или
wait.until(ec.number_of_windows_to_be(3)) # 2,1 etc.