ซีลีเนียมสามารถโต้ตอบกับเซสชันเบราว์เซอร์ที่มีอยู่ได้หรือไม่?


106

มีใครทราบบ้างว่า Selenium (ควรใช้ WebDriver) สามารถสื่อสารและดำเนินการผ่านเบราว์เซอร์ที่ทำงานอยู่ก่อนเปิดตัว Selenium Client ได้หรือไม่?

ฉันหมายถึงถ้า Selenium สามารถสื่อสารกับเบราว์เซอร์ได้โดยไม่ต้องใช้ Selenium Server (อาจเป็น Internet Explorer ที่เปิดใช้งานด้วยตนเอง)

คำตอบ:


35

นี่เป็นคำขอคุณลักษณะที่ค่อนข้างเก่า: อนุญาตให้ webdriver แนบกับเบราว์เซอร์ที่กำลังทำงานอยู่ ดังนั้นจึงไม่รองรับอย่างเป็นทางการ

แต่มีบางรหัสการทำงานซึ่งอ้างว่าให้การสนับสนุนนี้: https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/


ขอบคุณมากเพราะในลิงก์นั้นฉันพบคลาสที่อนุญาตให้ทำเช่นนั้นได้ แต่น่าเสียดายที่ฉันไม่สามารถใช้โซลูชันนั้นกับ IE ได้ (เฉพาะกับ Firefox) ฉันจะเปิดตัว IEDriver ปกติและสื่อสารกับมันจากกระบวนการอื่นโดยใช้มิดเดิลแวร์ หากคุณมีความคิดว่าทำไมชั้นเรียนถึงไม่ทำงานบน IE ฉันจะขอบคุณ ขอขอบคุณ.
Angel Romero

โรเบิร์ตปี 2018 ตอนนี้ คุณช่วยปรับปรุงคำตอบของคุณได้ไหม
MasterJoe

ในกรณีที่คนต้องการมันผมได้พยายามและทดสอบบางรหัส Java เพื่อให้การใช้ซีลีเนียมเซสชั่นเบราว์เซอร์ที่มีอยู่ - stackoverflow.com/a/51145789/6648326
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 ปัจจัยอย่างไรก็ตามมีเบราว์เซอร์จำลองที่ซ้ำกันอยู่ ฉันอยู่กับสิ่งนั้นได้
แซม

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
มีวิธีค้นหารหัสเซสชันและ URL ของตัวดำเนินการที่มีอยู่ผ่านระบบอัตโนมัติหรือไม่ ในกรณีของฉันแอปพลิเคชันอื่นเปิดเซสชันเบราว์เซอร์และฉันต้องการใช้สิ่งนั้น คุณช่วยแนะนำวิธีค้นหารหัสเซสชันของเบราว์เซอร์ได้อย่างไร
Sun Shine

เป็นไปได้ว่าคุณสามารถถ่ายโอนไฟล์ executor_command url & session id ลงในไฟล์เมื่อสคริปต์เริ่มต้นและอ่านจากไฟล์เมื่อคุณต้องการเชื่อมต่อเซสชันเบราว์เซอร์อีกครั้ง
SK Venkat

@SKVenkat ฉันจะรับรหัสเซสชันของหน้าต่างโครเมี่ยมได้อย่างไรฉันเปิดโดยใช้ pywinauto และตอนนี้ต้องการเรียกใช้ selenuim มีวิธี python ในการรับรหัสเซสชันของแท็บ chrome หรือไม่
Tayyab Nasir

@TayyabNasir โปรดดูคำตอบข้างต้น บรรทัดที่ห้าที่แสดงความคิดเห็น# session_id = driver.session_idคือวิธีที่คุณสามารถดึงรหัสเซสชันของหน้าต่างโครเมี่ยมโดยใช้ python selenium api ฉันเดาว่าแต่ละแท็บในเซสชัน Chrome ไม่มี ID ที่ไม่ซ้ำกัน
SK Venkat

