Selenium은 기존 브라우저 세션과 상호 작용할 수 있습니까?


105

Selenium (가급적이면 WebDriver)이 Selenium 클라이언트를 시작하기 전에 이미 실행중인 브라우저와 통신하고이를 통해 작동 할 수 있는지 아는 사람이 있습니까?

Selenium이 Selenium Server를 사용하지 않고 브라우저와 통신 할 수 있다면 (예를 들어 Internet Explorer가 수동으로 시작될 수 있음) 의미합니다.

답변:


35

이것은 꽤 오래된 기능 요청입니다. 웹 드라이버가 실행중인 브라우저에 연결되도록 허용합니다 . 따라서 공식적으로 지원되지 않습니다.

그러나 이것을 지원한다고 주장하는 몇 가지 작동 코드가 있습니다 : https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/ .


그 링크에서 그렇게 할 수있는 클래스를 찾았 기 때문에 대단히 감사합니다. 그러나 불행히도 IE에서는 해당 솔루션을 사용할 수 없습니다 (Firefox에서만). 일반 IEDriver를 시작하고 미들웨어를 사용하여 다른 프로세스와 통신 할 것입니다. 클래스가 IE에서 작동하지 않는 이유를 알고 있다면 감사하겠습니다. 감사합니다.
Angel Romero 2011

로버트, 이제 2018 년. 답변을 업데이트 해 주시겠습니까?
MasterJoe

누구나 필요로하는 경우 셀레늄이 기존 브라우저 세션 ( stackoverflow.com/a/51145789/6648326)을 사용하도록 Java 코드를 시도하고 테스트했습니다 .
MasterJoe

57

이것은 중복 답변입니다 ** python selenium의 드라이버에 다시 연결 ** 이것은 모든 드라이버와 Java API에 적용됩니다.

  1. 운전사를 열다
driver = webdriver.Firefox()  #python
  1. 드라이버 개체에서 session_id 및 _url로 추출합니다.
url = driver.command_executor._url       #"http://127.0.0.1:60622/hub"
session_id = driver.session_id            #'4e167f26-dc1d-4f51-a207-f761eaf73c31'
  1. 이 두 매개 변수를 사용하여 드라이버에 연결하십시오.
driver = webdriver.Remote(command_executor=url,desired_capabilities={})
driver.close()   # this prevents the dummy browser
driver.session_id = session_id

그리고 드라이버와 다시 연결됩니다.

driver.get("http://www.mrsmart.in")

2
이것이 바로 제가 찾던 것입니다. 감사.
milso

6
중복 더미 브라우저가 매번 발생하는 것을 제외하고는 나를 위해 작동합니다.
Pavel Vlasov

나는 또한 더미 창을 얻고 있는데, 그다지 큰 문제는 아니지만 디버깅하는 동안 성가신 일입니다. 제거하는 방법에 대한 아이디어가 있습니까?
Steve Gon

1
+1. 2 단계 인증 로그인을 피하려는 목적으로 작동하지만 중복 된 더미 브라우저가 있습니다. 나는 그것으로 살 수 있습니다.
Sam

1
selenium.common.exceptions.SessionNotCreatedException: Message: Session is already started
Cerin

23

이 스 니펫을 사용하면 기존 브라우저 인스턴스를 성공적으로 재사용 할 수 있지만 중복 브라우저가 발생하지 않습니다. Tarun Lalwani 의 블로그 에서 찾았습니다 .

from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver

# executor_url = driver.command_executor._url
# session_id = driver.session_id

def attach_to_session(executor_url, session_id):
    original_execute = WebDriver.execute
    def new_command_execute(self, command, params=None):
        if command == "newSession":
            # Mock the response
            return {'success': 0, 'value': None, 'sessionId': session_id}
        else:
            return original_execute(self, command, params)
    # Patch the function before creating the driver object
    WebDriver.execute = new_command_execute
    driver = webdriver.Remote(command_executor=executor_url, desired_capabilities={})
    driver.session_id = session_id
    # Replace the patched function with original function
    WebDriver.execute = original_execute
    return driver

bro = attach_to_session('http://127.0.0.1:64092', '8de24f3bfbec01ba0d82a7946df1d1c3')
bro.get('http://ya.ru/')

2
자동화를 통해 기존 세션 ID 및 실행기 URL을 찾는 방법이 있습니까? 제 경우에는 다른 응용 프로그램이 브라우저 세션을 열었고이를 사용하고 싶습니다. 브라우저 세션 ID를 찾는 방법을 추천 해 주시겠습니까?
Sun Shine

아마도 스크립트가 시작될 때 executor_command URL 및 세션 ID를 파일에 덤프하고 브라우저 세션을 다시 연결하고 싶을 때 파일에서 읽을 수 있습니다.
SK Venkat

