crystal-loot / selenium.cr

Selenium library for Crystal
https://crystal-loot.github.io/selenium.cr/
MIT License
24 stars 7 forks source link

[Question] Is there possible to reuse exists session instead of driver.create_session(capabilities) #24

Closed zw963 closed 1 year ago

zw963 commented 1 year ago

Basically, we need check whether a session is exists, then get the session id, and reuse it.

thanks.

matthewmcgarvey commented 1 year ago

This lists the WebDriver standards https://www.w3.org/TR/webdriver/#sessions and there is no API to get open session ids.

Unless there is a custom API on a browser for getting this, your best bet is to look for how others accomplished it in a custom way. https://stackoverflow.com/questions/8344776/can-selenium-interact-with-an-existing-browser-session

If there is no specific API for this, I'm not interested in implementing/supporting this feature.

zw963 commented 1 year ago

It seem like following java code works, although, i don't understand 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");
}
zw963 commented 1 year ago

Please ignore my previous comment, please let me try describe my issue again.

When crystal code exit unexpectedly, it often cause issue like this:

Unhandled exception: session not created: Session is already started (Selenium::Error)
  from lib/selenium/src/selenium/http_client.cr:13:7 in 'post'

I checked the driver.status and driver.service, it output like this:

driver.status # => #<Selenium::Status:0x7f4bafd32060 @ready=false, @message="Session already started">

driver.service # => #<Selenium::Firefox::Service:0x7f4bafd33bd0 @process=#<Process:0x7f4bafd45dc0 @input=nil, @output=nil, @error=nil, @process_info=Crystal::System::Process(@pid=180842, @channel=#<Channel(Int32):0x7f4bab514040>), @wait_count=0, @channel=nil>, @driver_path="/home/zw963/.webdrivers/geckodriver", @port=4444, @args=[]>

driver.status.ready? is false, The reason cause this is because the previous ran of geckodriver is still running unexpectedly, as following ps output.

zw963      30671  0.1  0.0   8952   788 ?        Sl   Feb02   0:26 /home/zw963/.webdrivers/geckodriver --port=4444

But, the process pid in driver.service is not same as the above running process pid.

I don't know why this issue happen, it maybe a bug? or misuse of this shards? my source code is here

So, any idea for avoid this issue happen or fix it?

for now, i have to use system("pkill geckodriver") to terminate the driver, then retry the driver, but obviously this solution is not the best, why selenium can not use the exist listening driver?

Thanks.

zw963 commented 1 year ago

Cool, i assume after this merged, we can visit several websites (e.g. several translate websites) synchronously use fiber, right?

zw963 commented 1 year ago

But, we are still can't reuse exists session, right?

zw963 commented 1 year ago

Hi, sorry for my this issue even myself still not clear until now.

I guess what i really want is not reuse exists session, i admit that I may not have a clear understanding of many concepts yet, but it seems to be a little better since those days, what i want is (we assume not use headless mode), a chrome browser process keep resident in the memory, which probably make open a new session more quickly then before, as we are doing browse use our browser, open a new tab and visit a site always quicker than close browser, then reopen browser visit same site, right?

Okay, compare to current headless mode, i guess this should be, create a chromedriver(with Capabilities), and keep it resident in the memory, then create a new session and visit site, then session.delete, repeatedly.

If this time i am not understood wrong, what i expect is, reuse a exists chrome driver, right?

Please point me out if this is not necessary completely, or, i am wrong, again?

Thanks.