5
@SK ฉันต้องการรหัสเซสชันของหน้าต่างโครเมี่ยมที่ฉันเปิดด้วยตนเองฉันไม่ได้เปิดหน้าต่างนั้นโดยใช้ซีลีเนียม
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
จากโซลูชันที่ยอดเยี่ยมนี้ฉันได้เขียนบล็อกโพสต์ที่สมบูรณ์ซึ่งฉันได้พูดถึงวิธีเชื่อมต่อกับเบราว์เซอร์ Chrome ที่เปิดอยู่แล้ว นอกจากนี้ยังแนบซอร์สโค้ดแบบเต็มในโพสต์บล็อกนั้นด้วย binaryclips.com/2015/08/25/…
joinaad

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 ที่สร้างขึ้นจากเซสชันเบราว์เซอร์ที่มีอยู่ ในการสร้างไดร์เวอร์นั้นคุณจำเป็นต้องรู้ "ข้อมูลเซสชัน" เท่านั้นนั่นคือที่อยู่ของเซิร์ฟเวอร์ (ในกรณีของเรา) ที่เบราว์เซอร์ทำงานอยู่และรหัสเซสชันของเบราว์เซอร์ ในการรับรายละเอียดเหล่านี้เราสามารถสร้างหนึ่งเซสชันเบราว์เซอร์ที่มีซีลีเนียมเปิดหน้าที่ต้องการจากนั้นเรียกใช้สคริปต์ทดสอบจริงในที่สุด

ฉันไม่รู้ว่ามีวิธีรับข้อมูลเซสชันของเซสชันที่ไม่ได้สร้างโดยซีลีเนียมหรือไม่

นี่คือตัวอย่างของข้อมูลเซสชัน:

ที่อยู่ของเซิร์ฟเวอร์ระยะไกล: http: // localhost: 24266 หมายเลขพอร์ตแตกต่างกันสำหรับแต่ละเซสชัน รหัสเซสชัน: 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 (... ) จะเริ่มต้นอ็อบเจ็กต์ความสามารถ อ็อบเจ็กต์ความสามารถจำเป็นสำหรับหลาย ๆ วิธีเช่น takeSc screenshot, executeScript และอื่น ๆ แต่เมื่อผ่าน startSession คุณจะต้องสร้างการสร้างเซสชันใหม่ การโอเวอร์โหลดนี้จะข้ามการสร้างเซสชันใหม่ แต่ยังคงนำไปสู่การเตรียมใช้งานอ็อบเจ็กต์ความสามารถ
Yanir

เพื่อนอย่าเปรียบเทียบสตริงกับ ==
Norill Tempest

3

โซลูชัน Javascript:

ฉันเชื่อมต่อกับเซสชันเบราว์เซอร์ที่มีอยู่สำเร็จแล้วโดยใช้ฟังก์ชันนี้

webdriver.WebDriver.attachToSession(executor, session_id);

เอกสารที่สามารถพบได้ที่นี่


3
นี่ไม่ได้อยู่ในเวอร์ชัน 4.0.0!
googamanga

1

ฉันได้วิธีแก้ปัญหาใน python ฉันแก้ไขคลาส webdriver ที่อยู่ในคลาส PersistenBrowser ที่ฉันพบ

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 และฉันใช้ Selenium Webdriver เวอร์ชันแพทช์ลิงซึ่งเปิดเบราว์เซอร์ PhantomJS ระหว่างการทดสอบ ดูบล็อกโพสต์นี้: http://blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/

ดูคำตอบของฉันสำหรับโพสต์นี้: ฉันจะรันคำสั่งบนเบราว์เซอร์ที่เปิดอยู่แล้วจากไฟล์ทับทิมได้อย่างไร


-1

มันค่อนข้างง่ายโดยใช้selenium-webdriverไคลเอนต์JavaScript :

ขั้นแรกตรวจสอบให้แน่ใจว่าคุณมีเซิร์ฟเวอร์ WebDriver ที่ทำงานอยู่ ตัวอย่างเช่น,การดาวน์โหลด ChromeDriverchromedriver --port=9515เรียกใช้แล้ว

ประการที่สองสร้างไดรเวอร์เช่นนี้ :

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

นี่คือตัวอย่างที่สมบูรณ์:

var webdriver = ต้องใช้ ('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 () จะไม่แสดงหมายเลขอ้างอิงของหน้าต่างเบราว์เซอร์เก่าของคุณ
Dzenly

ปรับปรุง: มี seleniumhq.github.io/selenium/docs/api/javascript/module/…ซึ่งอนุญาตให้เชื่อมต่อกับหน้าต่างเบราว์เซอร์ที่เปิดอยู่
Dzenly
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.