Bisakah Selenium berinteraksi dengan sesi browser yang ada?

106

Adakah yang tahu jika Selenium (sebaiknya WebDriver) dapat berkomunikasi dan bertindak melalui browser yang sudah berjalan sebelum meluncurkan Selenium Client?

Maksud saya jika Selenium dapat berkomunikasi dengan browser tanpa menggunakan Server Selenium (dengan dapat berupa Internet Explorer diluncurkan secara manual misalnya).

Angel Romero
sumber

Jawaban:

35

Ini adalah permintaan fitur yang cukup lama: Izinkan webdriver melampirkan ke browser yang sedang berjalan . Jadi secara resmi tidak didukung.

Namun, ada beberapa kode yang berfungsi yang mengklaim mendukung ini: https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/ .

Robert Munteanu
sumber
Terima kasih banyak karena di tautan itu saya telah menemukan kelas yang memungkinkan untuk melakukan itu, tetapi sayangnya saya tidak dapat menggunakan solusi itu dengan IE (hanya dengan Firefox). Saya akan meluncurkan IEDriver biasa dan berkomunikasi dengannya dari proses lain menggunakan middleware. Jika Anda tahu mengapa kelas tidak bekerja di IE, saya akan sangat menghargainya. Terima kasih.
Angel Romero
Robert, 2018 sekarang. Bisakah Anda memperbarui jawaban Anda?
MasterJoe
Jika ada yang membutuhkannya, saya telah mencoba dan menguji beberapa kode Java untuk membuat selenium menggunakan sesi browser yang ada - stackoverflow.com/a/51145789/6648326 .
MasterJoe
57

Ini adalah jawaban duplikat ** Hubungkan kembali ke driver dengan python selenium ** Ini berlaku pada semua driver dan untuk java api.

  1. buka driver
driver = webdriver.Firefox()  #python
  1. ekstrak ke session_id dan _url dari objek driver.
url = driver.command_executor._url       #"http://127.0.0.1:60622/hub"
session_id = driver.session_id            #'4e167f26-dc1d-4f51-a207-f761eaf73c31'
  1. Gunakan dua parameter ini untuk terhubung ke driver Anda.
driver = webdriver.Remote(command_executor=url,desired_capabilities={})
driver.close()   # this prevents the dummy browser
driver.session_id = session_id

Dan Anda terhubung ke driver Anda lagi.

driver.get("http://www.mrsmart.in")
Manoj Sahu
sumber
2
Inilah yang saya cari. Terima kasih.
milso
6
Ini berfungsi untuk saya kecuali browser tiruan duplikat meningkat setiap kali.
Pavel Vlasov
Saya mendapatkan jendela tiruan juga, itu bukan masalah besar, tetapi selama debugging itu mengganggu. Ada ide tentang cara menyingkirkan?
Steve Gon
1
+1. Berfungsi untuk tujuan saya menghindari login autentikasi 2 faktor namun ada browser tiruan duplikat. Saya bisa hidup dengan itu.
Sam
1
selenium.common.exceptions.SessionNotCreatedException: Message: Session is already started
Cerin
23

Cuplikan ini berhasil memungkinkan untuk menggunakan kembali browser yang ada, namun tetap menghindari peningkatan browser duplikat. Ditemukan di blog 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/')
Pavel Vlasov
sumber
2
Apakah ada cara untuk menemukan id sesi dan URL pelaksana yang ada melalui otomatisasi? Dalam kasus saya, aplikasi lain membuka sesi browser dan saya ingin menggunakannya. Bisakah Anda merekomendasikan, bagaimana menemukan id sesi browser itu?
Sun Shine
Mungkin Anda dapat membuang executor_command url & session id ke dalam file ketika skrip dimulai dan membacanya dari file ketika Anda ingin menghubungkan sesi browser lagi.
SK Venkat
@SKVenkat bagaimana saya bisa mendapatkan session id dari jendela chrome, saya membukanya menggunakan pywinauto dan sekarang ingin menjalankan selenuim di atasnya, apakah ada cara python untuk mendapatkan session id dari tab chrome
Tayyab Nasir
@TayyabNasir, mohon perhatikan jawaban di atas. Baris kelima yang dikomentari # session_id = driver.session_idadalah cara Anda dapat mengambil id sesi dari jendela chrome menggunakan api selenium python. Saya rasa setiap tab di sesi chrome tidak memiliki ID unik.
SK Venkat
4
@SK Saya ingin sesi Id dari jendela chrome yang saya buka secara manual, saya tidak membuka jendela itu menggunakan selenium
Tayyab Nasir
12

Itu mungkin. Tetapi Anda harus meretasnya sedikit, ada kode Yang harus Anda lakukan adalah menjalankan server yang berdiri sendiri dan "menambal" 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;
        }
    }
}
Alex Ilyin
sumber
5
Berdasarkan solusi luar biasa ini, saya telah menulis posting blog lengkap di mana saya telah membahas cara menyambung ke browser Chrome yang sudah dibuka. Kode sumber lengkap juga dilampirkan di posting blog itu. binaryclips.com/2015/08/25/…
joinsaad
4

