1. 程式人生 > >Selenium Webdriver重新使用已開啟的瀏覽器例項(Chrome版)

Selenium Webdriver重新使用已開啟的瀏覽器例項(Chrome版)

昨天百度了半天關於Selenium Webdriver怎樣重新使用已開啟的瀏覽器的問題,就找到了這麼位大佬的文章:

因為沒積分,程式碼是在這下的

把程式碼下下來研究了半天,勉強算是改了個Chrome版的,能夠在已經開啟的Chrome瀏覽器上繼續操作,但是有很大缺陷,程式碼執行時不會報一些異常了,所以發出來希望有大佬幫忙修改一下,註解是我自己的理解,可能會有錯

一共三個工具類,第一個是修改的ChromeDriver,程式碼如下

import static org.openqa.selenium.remote.CapabilityType.PROXY;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import org.openqa.selenium.Capabilities;
import org.openqa.selenium.ImmutableCapabilities;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.Proxy;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.Command;
import org.openqa.selenium.remote.DriverCommand;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.Response;


public class MyChromeDriver extends ChromeDriver {

	
	// 用於設定capabilities
	private Capabilities myCapabilities;

	public MyChromeDriver(String sessionID,String localserver) {
		mystartClient(localserver);
		mystartSession(sessionID);
	}
	//重寫startSession方法,可以防止呼叫父級startSession方法而導致開啟多個瀏覽器
	@Override
	protected void startSession(Capabilities desiredCapabilities) {
		// Do Nothing
	}
	//改寫的startClient方法,用於傳入localserver(即瀏覽器的地址),配合sessionID能找出在用的瀏覽器
	protected void mystartClient(String localserver) {
		HttpCommandExecutor delegate = null;

		try {
			URL driverserver = new URL(localserver);
			delegate = new MyHttpCommandExecutor(driverserver);
		} catch (MalformedURLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		setCommandExecutor(delegate);
		System.out.println("Connect to the existing browser");
	}
	//改寫的startSession方法,用於傳入sessionID,配合localserver能找出在用的瀏覽器
	protected void mystartSession(String sessionID) {

		if (!sessionID.isEmpty()) {
			super.setSessionId(sessionID);
		}

		Command command = new Command(super.getSessionId(), DriverCommand.STATUS);
		Response response;
		try {
			response = ((MyHttpCommandExecutor)getCommandExecutor()).execute(command);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			System.out.println("Can't use this Session");
			return;
		}
		//列印系統資訊
		System.out.println("response.getValue()" + response.getValue());
		if (response.getValue() instanceof Exception)
		{
			((Exception)response.getValue()).printStackTrace();
		}
		
		//為了能執行Script
		this.myCapabilities = dropCapabilities(new ChromeOptions()) ;

	}
	
	private static Capabilities dropCapabilities(Capabilities capabilities) 
	{
		if (capabilities == null) {
			return new ImmutableCapabilities();
		}

		MutableCapabilities caps = new MutableCapabilities(capabilities);

		// Ensure that the proxy is in a state fit to be sent to the extension
		Proxy proxy = Proxy.extractFrom(capabilities);
		if (proxy != null) {
			caps.setCapability(PROXY, proxy);
		}

		return caps;
}

	@Override
	public void quit() {
		try {
			execute(DriverCommand.QUIT);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public Capabilities getCapabilities() {
		return myCapabilities;
	}

	
}

第二個修改的HttpCommandExecutor,應該是用來設定CommandCodec與ResponseCodec的,不大清楚

import static org.openqa.selenium.remote.DriverCommand.GET_ALL_SESSIONS;
import static org.openqa.selenium.remote.DriverCommand.NEW_SESSION;
import static org.openqa.selenium.remote.DriverCommand.QUIT;

import java.io.IOException;
import java.net.URL;

import org.openqa.selenium.NoSuchSessionException;
import org.openqa.selenium.SessionNotCreatedException;
import org.openqa.selenium.UnsupportedCommandException;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.remote.Command;
import org.openqa.selenium.remote.CommandCodec;
import org.openqa.selenium.remote.Dialect;
import org.openqa.selenium.remote.HttpCommandExecutor;
import org.openqa.selenium.remote.HttpSessionId;
import org.openqa.selenium.remote.ProtocolHandshake;
import org.openqa.selenium.remote.Response;
import org.openqa.selenium.remote.ResponseCodec;
import org.openqa.selenium.remote.http.HttpClient;
import org.openqa.selenium.remote.http.HttpRequest;
import org.openqa.selenium.remote.http.HttpResponse;
import org.openqa.selenium.remote.http.W3CHttpCommandCodec;
import org.openqa.selenium.remote.http.W3CHttpResponseCodec;
import org.openqa.selenium.remote.internal.ApacheHttpClient;


//該類是為了設定CommandCodec與ResponseCodec,父類這些預設為空
public class MyHttpCommandExecutor extends HttpCommandExecutor{
	private CommandCodec<HttpRequest> mycommandCodec;
	private ResponseCodec<HttpResponse> myresponseCodec;
	private final HttpClient myclient;
	
	public MyHttpCommandExecutor(URL addressOfRemoteServer) {
		super(addressOfRemoteServer);
		initCodec();
		this.myclient = new ApacheHttpClient.Factory().createClient(addressOfRemoteServer);
	}
	
	private void initCodec()
	{
		mycommandCodec = new W3CHttpCommandCodec();
		myresponseCodec = new W3CHttpResponseCodec();
	}
	
	@SuppressWarnings("deprecation")
	public Response execute(Command command) throws IOException {
		if (command.getSessionId() == null) {
			if (QUIT.equals(command.getName())) {
				return new Response();
			}
			if (!GET_ALL_SESSIONS.equals(command.getName()) && !NEW_SESSION.equals(command.getName())) {
				throw new NoSuchSessionException("Session ID is null. Using WebDriver after calling quit()?");
			}
		}

		if (NEW_SESSION.equals(command.getName())) {
			if (mycommandCodec != null) {
				throw new SessionNotCreatedException("Session already exists");
			}
			ProtocolHandshake handshake = new ProtocolHandshake();

			ProtocolHandshake.Result result = handshake.createSession(myclient, command);
			Dialect dialect = result.getDialect();
			mycommandCodec = dialect.getCommandCodec();

			myresponseCodec = dialect.getResponseCodec();
			return result.createResponse();
		}

		if (mycommandCodec == null || myresponseCodec == null) {
			throw new WebDriverException("No command or response codec has been defined. Unable to proceed");
		}

		HttpRequest httpRequest = mycommandCodec.encode(command);
		try {

			HttpResponse httpResponse = myclient.execute(httpRequest);

			Response response = myresponseCodec.decode(httpResponse);
			if (response.getSessionId() == null) {
				if (httpResponse.getTargetHost() != null) {
					response.setSessionId(HttpSessionId.getSessionId(httpResponse.getTargetHost()));
				} else {
					// Spam in the session id from the request
					response.setSessionId(command.getSessionId().toString());
				}
			}
			if (QUIT.equals(command.getName())) {
				myclient.close();
			}
			return response;
		} catch (UnsupportedCommandException e) {
			if (e.getMessage() == null || "".equals(e.getMessage())) {
				throw new UnsupportedOperationException(
						"No information from server. Command name was: " + command.getName(), e.getCause());
			}
			throw e;
		}
}
}

然後是個傳參的類,水平太差,只能弄了個檔案儲存資料,希望有大佬能優化一下

package su.jian;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class URLAndSession {

	public String getSessionID() throws IOException {
		FileReader fr = new FileReader("sessionID.txt");  
		BufferedReader br = new BufferedReader(fr);
		String sessionID = br.readLine();
		fr.close();
		return sessionID;
	}

	public void setSessionID(String sessionID) throws IOException {
		FileWriter fw = new FileWriter("sessionID.txt");
		fw.write(sessionID);
		fw.close();
	}

	public String getLocalserver() throws IOException {
		FileReader fr = new FileReader("localserver.txt"); 
		BufferedReader br = new BufferedReader(fr);
		String localserver = br.readLine();
		fr.close();
		return localserver;
	}

	public void setLocalserver(String localserver) throws IOException {
		FileWriter fw = new FileWriter("localserver.txt");
		fw.write(localserver);
		fw.close();
	}

	
	
	
}

最後是用例,能夠在第一個開啟的瀏覽器的同一個標籤開啟新網頁,也可以定位元素,但是不會報異常

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import org.junit.Test;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.HttpCommandExecutor;

public class TestCase {
	
	private static URLAndSession uas = new URLAndSession();
	
	static {
		System.setProperty("webdriver.chrome.driver", "D:/chromedriver_win32/chromedriver.exe");
	}
	
	public static void main(String[] args) throws IOException {
		//這兒沒法用WebDriver定義,因為會沒有getSessionId方法
		ChromeDriver driver = new ChromeDriver();
		//獲取已開啟瀏覽器的sessionId
		String sessionId = driver.getSessionId().toString();
		System.out.println("sessionId:"+sessionId);
		//獲取已開啟瀏覽器的URL
		String url = ((HttpCommandExecutor)(driver.getCommandExecutor())).getAddressOfRemoteServer().toString();
		System.out.println(url);
		//儲存資料
		uas.setSessionID(sessionId);
		uas.setLocalserver(url);
		driver.manage().window().maximize();
		driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
		driver.get("http://www.baidu.com");
	}
	
	@Test
	public void testName() throws Exception {
		
		System.out.println(uas.getSessionID()+"==========="+uas.getLocalserver());
		//構造器獲取sessionId和URL
		ChromeDriver driver = new MyChromeDriver(uas.getSessionID(),uas.getLocalserver());
		driver.get("http://www.sohu.com/");
	}
}
望大佬修改,能給個現成的就更好了