2025, Oct 02 23:17

Как получить current_url во второй вкладке в Selenium

Почему Selenium возвращает текущий URL исходной вкладки и как это исправить: переключаемся через window_handles или строим ссылку из onclick. Пошаговый пример

Если клик в Selenium открывает новую вкладку браузера, то сразу после этого вызов current_url часто возвращает адрес исходной страницы. Драйвер сохраняет фокус на первой вкладке, пока ему явно не скажут переключиться. Поэтому получить URL только что открытой вкладки поначалу бывает непросто.

Воспроизведение проблемы

Следующий скрипт открывает solrenview.com, фильтрует по установщику, выбирает подсказку и кликает по результату, который открывается во второй вкладке. Хотя в браузере новая вкладка заметно активна, в консоли печатается исходный URL.

import time
import os, sys
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
print(f"Program name: {os.path.basename(__file__)}")
TRY_MODE = True
EXIT_AFTER = 10
SAVE_EVERY = 1
WAIT_SEC = 1
base_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
print("Checking Browser driver...")
chrome_opts = Options()
chrome_opts.add_argument("start-maximized")
chrome_opts.add_argument('--use-gl=swiftshader')
chrome_opts.add_argument('--disable-gpu')
chrome_opts.add_argument('--no-sandbox')
chrome_opts.add_argument('--disable-dev-shm-usage')
chrome_opts.add_argument("start-maximized")
chrome_opts.add_argument('--log-level=3')
chrome_opts.add_argument('--enable-unsafe-swiftshader')
svc = Service()
browser = webdriver.Chrome(service=svc, options=chrome_opts)
sync = WebDriverWait(browser, 10)
home_url = "https://www.solrenview.com/"
browser.get(home_url)
sync.until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[@id='gMapsFr']")))
browser.execute_script("arguments[0].click();", sync.until(EC.element_to_be_clickable((By.XPATH, '//label[@for="ByInstaller"]'))))
time.sleep(0.5)
sync.until(EC.presence_of_element_located((By.XPATH, '//input[@id="searchBox"]'))).clear()
time.sleep(0.5)
sync.until(EC.presence_of_element_located((By.XPATH, '//input[@id="searchBox"]'))).send_keys("Barrier Solar Inc.")
time.sleep(0.5)
browser.execute_script("arguments[0].click();", sync.until(EC.element_to_be_clickable((By.XPATH, '//div[@id="autoSuggestionsList"]//li'))))
time.sleep(3)
browser.execute_script("arguments[0].click();", sync.until(EC.element_to_be_clickable((By.XPATH, f'(//a[contains(text(), "Double E")])[{1}]'))))
current_url = browser.current_url
print(current_url)
input("Press!")

Что происходит на самом деле

Selenium не переключает контекст на новое окно или вкладку автоматически. Клик открывает вторую вкладку, но фокус драйвера остаётся на исходной, поэтому current_url относится к первой вкладке. Это запланированное поведение, описанное в разделах Selenium по работе с окнами и вкладками. Прежде чем читать адрес, нужно явно перейти на нужную вкладку.

Документация Selenium: Работа с окнами и вкладками

Прямое решение: переключиться на новую вкладку

Возьмите последний хэндл из window_handles, переключитесь на него и затем прочитайте URL. В нашем случае вторая вкладка будет последним хэндлом.

last_tab = browser.window_handles[-1]
browser.switch_to.window(last_tab)
print(browser.current_url)

Альтернатива: сформировать целевой URL без переключения

На странице целевые ссылки используют onclick вида SiteUrlFunc(5746). Идентификатор внутри onclick совпадает с параметром siteId у конечного адреса. Можно прочитать значение onclick, извлечь id и собрать URL напрямую, не переходя по ссылке.

target = browser.find_element(By.XPATH, f'(//a[contains(text(), "Double E")])[{1}]')
handler = target.get_attribute('onclick')
print('on_click:', handler)
site_id = handler.replace("SiteUrlFunc(", "").replace(");", "")
print('number:', site_id)
print(f"https://www.solrenview.com/SolrenView/mainFr.php?siteId={site_id}")

