Selenium có thể tương tác với một phiên trình duyệt hiện có không?


102

Có ai biết liệu Selenium (tốt nhất là WebDriver) có thể giao tiếp và hành động thông qua một trình duyệt đã chạy trước khi khởi chạy một Selenium Client không?

Ý tôi là nếu Selenium có thể kết nối với trình duyệt mà không cần sử dụng Selenium Server (ví dụ: có thể là Internet Explorer được khởi chạy theo cách thủ công).

Câu trả lời:


35

Đây là một yêu cầu tính năng khá cũ: Cho phép trình duyệt web đính kèm vào trình duyệt đang chạy . Vì vậy, nó chính thức không được hỗ trợ.

Tuy nhiên, có một số mã hoạt động tuyên bố hỗ trợ điều này: https://web.archive.org/web/20171214043703/http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/ .


Cảm ơn bạn rất nhiều vì trong liên kết đó, tôi đã tìm thấy một lớp cho phép làm điều đó, nhưng rất tiếc là tôi không thể sử dụng giải pháp đó với IE (chỉ với Firefox). Tôi sẽ khởi chạy IEDriver thông thường và kết hợp với nó từ các quy trình xử lý khác bằng cách sử dụng phần mềm trung gian. Nếu bạn có ý kiến ​​tại sao lớp học không hoạt động trên IE, tôi sẽ đánh giá cao. Cảm ơn bạn.
Angel Romero

Robert, bây giờ là năm 2018. Bạn có thể vui lòng cập nhật câu trả lời của bạn?
MasterJoe

Trong trường hợp có ai cần, tôi đã thử và kiểm tra một số mã Java để làm cho selen sử dụng phiên trình duyệt hiện có - stackoverflow.com/a/51145789/6648326 .
MasterJoe

54

Đây là một câu trả lời trùng lặp ** Kết nối lại với trình điều khiển trong python selen ** Điều này có thể áp dụng trên tất cả các trình điều khiển và cho java api.

  1. mở một trình điều khiển
driver = webdriver.Firefox()  #python
  1. trích xuất sang session_id và _url từ đối tượng trình điều khiển.
url = driver.command_executor._url       #"http://127.0.0.1:60622/hub"
session_id = driver.session_id            #'4e167f26-dc1d-4f51-a207-f761eaf73c31'
  1. Sử dụng hai tham số này để kết nối với trình điều khiển của bạn.
driver = webdriver.Remote(command_executor=url,desired_capabilities={})
driver.close()   # this prevents the dummy browser
driver.session_id = session_id

Và bạn lại được kết nối với trình điều khiển của mình.

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

1
Điều này thật đúng với gì mà tôi đã tìm kiếm. Cảm ơn.
milso

6
Nó hoạt động đối với tôi ngoại trừ một trình duyệt giả trùng lặp đang tăng lên mỗi lần.
Pavel Vlasov

Tôi cũng nhận được cửa sổ giả, nó không phải là vấn đề lớn, nhưng trong quá trình gỡ lỗi nó gây khó chịu. Bất kỳ ý tưởng về cách thoát khỏi?
Steve Gon

1
+1. Hoạt động cho mục đích của tôi là tránh đăng nhập xác thực 2 yếu tố tuy nhiên vẫn có các trình duyệt giả trùng lặp. Tôi có thể sống với điều đó.
Sam

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

23

Đoạn mã này cho phép sử dụng lại thành công phiên bản trình duyệt hiện có nhưng tránh nâng cao trình duyệt trùng lặp. Tìm thấy tại blog của 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
Có cách nào để tìm id phiên hiện có và URL trình thực thi thông qua tự động hóa không? Trong trường hợp của tôi, một ứng dụng khác đã mở một phiên trình duyệt và tôi muốn sử dụng phiên đó. Bạn có thể vui lòng giới thiệu, làm thế nào để tìm id phiên trình duyệt của đó?
Sun Shine

Có thể bạn có thể kết xuất url executive_command và id phiên vào một tệp khi tập lệnh bắt đầu và đọc nó từ tệp khi bạn muốn nối lại phiên trình duyệt.
SK Venkat

@SKVenkat làm cách nào để lấy id phiên của cửa sổ chrome, tôi đã mở nó bằng pywinauto và bây giờ muốn chạy selenuim trên đó, có cách nào trong python để lấy id phiên của tab chrome không
Tayyab Nasir

@TayyabNasir, vui lòng xem câu trả lời ở trên. Dòng thứ năm được nhận xét # session_id = driver.session_idlà cách bạn có thể truy xuất id phiên của cửa sổ chrome bằng cách sử dụng python selenium api. Tôi đoán rằng mỗi tab trong phiên chrome không có ID duy nhất.
SK Venkat

3
@SK Tôi muốn phiên Id của cửa sổ chrome mà tôi đã mở theo cách thủ công, tôi đã không mở cửa sổ đó bằng selen
Tayyab Nasir

12

Điều đó là có thể. Nhưng bạn phải hack nó một chút, có một đoạn mã Việc bạn phải làm là chạy máy chủ độc lập và "vá" 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
Dựa trên giải pháp tuyệt vời này, tôi đã viết một bài đăng blog hoàn chỉnh, trong đó tôi đã thảo luận về cách kết nối với phiên bản trình duyệt đã mở của chrome. Mã nguồn đầy đủ cũng được đính kèm trên bài đăng blog đó. binaryclips.com/2015/08/25/…
tham gia vào