@SKVenkat 어떻게 크롬 창의 세션 ID를 얻을 수 있습니까? pywinauto를 사용하여 열었고 이제 selenuim을 실행하고 싶습니다. 크롬 탭의 세션 ID를 얻는 파이썬 방법이
있습니까

@TayyabNasir, 위의 답변을 친절하게 살펴보십시오. 주석 처리 된 다섯 번째 줄은 # session_id = driver.session_idpython selenium api를 사용하여 크롬 창의 세션 ID를 검색 할 수있는 방법입니다. 크롬 세션의 각 탭에는 고유 ID가 없다고 생각합니다.
SK Venkat

3
@SK 수동으로 연 크롬 창의 세션 ID를 원합니다. 셀레늄을 사용하여 해당 창을 열지 않았습니다.
Tayyab Nasir

12

것이 가능하다. 하지만 약간 해킹해야합니다. 코드가 있습니다. 독립형 서버를 실행하고 RemoteWebDriver를 "패치"하는 것입니다.

public class CustomRemoteWebDriver : RemoteWebDriver
{
    public static bool newSession;
    public static string capPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionCap");
    public static string sessiodIdPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestFiles", "tmp", "sessionid");

    public CustomRemoteWebDriver(Uri remoteAddress) 
        : base(remoteAddress, new DesiredCapabilities())
    {
    }

    protected override Response Execute(DriverCommand driverCommandToExecute, Dictionary<string, object> parameters)
    {
        if (driverCommandToExecute == DriverCommand.NewSession)
        {
            if (!newSession)
            {
                var capText = File.ReadAllText(capPath);
                var sidText = File.ReadAllText(sessiodIdPath);

                var cap = JsonConvert.DeserializeObject<Dictionary<string, object>>(capText);
                return new Response
                {
                    SessionId = sidText,
                    Value = cap
                };
            }
            else
            {
                var response = base.Execute(driverCommandToExecute, parameters);
                var dictionary = (Dictionary<string, object>) response.Value;
                File.WriteAllText(capPath, JsonConvert.SerializeObject(dictionary));
                File.WriteAllText(sessiodIdPath, response.SessionId);
                return response;
            }
        }
        else
        {
            var response = base.Execute(driverCommandToExecute, parameters);
            return response;
        }
    }
}

5
이 뛰어난 솔루션을 기반으로 이미 열려있는 크롬 브라우저 인스턴스에 연결하는 방법에 대해 논의한 전체 블로그 게시물을 작성했습니다. 전체 소스 코드도 해당 블로그 게시물에 첨부되어 있습니다. binaryclips.com/2015/08/25/…
joinsaad

4

이 기능은 셀레늄에서 공식적으로 지원하지 않는 것으로 보입니다. 그러나 Tarun Lalwani는이 기능을 제공하기 위해 작동하는 Java 코드를 만들었습니다. 참조-http: //tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/

다음은 위 링크에서 복사 한 작업 샘플 코드입니다.