Tampaknya fitur ini tidak didukung secara resmi oleh selenium. Namun, Tarun Lalwani telah membuat kode Java yang berfungsi untuk menyediakan fitur tersebut. Lihat - http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/

Berikut adalah kode contoh yang berfungsi, disalin dari tautan di atas:

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

Pengujian Anda harus memiliki RemoteWebDriver yang dibuat dari sesi browser yang ada. Untuk membuat Driver itu, Anda hanya perlu mengetahui "info sesi", yaitu alamat server (lokal dalam kasus kami) tempat browser berjalan dan id sesi browser. Untuk mendapatkan detail ini, kita dapat membuat satu sesi browser dengan selenium, membuka halaman yang diinginkan, dan akhirnya menjalankan script pengujian yang sebenarnya.

Saya tidak tahu apakah ada cara untuk mendapatkan info sesi untuk sesi yang tidak dibuat oleh selenium.

Berikut adalah contoh info sesi:

Alamat server jarak jauh: http: // localhost: 24266 . Nomor port berbeda untuk setiap sesi. ID Sesi: 534c7b561aacdd6dc319f60fed27d9d6.

MasterJoe
sumber
"Saya tidak tahu apakah ada cara untuk mendapatkan info sesi untuk sesi yang tidak dibuat oleh selenium." sebenarnya ini adalah masalah yang telah saya coba selama beberapa hari ... belum berhasil
slesh
@slesh - Saya sarankan Anda membuat pertanyaan baru untuk itu dan mungkin menawarkan 100 poin Anda jika tidak mendapat cukup perhatian.
MasterJoe
Terima kasih atas referensi untuk karya Tarun Lalwani. Antara halamannya dan jawaban Anda, saya bisa memahaminya. Impor akan menyenangkan, serta komentar yang menjelaskan tujuan dari beberapa pernyataan. Tapi semuanya, sangat membantu.
Tihamer
4

Terinspirasi oleh jawaban Eric, inilah solusi saya untuk masalah ini untuk selenium 3.7.0. Dibandingkan dengan solusi di http://tarunlalwani.com/post/reusing-existing-browser-session-selenium/ , keuntungannya adalah tidak akan ada jendela browser kosong setiap kali saya terhubung ke sesi yang ada.

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']

Untuk menggunakannya:

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))
Labu Besar
sumber
3

Semua solusi sejauh ini kurang memiliki fungsi tertentu. Inilah solusi saya:

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());
    }
}
Yanir
sumber
Fungsi apa yang ditambahkan ini (yang lainnya hilang)?
jalanb
1
Secara internal, hanya metode startSession (...) yang akan menginisialisasi objek kapabilitas. Objek kapabilitas diperlukan untuk banyak metode seperti takeScreenshot, executeScript, dan lainnya. Tetapi dengan melalui startSession Anda harus membuat pembuatan sesi baru. Kelebihan beban ini melewatkan pembuatan sesi baru tetapi masih mengarah ke inisialisasi objek kemampuan.
Yanir
Bung, jangan bandingkan string dengan ==
Norill Tempest
3

Solusi Javascript:

Saya berhasil melampirkan ke sesi browser yang ada menggunakan fungsi ini

webdriver.WebDriver.attachToSession(executor, session_id);

Dokumentasi dapat ditemukan di sini .

gm2008
sumber
3
Ini tidak ada dalam versi 4.0.0!
googamanga
1

Saya mendapat solusi dengan python, saya memodifikasi kelas webdriver berdasarkan kelas PersistenBrowser yang saya temukan.

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

ganti modul webdriver /usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py

Ej. menggunakan:

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
Eric Axel
sumber
0

Saya menggunakan Rails + Cucumber + Selenium Webdriver + PhantomJS, dan saya telah menggunakan versi Selenium Webdriver yang di-patch, yang membuat browser PhantomJS tetap terbuka di antara pengujian. Lihat entri blog ini: http://blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/

Lihat juga jawaban saya untuk posting ini: Bagaimana cara menjalankan perintah pada browser yang sudah dibuka dari file ruby

rap1ds
sumber
-1

Ini cukup mudah menggunakan selenium-webdriverklien JavaScript :

Pertama, pastikan Anda menjalankan server WebDriver. Misalnya, unduh ChromeDriver , lalu jalankanchromedriver --port=9515 .

Kedua, buat driver seperti ini :

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

Berikut contoh lengkapnya:

var webdriver = membutuhkan ('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();
Dan Dascalescu
sumber
4
Itu tidak menggunakan sesi browser YANG SUDAH ADA. Ini membuat sesi chromedriver baru dan membuka jendela browser baru. Dan getAllWindowHandles () tidak akan menampilkan pegangan jendela browser lama Anda.
Dzenly
Pembaruan: Ada seleniumhq.github.io/selenium/docs/api/javascript/module/… Yang memungkinkan untuk terhubung ke jendela browser yang terbuka.
Dzenly