Seleniumは既存のブラウザセッションと対話できますか?


102

Selenium(WebDriverが望ましい)が、Seleniumクライアントを起動する前にすでに実行されているブラウザーと通信して動作できるかどうかを誰かが知っていますか?

つまり、SeleniumがSeleniumサーバーを使用せずにブラウザーと通信できるかどうかを意味します(たとえば、手動で起動されたInternet Explorerなど)。

回答:


35

これはかなり古い機能のリクエストです実行中のブラウザにWebドライバを接続できるようにします。したがって、公式にはサポートされていません。

ただし、これをサポートすると主張するいくつかの実用的なコードがありますhttps//web.archive.org/web/20171214043703/http//tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/


そのリンクでそれを可能にするクラスを見つけたので、どうもありがとうございましたが、残念ながら、IEではそのソリューションを使用できません(Firefoxでのみ)。通常のIEDriverを起動し、ミドルウェアを使用して他のプロセスからそれと通信します。クラスがIEで機能しない理由がわかれば、よろしくお願いします。ありがとうございました。
エンジェルロメロ2011

ロバート、2018年になりました。答えを更新していただけませんか?
MasterJoe

誰かがそれを必要とする場合に備えて、私はセレンに既存のブラウザセッションを使用させるためにいくつかのJavaコードを試し、テストしました-stackoverflow.com/a/51145789/6648326
MasterJoe 2018

54

これは重複した回答です** python seleniumのドライバーに再接続します**これは、すべてのドライバーとJavaAPIに適用されます。

  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. これらの2つのパラメーターを使用して、ドライバーに接続します。
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")

1
これはまさに私が探していたものです。ありがとう。
milso 2016年

6
重複するダミーブラウザが毎回発生することを除いて、それは私にとってはうまくいきます。
PavelVlasov18年

ダミーウィンドウも表示されます。それほど大きな問題ではありませんが、デバッグ中は煩わしいです。取り除く方法についてのアイデアはありますか?
スティーブゴン

1
+1。2要素認証ログインを回避するという私の目的のために機能しますが、重複するダミーブラウザが存在します。私はそれと一緒に暮らすことができます。
サム

1
selenium.common.exceptions.SessionNotCreatedException: Message: Session is already started
セリン

23

このスニペットを使用すると、既存のブラウザインスタンスを正常に再利用できますが、重複するブラウザが発生することはありません。タルンラルワニのブログで見つかりました。

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を見つける方法をお勧めしますか?
日磨き

おそらく、スクリプトの開始時にexecutor_commandのURLとセッションIDをファイルにダンプし、ブラウザセッションを再度フックするときにファイルから読み取ることができます。
SKVenkat19年

@SKVenkatクロームウィンドウのセッションIDを取得するにはどうすればよいですか?pywinautoを使用して開き、selenuimを実行したいのですが、クロームタブのセッションIDを取得するPythonの方法はありますか
Tayyab Nasir

@TayyabNasir、上記の回答をご覧ください。コメントアウトされた5行目# session_id = driver.session_idは、python seleniumapiを使用してChromeウィンドウのセッションIDを取得する方法です。Chromeセッションの各タブには一意のIDがないと思います。
SKヴェンカト

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;
        }
    }
}

4
この優れたソリューションに基づいて、すでに開いているchromeのブラウザインスタンスに接続する方法について説明した完全なブログ投稿を作成しました。完全なソースコードもそのブログ投稿に添付されています。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を知っているだけで済みます。これらの詳細を取得するには、Seleniumを使用して1つのブラウザーセッションを作成し、目的のページを開いて、最後に実際のテストスクリプトを実行します。

セレンによって作成されていないセッションのセッション情報を取得する方法があるかどうかはわかりません。

セッション情報の例を次に示します。

リモートサーバーのアドレス:http:// localhost:24266。ポート番号はセッションごとに異なります。セッションID:534c7b561aacdd6dc319f60fed27d9d6。


「セレンによって作成されていないセッションのセッション情報を取得する方法があるかどうかはわかりません。」それは実際、私がすでに数日間試してきた問題です...まだ成功していません
2018

@ slesh-そのための新しい質問を作成し、十分な注意が払われない場合は100ポイントを提供することをお勧めします。
MasterJoe

タルン・ラルワニの作品を参照していただきありがとうございます。彼のページとあなたの答えの間で、私はそれを理解することができました。いくつかのステートメントの目的を説明するコメントと同様に、インポートは素晴らしかったでしょう。しかし、すべて、非常に役に立ちました。
ティハマー

4

エリックの答えに触発されて、これがセレン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 2016

1
内部的には、startSession(...)メソッドだけが機能オブジェクトを初期化します。機能オブジェクトは、takeScreenshot、executeScriptなどの多くのメソッドに必要です。ただし、startSessionを実行することにより、新しいセッションを作成する必要があります。このオーバーロードは、新しいセッションの作成をスキップしますが、それでも機能オブジェクトの初期化につながります。
Yanir 2016

おい、文字列を==と比較しないでください
NorillTempest19年

3

Javascriptソリューション:

この機能を使用して、既存のブラウザセッションに正常に接続しました

webdriver.WebDriver.attachToSession(executor, session_id);

ドキュメントはここにあります


3
これは4.0.0バージョンにはありません!
googamanga

1

私はPythonで解決策を得ました、私は見つけたPersistenBrowserクラスに基づいてwebdriverクラスを変更しました。

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

webdriverモジュール/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ブラウザーを開いたままにするモンキーパッチバージョンのSeleniumWebdriverを使用しています。このブログ投稿を参照してください:http//blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/

この投稿に対する私の回答も参照してください:ルビーファイルからすでに開いているブラウザでコマンドを実行するにはどうすればよいですか?


-1

これは、JavaScriptselenium-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
既存のブラウザセッションは使用しません。新しいchromedriverセッションを作成し、新しいブラウザウィンドウを開きます。また、getAllWindowHandles()は、古いブラウザウィンドウのハンドルを表示しません。
2016年

更新:seleniumhq.github.io/selenium/docs/api/javascript/module/…があり ます。これにより、開いている既存のブラウザーウィンドウに接続できます。
2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.