4

Có vẻ như tính năng này không được hỗ trợ chính thức bởi selen. Tuy nhiên, Tarun Lalwani đã tạo ra mã Java hoạt động để cung cấp tính năng này. Tham khảo - http://tarunlalwani.com/post/reusing-existing-browser-session-selenium-java/

Đây là mã mẫu hoạt động, được sao chép từ liên kết trên:

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

Thử nghiệm của bạn cần phải tạo RemoteWebDriver từ phiên trình duyệt hiện có. Để tạo Trình điều khiển đó, bạn chỉ cần biết "thông tin phiên", tức là địa chỉ của máy chủ (cục bộ trong trường hợp của chúng tôi) nơi trình duyệt đang chạy và id phiên của trình duyệt. Để có được những chi tiết này, chúng ta có thể tạo một phiên trình duyệt với selen, mở trang mong muốn và cuối cùng chạy tập lệnh thử nghiệm thực tế.

Tôi không biết có cách nào để lấy thông tin phiên cho một phiên không được tạo bởi selen không.

Đây là một ví dụ về thông tin phiên:

Địa chỉ của máy chủ từ xa: http: // localhost: 24266 . Số cổng khác nhau cho mỗi phiên. Id phiên: 534c7b561aacdd6dc319f60fed27d9d6.


"Tôi không biết có cách nào để lấy thông tin phiên cho một phiên không được tạo bởi selen hay không." nó thực sự là một vấn đề mà tôi đã cố gắng trong vài ngày rồi ... vẫn chưa thành công
slesh

@slesh - Tôi khuyên bạn nên tạo một câu hỏi mới cho câu hỏi đó và có thể đưa ra 100 điểm nếu câu hỏi đó không gây được sự chú ý.
MasterJoe

Cảm ơn bạn đã tham khảo tác phẩm của Tarun Lalwani. Giữa trang của anh ấy và câu trả lời của bạn, tôi đã có thể tìm ra nó. Việc nhập khẩu sẽ rất tốt, cũng như các bình luận giải thích mục đích của một số tuyên bố. Nhưng tất cả và tất cả, rất hữu ích.
Tihamer

4

Lấy cảm hứng từ câu trả lời của Eric, đây là giải pháp của tôi cho vấn đề này cho selen 3.7.0. So với giải pháp tại http://tarunlalwani.com/post/reusing-existing-browser-session-selenium/ , ưu điểm là sẽ không có cửa sổ trình duyệt trống mỗi khi tôi kết nối với phiên hiện có.

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

Để dùng nó:

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

Tất cả các giải pháp cho đến nay đều thiếu một số chức năng nhất định. Đây là giải pháp của tôi:

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

Chức năng này bổ sung (mà các chức năng khác bị thiếu)?
jalanb

1
Bên trong, chỉ phương thức startSession (...) sẽ khởi tạo đối tượng khả năng. Đối tượng khả năng được yêu cầu cho nhiều phương thức như takeScreenshot, executeScript và hơn thế nữa. Nhưng bằng cách đi qua startSession, bạn sẽ phải tạo một phiên tạo mới. Quá tải này bỏ qua việc tạo một phiên mới nhưng vẫn dẫn đến khởi tạo đối tượng khả năng.
Yanir

anh chàng, đừng so sánh chuỗi với ==
Norill Tempest

3

Giải pháp Javascript:

Tôi đã đính kèm thành công vào phiên trình duyệt hiện có bằng chức năng này

webdriver.WebDriver.attachToSession(executor, session_id);

Tài liệu có thể được tìm thấy ở đây .


3
Đây không phải là phiên bản 4.0.0!
googamanga 19/03/18

1

Tôi có một giải pháp trong python, tôi đã sửa đổi lớp webdriver trên lớp PersistenBrowser mà tôi tìm thấy.

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

thay thế mô-đun webdriver /usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py

Ej. sử dụng:

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

Tôi đang sử dụng Rails + Cucumber + Selenium Webdriver + PhantomJS và tôi đang sử dụng phiên bản vá lỗi của Selenium Webdriver, giúp trình duyệt PhantomJS luôn mở giữa các lần chạy thử nghiệm. Xem bài đăng trên blog này: http://blog.sharetribe.com/2014/04/07/faster-cucumber-startup-keep-phantomjs-browser-open-between-tests/

Xem thêm câu trả lời của tôi cho bài đăng này: Làm cách nào để thực hiện lệnh trên trình duyệt đã mở từ tệp ruby


-1

Điều này khá dễ dàng bằng cách sử dụng JavaScript selenium-webdriver ứng dụng khách :

Trước tiên, hãy đảm bảo rằng bạn có một máy chủ WebDriver đang chạy. Ví dụ: tải xuống ChromeDriver , sau đó chạychromedriver --port=9515 .

Thứ hai, tạo trình điều khiển như sau :

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

Đây là một ví dụ đầy đủ:

var webdriver = demand ('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
Nó không sử dụng phiên trình duyệt TỒN TẠI. Nó tạo một phiên trình điều khiển màu mới và mở một cửa sổ trình duyệt mới. Và getAllWindowHandles () sẽ không hiển thị tay cầm của cửa sổ trình duyệt cũ của bạn.
Dzenly

Cập nhật: Có seleniumhq.github.io/selenium/docs/api/javascript/module/… Cho phép kết nối với cửa sổ trình duyệt đã mở hiện có.
Dzenly
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.