Полный пример с обоими подходами

Ниже — сквозной пример, который показывает, как получить URL из onclick, а также как переключиться на новую вкладку и взять адрес прямо из браузера.

import time
import os, sys
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
print(f"Program name: {os.path.basename(__file__)}")
TRY_MODE = True
EXIT_AFTER = 10
SAVE_EVERY = 1
WAIT_SEC = 1
base_dir = os.path.abspath(os.path.dirname(sys.argv[0]))
print("Checking Browser driver...")
chrome_opts = Options()
chrome_opts.add_argument("start-maximized")
chrome_opts.add_argument('--use-gl=swiftshader')
chrome_opts.add_argument('--disable-gpu')
chrome_opts.add_argument('--no-sandbox')
chrome_opts.add_argument('--disable-dev-shm-usage')
chrome_opts.add_argument("start-maximized")
chrome_opts.add_argument('--log-level=3')
chrome_opts.add_argument('--enable-unsafe-swiftshader')
svc = Service()
browser = webdriver.Chrome(service=svc, options=chrome_opts)
sync = WebDriverWait(browser, 10)
home_url = "https://www.solrenview.com/"
browser.get(home_url)
sync.until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[@id='gMapsFr']")))
browser.execute_script("arguments[0].click();", sync.until(EC.element_to_be_clickable((By.XPATH, '//label[@for="ByInstaller"]'))))
time.sleep(0.5)
sync.until(EC.presence_of_element_located((By.XPATH, '//input[@id="searchBox"]'))).clear()
time.sleep(0.5)
sync.until(EC.presence_of_element_located((By.XPATH, '//input[@id="searchBox"]'))).send_keys("Barrier Solar Inc.")
time.sleep(0.5)
browser.execute_script("arguments[0].click();", sync.until(EC.element_to_be_clickable((By.XPATH, '//div[@id="autoSuggestionsList"]//li'))))
time.sleep(3)
browser.execute_script("arguments[0].click();", sync.until(EC.element_to_be_clickable((By.XPATH, f'(//a[contains(text(), "Double E")])[{1}]'))))
print(f"{browser.current_url = }")
# Build the URL from onclick
anchor = browser.find_element(By.XPATH, f'(//a[contains(text(), "Double E")])[{1}]')
onclick_val = anchor.get_attribute('onclick')
print('onclick:', onclick_val)
site_id = onclick_val.replace("SiteUrlFunc(", "").replace(");", "")
print('number:', site_id)
print(f"generated: https://www.solrenview.com/SolrenView/mainFr.php?siteId={site_id}")
# Switch to the newly opened tab and print its URL
last_tab = browser.window_handles[-1]
browser.switch_to.window(last_tab)
print(f"last : {browser.current_url = }")
# Switch back to the first tab
first_tab = browser.window_handles[0]
browser.switch_to.window(first_tab)
print(f"first: {browser.current_url = }")
input("Press ENTER to close")

Почему это важно

Во многих веб‑приложениях встречаются сценарии с несколькими вкладками и окнами. Если ожидать, что Selenium автоматически последует за визуально активной вкладкой, можно получить скрытые ошибки, нестабильные проверки и вводящие в заблуждение логи. Явное переключение контекста или построение целевого URL из доступных атрибутов делает автоматизацию стабильнее и понятнее. Когда управление вкладками осознанное, сбор результатов, навигация и завершение сессии становятся предсказуемыми.

Выводы

Когда клик открывает новую вкладку, драйвер остаётся в исходном контексте, пока вы его не переключите. Используйте window_handles, чтобы выбрать нужную вкладку, и только потом читайте current_url. Если страница раскрывает параметры назначения в атрибутах вроде onclick, можно сформировать итоговый адрес без переключения. Эти два приёма экономят время при отладке навигации и делают тестовые сценарии более детерминированными.

Статья основана на вопросе с StackOverflow от Rapid1898 и ответе от furas.