public static RemoteWebDriver createDriverFromSession(final SessionId sessionId, URL command_executor){
    CommandExecutor executor = new HttpCommandExecutor(command_executor) {

    @Override
    public Response execute(Command command) throws IOException {
        Response response = null;
        if (command.getName() == "newSession") {
            response = new Response();
            response.setSessionId(sessionId.toString());
            response.setStatus(0);
            response.setValue(Collections.<String, String>emptyMap());

            try {
                Field commandCodec = null;
                commandCodec = this.getClass().getSuperclass().getDeclaredField("commandCodec");
                commandCodec.setAccessible(true);
                commandCodec.set(this, new W3CHttpCommandCodec());

                Field responseCodec = null;
                responseCodec = this.getClass().getSuperclass().getDeclaredField("responseCodec");
                responseCodec.setAccessible(true);
                responseCodec.set(this, new W3CHttpResponseCodec());
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        } else {
            response = super.execute(command);
        }
        return response;
    }
    };

    return new RemoteWebDriver(executor, new DesiredCapabilities());
}

public static void main(String [] args) {

    ChromeDriver driver = new ChromeDriver();
    HttpCommandExecutor executor = (HttpCommandExecutor) driver.getCommandExecutor();
    URL url = executor.getAddressOfRemoteServer();
    SessionId session_id = driver.getSessionId();


    RemoteWebDriver driver2 = createDriverFromSession(session_id, url);
    driver2.get("http://tarunlalwani.com");
}

테스트에는 기존 브라우저 세션에서 생성 된 RemoteWebDriver가 있어야합니다. 해당 드라이버를 생성하려면 "세션 정보", 즉 브라우저가 실행되는 서버의 주소 (이 경우 로컬)와 브라우저 세션 ID 만 알면됩니다. 이러한 세부 정보를 얻으려면 셀레늄으로 하나의 브라우저 세션을 만들고 원하는 페이지를 연 다음 마지막으로 실제 테스트 스크립트를 실행할 수 있습니다.

셀레늄에 의해 생성되지 않은 세션에 대한 세션 정보를 얻을 수있는 방법이 있는지 모르겠습니다.

다음은 세션 정보의 예입니다.

원격 서버 주소 : http : // localhost : 24266 . 포트 번호는 세션마다 다릅니다. 세션 ID : 534c7b561aacdd6dc319f60fed27d9d6.


"셀레늄에 의해 생성되지 않은 세션에 대한 세션 정보를 얻을 수있는 방법이 있는지 모르겠습니다." 그것은 실제로 내가 이미 며칠 동안 시도해온 문제입니다 ... 아직 성공하지 못했습니다
slesh

@slesh-나는 당신이 그것에 대한 새로운 질문을 만들고 충분한 관심을 얻지 못하면 당신의 포인트를 100 점 제공 할 것을 제안합니다.
MasterJoe

Tarun Lalwani의 작업을 참조 해 주셔서 감사합니다. 그의 페이지와 당신의 대답 사이에서 나는 그것을 알아낼 수있었습니다. 일부 진술의 목적을 설명하는 주석뿐만 아니라 수입도 좋았을 것입니다. 그러나 모든 것이 매우 도움이됩니다.
Tihamer

4

Eric의 대답에 영감을 받아 셀레늄 3.7.0에 대한이 문제에 대한 해결책이 있습니다. http://tarunlalwani.com/post/reusing-existing-browser-session-selenium/ 의 솔루션과 비교할 때 장점은 기존 세션에 연결할 때마다 빈 브라우저 창이 나타나지 않는다는 것입니다.

import warnings

from selenium.common.exceptions import WebDriverException
from selenium.webdriver.remote.errorhandler import ErrorHandler
from selenium.webdriver.remote.file_detector import LocalFileDetector
from selenium.webdriver.remote.mobile import Mobile
from selenium.webdriver.remote.remote_connection import RemoteConnection
from selenium.webdriver.remote.switch_to import SwitchTo
from selenium.webdriver.remote.webdriver import WebDriver


# This webdriver can directly attach to an existing session.
class AttachableWebDriver(WebDriver):
    def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub',
                 desired_capabilities=None, browser_profile=None, proxy=None,
                 keep_alive=False, file_detector=None, session_id=None):
        """
        Create a new driver that will issue commands using the wire protocol.

        :Args:
         - command_executor - Either a string representing URL of the remote server or a custom
             remote_connection.RemoteConnection object. Defaults to 'http://127.0.0.1:4444/wd/hub'.
         - desired_capabilities - A dictionary of capabilities to request when
             starting the browser session. Required parameter.
         - browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object.
             Only used if Firefox is requested. Optional.
         - proxy - A selenium.webdriver.common.proxy.Proxy object. The browser session will
             be started with given proxy settings, if possible. Optional.
         - keep_alive - Whether to configure remote_connection.RemoteConnection to use
             HTTP keep-alive. Defaults to False.
         - file_detector - Pass custom file detector object during instantiation. If None,
             then default LocalFileDetector() will be used.
        """
        if desired_capabilities is None:
            raise WebDriverException("Desired Capabilities can't be None")
        if not isinstance(desired_capabilities, dict):
            raise WebDriverException("Desired Capabilities must be a dictionary")
        if proxy is not None:
            warnings.warn("Please use FirefoxOptions to set proxy",
                          DeprecationWarning)
            proxy.add_to_capabilities(desired_capabilities)
        self.command_executor = command_executor
        if type(self.command_executor) is bytes or isinstance(self.command_executor, str):
            self.command_executor = RemoteConnection(command_executor, keep_alive=keep_alive)

        self.command_executor._commands['GET_SESSION'] = ('GET', '/session/$sessionId')  # added

        self._is_remote = True
        self.session_id = session_id  # added
        self.capabilities = {}
        self.error_handler = ErrorHandler()
        self.start_client()
        if browser_profile is not None:
            warnings.warn("Please use FirefoxOptions to set browser profile",
                          DeprecationWarning)

        if session_id:
            self.connect_to_session(desired_capabilities)  # added
        else:
            self.start_session(desired_capabilities, browser_profile)

        self._switch_to = SwitchTo(self)
        self._mobile = Mobile(self)
        self.file_detector = file_detector or LocalFileDetector()

        self.w3c = True  # added hardcoded

    def connect_to_session(self, desired_capabilities):
        response = self.execute('GET_SESSION', {
            'desiredCapabilities': desired_capabilities,
            'sessionId': self.session_id,
        })
        # self.session_id = response['sessionId']
        self.capabilities = response['value']

그것을 사용하려면 :

if use_existing_session:
    browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
                                  desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER),
                                  session_id=session_id)
    self.logger.info("Using existing browser with session id {}".format(session_id))
else:
    browser = AttachableWebDriver(command_executor=('http://%s:4444/wd/hub' % ip),
                                  desired_capabilities=(DesiredCapabilities.INTERNETEXPLORER))
    self.logger.info('New session_id  : {}'.format(browser.session_id))

3

지금까지 모든 솔루션에는 특정 기능이 없었습니다. 내 해결책은 다음과 같습니다.

public class AttachedWebDriver extends RemoteWebDriver {

    public AttachedWebDriver(URL url, String sessionId) {
        super();
        setSessionId(sessionId);
        setCommandExecutor(new HttpCommandExecutor(url) {
            @Override
            public Response execute(Command command) throws IOException {
                if (command.getName() != "newSession") {
                    return super.execute(command);
                }
                return super.execute(new Command(getSessionId(), "getCapabilities"));
            }
        });
        startSession(new DesiredCapabilities());
    }
}

어떤 기능이 추가됩니까 (다른 기능은 누락 됨)?
jalanb

1
내부적으로 startSession (...) 메서드 만 기능 개체를 초기화합니다. 기능 개체는 takeScreenshot, executeScript 등과 같은 많은 메서드에 필요합니다. 그러나 startSession을 통해 새 세션 생성을 만들어야합니다. 이 오버로드는 새 세션 생성을 건너 뛰지 만 여전히 기능 개체 초기화로 이어집니다.
Yanir

친구, ==와 문자열 비교하지 않는다
Norill 폭풍우

3

자바 스크립트 솔루션 :

이 기능을 사용하여 기존 브라우저 세션에 성공적으로 연결했습니다.

webdriver.WebDriver.attachToSession(executor, session_id);

문서는 여기 에서 찾을 수 있습니다 .


3
이것은 4.0.0 버전이 아닙니다!
googamanga

1

파이썬으로 해결책을 얻었고 내가 찾은 PersistenBrowser 클래스를 기반으로 웹 드라이버 클래스를 수정했습니다.

https://github.com/axelPalmerin/personal/commit/fabddb38a39f378aa113b0cb8d33391d5f91dca5

웹 드라이버 모듈 /usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py 교체

Ej. 쓰다:

from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

runDriver = sys.argv[1]
sessionId = sys.argv[2]

def setBrowser():
    if eval(runDriver):
        webdriver = w.Remote(command_executor='http://localhost:4444/wd/hub',
                     desired_capabilities=DesiredCapabilities.CHROME,
                     )
    else:
        webdriver = w.Remote(command_executor='http://localhost:4444/wd/hub',
                             desired_capabilities=DesiredCapabilities.CHROME,
                             session_id=sessionId)

    url = webdriver.command_executor._url
    session_id = webdriver.session_id
    print url
    print session_id
    return webdriver

0

저는 Rails + Cucumber + Selenium Webdriver + PhantomJS를 사용하고 있으며, 테스트 실행 사이에 PhantomJS 브라우저를 열어 두는 Selenium Webdriver의 원숭이 패치 버전을 사용하고 있습니다. 이 블로그 게시물을 참조하십시오 : http://blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/

이 게시물에 대한 내 답변도 참조하십시오 . 루비 파일에서 이미 열린 브라우저에서 명령을 실행하는 방법


-1

JavaScript selenium-webdriver클라이언트를 사용하면 매우 쉽습니다 .

먼저 WebDriver 서버가 실행 중인지 확인하십시오. 예를 들어 ChromeDriver를 다운로드 한 다음chromedriver --port=9515 .

둘째, 다음 과 같은 드라이버를 만듭니다 .

var driver = new webdriver.Builder()
   .withCapabilities(webdriver.Capabilities.chrome())
   .usingServer('http://localhost:9515')  // <- this
   .build();

다음은 완전한 예입니다.

var webdriver = require ( 'selenium-webdriver');

var driver = new webdriver.Builder()
   .withCapabilities(webdriver.Capabilities.chrome())
   .usingServer('http://localhost:9515')
   .build();

driver.get('http://www.google.com');
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.name('btnG')).click();
driver.getTitle().then(function(title) {
   console.log(title);
 });

driver.quit();

4
EXISTING 브라우저 세션을 사용하지 않습니다. 새 chromedriver 세션을 만들고 새 브라우저 창을 엽니 다. 그리고 getAllWindowHandles ()는 이전 브라우저 창의 핸들을 표시하지 않습니다.
Dzenly

업데이트 : 이미 열려있는 브라우저 창에 연결할 수있는 seleniumhq.github.io/selenium/docs/api/javascript/module/… 이 있습니다.
Dzenly
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.