重構SeleniumeDownloader底層瀏覽器驅動

2023-03-10 18:02:32

一、解決bug:Selenium with PhantomJS,重構SeleniumeDownloader底層瀏覽器驅動

0、小背景:

想爬取外網steam的資料,但是steam官網在海外,加上steam處於反爬考慮,對於非同步資料-json資料進行處理,導致如果直接去拿人家的ajax介面作為請求url進行爬取就爬取得到一堆亂碼的沒用資料。---解決:使用Selenium 模擬使用者使用瀏覽器(通過js渲染),然後再解析處理selenium下載器下載下來的資料。
但是一開始,專案中selenium底層是使用phantomjs 作為驅動器(瀏覽器),出現瞭如下的一系列:

1、bug 截圖

  • 找不到變數xxx

  • 報錯資訊:
[ERROR - 2023-03-07T12:00:29.232Z] Session [258893b0-bcdf-11ed-9fc2-3f99c08d4ed8] - page.onError - msg: ReferenceError: Can't find variable: InitMiniprofileHovers

  phantomjs://platform/console++.js:263 in error
[ERROR - 2023-03-07T12:00:29.233Z] Session [258893b0-bcdf-11ed-9fc2-3f99c08d4ed8] - page.onError - stack:
  global code (https://store.steampowered.com/charts/topselling/SG:671)

  phantomjs://platform/console++.js:263 in error
[ERROR - 2023-03-07T12:00:30.743Z] Session [258893b0-bcdf-11ed-9fc2-3f99c08d4ed8] - page.onError - msg: ReferenceError: Can't find variable: WebStorage

  phantomjs://platform/console++.js:263 in error
[ERROR - 2023-03-07T12:00:30.744Z] Session [258893b0-bcdf-11ed-9fc2-3f99c08d4ed8] - page.onError - stack:
  (anonymous function) (https://store.st.dl.eccdnx.com/public/shared/javascript/shared_responsive_adapter.js?v=TNYlyRmh1mUl&l=schinese&_cdn=china_eccdnx:43)
  l (https://store.st.dl.eccdnx.com/public/shared/javascript/jquery-1.8.3.min.js?v=.TZ2NKhB-nliU&_cdn=china_eccdnx:2)
  fireWith (https://store.st.dl.eccdnx.com/public/shared/javascript/jquery-1.8.3.min.js?v=.TZ2NKhB-nliU&_cdn=china_eccdnx:2)
  ready (https://store.st.dl.eccdnx.com/public/shared/javascript/jquery-1.8.3.min.js?v=.TZ2NKhB-nliU&_cdn=china_eccdnx:2)
  A (https://store.st.dl.eccdnx.com/public/shared/javascript/jquery-1.8.3.min.js?v=.TZ2NKhB-nliU&_cdn=china_eccdnx:2)

  phantomjs://platform/console++.js:263 in error
[ERROR - 2023-03-07T12:00:30.746Z] Session [258893b0-bcdf-11ed-9fc2-3f99c08d4ed8] - page.onError - msg: ReferenceError: Can't find variable: GetNavCookie

2、待爬取的頁面是存在該變數的:InitMiniprofileHovers、GetNavCookie

3、偵錯-核心步驟

  • 斷點入口
Page page = downloader.download(request, this);//爬蟲任務的下載器,開始下載頁面
  • SeleniumDownloader
//獲取到web驅動器
webDriver = webDriverPool.get();
//驅動器下載頁面
webDriver.get(request.getUrl());//這裡出錯

▪ webDriver變數的情況:

  • RemoteWebDriver
 this.execute("get", ImmutableMap.of("url", url));//執行下載命令

response = this.executor.execute(command);//響應體,即執行命令後的結果
//command 只是一個封裝了sessionId, driverCommand-get, 請求引數url的物件
  • PhantomJSCommandExecutor
Response var2 = super.execute(command);

...


4、分析錯誤原因:

報錯原因:是phantomis設計的不夠合理: 在頁面尋找不到dom元素的時候,合理設計應該返回nul,而不應該throw異常。

網友的錯誤原因--加密方式,理由:PhantomJS使用的加密方式是SSLv3,有些網站用的是TLS。

解決加密問題的方法:--ignore-ssl-errors=true 和 --ssl-protocol=any

▷ 自己的專案中的 web驅動器/瀏覽器(排除加密方式的原因):

5、小心得:

phantomjs在對ES6的支援上天生有坑,前端使用ES6的網站都不建議用phantomis去跑。

6、解決:使用 chrome 代替 PhantomJS

7、新的問題:chrome 解析外網的時候,不穩定

  • 解決---vpn
  • 現在思路就變成了Selenium 在呼叫瀏覽器 chrome 的時候,開vpn,預設整合到 Selenium中的瀏覽器,都是普通純淨的瀏覽器。

發現微軟的瀏覽器Edge 開啟steam 官網,不開vpn,也很流暢,不過要是steam的連結帶上地理位置,例如香港,又打不開了,解決:vpn



二、改寫Selenium的瀏覽器-目的為了新增代理

1、基本思路:先理清業務的邏輯

發現,在專案呼叫完爬蟲框架的排程器後,下載器開始發揮作用。

case CHROME:
                    if (isWindows) {
                        System.setProperty("selenuim_config", "C:\\data\\config\\config-chrome.ini");
                        SeleniumDownloader seleniumDownloader = new SeleniumDownloader("C:\\data\\config\\chromedriver.exe");
                        // 瀏覽器開啟10s後才開始爬取資料
                        seleniumDownloader.setSleepTime(10 * 1000);
                        autoSpider.setDownloader(seleniumDownloader);
                    }

業務中,我們是通過了建立了SeleniumDownloader的下載器來下載頁面,但是確定就是底層的瀏覽器是純淨普通版的瀏覽器。

看到業務在建立SeleniumDownloader的下載器的時候,給它注入了一個組態檔config-chrome.ini,


2、個人解決思路1:考慮把代理的options 也通過這個組態檔注入

但是發現這個組態檔是一個啟動檔案,裡面並沒options的屬性可以設定。

啟動檔案的設定,沒法實現


3、個人解決思路2:看看SeleniumDownloader的下載器底層的瀏覽器驅動池WebDriverPool

是否有暴露給外界什麼屬性可以設定options,閱讀原始碼後,發現它只暴露一個屬性就是設定啟動檔案config-chrome.ini。

public void configure() throws IOException {
		// Read config file
		sConfig = new Properties();
		String configFile = DEFAULT_CONFIG_FILE;
		if (System.getProperty("selenuim_config")!=null){
			configFile = System.getProperty("selenuim_config");
		}
		sConfig.load(new FileReader(configFile));

		// Prepare capabilities
		sCaps = new DesiredCapabilities();
		sCaps.setJavascriptEnabled(true);
		sCaps.setCapability("takesScreenshot", false);

		String driver = sConfig.getProperty("driver", DRIVER_PHANTOMJS);

		// Fetch PhantomJS-specific configuration parameters
		......
}

4、個人解決思路3:重寫底層的瀏覽器驅動池WebDriverPool,然後再重寫一個呼叫該WebDriverPool的下載器

下載器和驅動器管理池都是在官網提供的原始碼的基礎進行修改;

SeleniumDownloader2:在SeleniumDownloader基礎上新增了代理列舉屬性proxyEnum,並使用了自己重寫的瀏覽器驅動池WebDriverPool2

WebDriverPool2:改寫了 WebDriverPool的構造器,以及改寫了初始化 WebDriver範例的configure方法(目的,就是為了增加上像代理等的options選項)

  • 當然,還增加了一個輪詢方法incrForLoop,目的就是為了獲得代理列表的索引

■ WebDriverPool2:

  • 用省略號表示代理和官網的是一摸一樣的!

  • 細節: ChromeOptions需要設定ssl協定(官網給出的demo沒加,導致我開vpn一直沒成功,又沒提示.....)

    ​ 分析和解決:因為https=http+ssl/tls,我們通過瀏覽器存取的時候,瀏覽器會把所有url地址都處理成安全通訊協定,所以程式碼中需要設定ssl協定

public class WebDriverPool2 {
	......
    /** 代理列舉引數 */
    private final ProxyEnum proxyEnum;
    /** 代理列表 */
    private List<String> proxies;
    /** ip代理列表的索引 */
    private final AtomicInteger pointer = new AtomicInteger(-1);
	......
        
    /**
     * 初始化一個 WebDriver 範例
     * @throws IOException 異常
     */
    public void configure() throws IOException {
       ......
        if (isUrl(driver)) {
            sCaps.setBrowserName("phantomjs");
            mDriver = new RemoteWebDriver(new URL(driver), sCaps);
        } else if (driver.equals(DRIVER_FIREFOX)) {
            mDriver = new FirefoxDriver(sCaps);
        } else if (driver.equals(DRIVER_CHROME)) {
            if(proxyEnum == ProxyEnum.VPN_ENABLE || proxyEnum == ProxyEnum.PROXY_ENABLE){
                //給谷歌瀏覽器,新增上ip代理或vpn等options
                ChromeOptions options = new ChromeOptions();
                //禁止載入圖片
                options.addArguments("blink-settings=imagesEnabled=false");
                Proxy proxy = new Proxy();
                String httpProxy = proxies.get(incrForLoop());
                // 需要設定ssl協定
                proxy.setHttpProxy(httpProxy).setSslProxy(httpProxy);
                options.setCapability("proxy",proxy);
                sCaps.setCapability(ChromeOptions.CAPABILITY, options);
                logger.info("chrome webDriver proxy is : " + proxy);
            }
            mDriver = new ChromeDriver(sCaps);
        } else if (driver.equals(DRIVER_PHANTOMJS)) {
            mDriver = new PhantomJSDriver(sCaps);
        }
    }


    /**
     * 輪詢:從代理列表選出一個代理的索引
     * @return 索引
     */
    private int incrForLoop() {
        int p = pointer.incrementAndGet();
        int size = proxies.size();
        if (p < size) {
            return p;
        }
        while (!pointer.compareAndSet(p, p % size)) {
            p = pointer.get();
        }
        return p % size;
    }

    public WebDriverPool2(int capacity, ProxyEnum proxyEnum, MasterWebservice masterWebservice) {
        this.capacity = capacity;
        //設定代理的情況
        this.proxyEnum = proxyEnum;
        //vpn的情況
        if(proxyEnum == ProxyEnum.VPN_ENABLE){
            this.proxies = masterWebservice.getVpn();
        //ip代理的情況
        }else if(proxyEnum == ProxyEnum.PROXY_ENABLE){
            //獲取動態生成的ip列表,帶有埠的,引數形式舉例 42.177.155.5:75114
            this.proxies = masterWebservice.getProxyIps();
        }
    }

}

■ SeleniumDownloader2:

/**
 * 在SeleniumDownloader基礎上新增了代理列舉屬性proxyEnum
 * 並且要把官網SeleniumDownloader程式碼中使用WebDriverPool(實際是使用上咱改寫的WebDriverPool2)的方法引入,還有使用到WebDriverPool的方法
 * 中,需要的屬性,要注意父類別中被設定私有,需要重寫一下(從父類別copy到子類就行啦)
 */
public class SeleniumDownloader2 extends SeleniumDownloader {
    private volatile WebDriverPool2 webDriverPool;
    
    /** 代理列舉引數 */
    private ProxyEnum proxyEnum;
    /** 通過masterWebservice獲得遠端的動態ip列表 */
    private MasterWebservice masterWebservice;
    
    public SeleniumDownloader2(String chromeDriverPath, ProxyEnum proxyEnum, MasterWebservice masterWebservice) {
        System.getProperties().setProperty("webdriver.chrome.driver",
                chromeDriverPath);
        this.proxyEnum = proxyEnum;
        this.masterWebservice = masterWebservice;
    }
    
    ......
}

■ seleniume 包下的下載器和瀏覽器如下:

■ 官網提供的WebDriverPool:

package us.codecraft.webmagic.downloader.selenium;

import org.apache.log4j.Logger;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;

import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author [email protected] <br>
 *         Date: 13-7-26 <br>
 *         Time: 下午1:41 <br>
 */
class WebDriverPool {
	private Logger logger = Logger.getLogger(getClass());

	private final static int DEFAULT_CAPACITY = 5;

	private final int capacity;

	private final static int STAT_RUNNING = 1;

	private final static int STAT_CLODED = 2;

	private AtomicInteger stat = new AtomicInteger(STAT_RUNNING);

	/*
	 * new fields for configuring phantomJS
	 */
	private WebDriver mDriver = null;
	private boolean mAutoQuitDriver = true;

	private static final String DEFAULT_CONFIG_FILE = "/data/webmagic/webmagic-selenium/config.ini";
	private static final String DRIVER_FIREFOX = "firefox";
	private static final String DRIVER_CHROME = "chrome";
	private static final String DRIVER_PHANTOMJS = "phantomjs";

	protected static Properties sConfig;
	protected static DesiredCapabilities sCaps;

	/**
	 * Configure the GhostDriver, and initialize a WebDriver instance. This part
	 * of code comes from GhostDriver.
	 * https://github.com/detro/ghostdriver/tree/master/test/java/src/test/java/ghostdriver
	 * 
	 * @author [email protected]
	 * @throws IOException
	 */
	public void configure() throws IOException {
		// Read config file
		sConfig = new Properties();
		String configFile = DEFAULT_CONFIG_FILE;
		if (System.getProperty("selenuim_config")!=null){
			configFile = System.getProperty("selenuim_config");
		}
		sConfig.load(new FileReader(configFile));

		// Prepare capabilities
		sCaps = new DesiredCapabilities();
		sCaps.setJavascriptEnabled(true);
		sCaps.setCapability("takesScreenshot", false);

		String driver = sConfig.getProperty("driver", DRIVER_PHANTOMJS);

		// Fetch PhantomJS-specific configuration parameters
		if (driver.equals(DRIVER_PHANTOMJS)) {
			// "phantomjs_exec_path"
			if (sConfig.getProperty("phantomjs_exec_path") != null) {
				sCaps.setCapability(
						PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY,
						sConfig.getProperty("phantomjs_exec_path"));
			} else {
				throw new IOException(
						String.format(
								"Property '%s' not set!",
								PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY));
			}
			// "phantomjs_driver_path"
			if (sConfig.getProperty("phantomjs_driver_path") != null) {
				System.out.println("Test will use an external GhostDriver");
				sCaps.setCapability(
						PhantomJSDriverService.PHANTOMJS_GHOSTDRIVER_PATH_PROPERTY,
						sConfig.getProperty("phantomjs_driver_path"));
			} else {
				System.out
						.println("Test will use PhantomJS internal GhostDriver");
			}
		}

		// Disable "web-security", enable all possible "ssl-protocols" and
		// "ignore-ssl-errors" for PhantomJSDriver
		// sCaps.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, new
		// String[] {
		// "--web-security=false",
		// "--ssl-protocol=any",
		// "--ignore-ssl-errors=true"
		// });

		ArrayList<String> cliArgsCap = new ArrayList<String>();
		cliArgsCap.add("--web-security=false");
		cliArgsCap.add("--ssl-protocol=any");
		cliArgsCap.add("--ignore-ssl-errors=true");
		sCaps.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS,
				cliArgsCap);

		// Control LogLevel for GhostDriver, via CLI arguments
		sCaps.setCapability(
				PhantomJSDriverService.PHANTOMJS_GHOSTDRIVER_CLI_ARGS,
				new String[] { "--logLevel="
						+ (sConfig.getProperty("phantomjs_driver_loglevel") != null ? sConfig
								.getProperty("phantomjs_driver_loglevel")
								: "INFO") });

		// String driver = sConfig.getProperty("driver", DRIVER_PHANTOMJS);

		// Start appropriate Driver
		if (isUrl(driver)) {
			sCaps.setBrowserName("phantomjs");
			mDriver = new RemoteWebDriver(new URL(driver), sCaps);
		} else if (driver.equals(DRIVER_FIREFOX)) {
			mDriver = new FirefoxDriver(sCaps);
		} else if (driver.equals(DRIVER_CHROME)) {
			mDriver = new ChromeDriver(sCaps);
		} else if (driver.equals(DRIVER_PHANTOMJS)) {
			mDriver = new PhantomJSDriver(sCaps);
		}
	}

	/**
	 * check whether input is a valid URL
	 * 
	 * @author [email protected]
	 * @param urlString urlString
	 * @return true means yes, otherwise no.
	 */
	private boolean isUrl(String urlString) {
		try {
			new URL(urlString);
			return true;
		} catch (MalformedURLException mue) {
			return false;
		}
	}

	/**
	 * store webDrivers created
	 */
	private List<WebDriver> webDriverList = Collections
			.synchronizedList(new ArrayList<WebDriver>());

	/**
	 * store webDrivers available
	 */
	private BlockingDeque<WebDriver> innerQueue = new LinkedBlockingDeque<WebDriver>();

	public WebDriverPool(int capacity) {
		this.capacity = capacity;
	}

	public WebDriverPool() {
		this(DEFAULT_CAPACITY);
	}

	/**
	 * 
	 * @return
	 * @throws InterruptedException
	 */
	public WebDriver get() throws InterruptedException {
		checkRunning();
		WebDriver poll = innerQueue.poll();
		if (poll != null) {
			return poll;
		}
		if (webDriverList.size() < capacity) {
			synchronized (webDriverList) {
				if (webDriverList.size() < capacity) {

					// add new WebDriver instance into pool
					try {
						configure();
						innerQueue.add(mDriver);
						webDriverList.add(mDriver);
					} catch (IOException e) {
						e.printStackTrace();
					}

					// ChromeDriver e = new ChromeDriver();
					// WebDriver e = getWebDriver();
					// innerQueue.add(e);
					// webDriverList.add(e);
				}
			}

		}
		return innerQueue.take();
	}

	public void returnToPool(WebDriver webDriver) {
		checkRunning();
		innerQueue.add(webDriver);
	}

	protected void checkRunning() {
		if (!stat.compareAndSet(STAT_RUNNING, STAT_RUNNING)) {
			throw new IllegalStateException("Already closed!");
		}
	}

	public void closeAll() {
		boolean b = stat.compareAndSet(STAT_RUNNING, STAT_CLODED);
		if (!b) {
			throw new IllegalStateException("Already closed!");
		}
		for (WebDriver webDriver : webDriverList) {
			logger.info("Quit webDriver" + webDriver);
			webDriver.quit();
			webDriver = null;
		}
	}

}

■ 官網提供的SeleniumDownloader:

package us.codecraft.webmagic.downloader.selenium;

import org.apache.log4j.Logger;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.downloader.Downloader;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.PlainText;

import java.io.Closeable;
import java.io.IOException;
import java.util.Map;

/**
 * 使用Selenium呼叫瀏覽器進行渲染。目前僅支援chrome。<br>
 * 需要下載Selenium driver支援。<br>
 *
 * @author [email protected] <br>
 *         Date: 13-7-26 <br>
 *         Time: 下午1:37 <br>
 */
public class SeleniumDownloader implements Downloader, Closeable {

	private volatile WebDriverPool webDriverPool;

	private Logger logger = Logger.getLogger(getClass());

	private int sleepTime = 0;

	private int poolSize = 1;

	private static final String DRIVER_PHANTOMJS = "phantomjs";

	/**
	 * 新建
	 *
	 * @param chromeDriverPath chromeDriverPath
	 */
	public SeleniumDownloader(String chromeDriverPath) {
		System.getProperties().setProperty("webdriver.chrome.driver",
				chromeDriverPath);
	}

	/**
	 * Constructor without any filed. Construct PhantomJS browser
	 * 
	 * @author [email protected]
	 */
	public SeleniumDownloader() {
		// System.setProperty("phantomjs.binary.path",
		// "/Users/Bingo/Downloads/phantomjs-1.9.7-macosx/bin/phantomjs");
	}

	/**
	 * set sleep time to wait until load success
	 *
	 * @param sleepTime sleepTime
	 * @return this
	 */
	public SeleniumDownloader setSleepTime(int sleepTime) {
		this.sleepTime = sleepTime;
		return this;
	}

	@Override
	public Page download(Request request, Task task) {
		checkInit();
		WebDriver webDriver;
		try {
			webDriver = webDriverPool.get();
		} catch (InterruptedException e) {
			logger.warn("interrupted", e);
			return null;
		}
		logger.info("downloading page " + request.getUrl());
		webDriver.get(request.getUrl());
		try {
			Thread.sleep(sleepTime);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		WebDriver.Options manage = webDriver.manage();
		Site site = task.getSite();
		if (site.getCookies() != null) {
			for (Map.Entry<String, String> cookieEntry : site.getCookies()
					.entrySet()) {
				Cookie cookie = new Cookie(cookieEntry.getKey(),
						cookieEntry.getValue());
				manage.addCookie(cookie);
			}
		}

		/*
		 * TODO You can add mouse event or other processes
		 * 
		 * @author: [email protected]
		 */

		WebElement webElement = webDriver.findElement(By.xpath("/html"));
		String content = webElement.getAttribute("outerHTML");
		Page page = new Page();
		page.setRawText(content);
		page.setHtml(new Html(content, request.getUrl()));
		page.setUrl(new PlainText(request.getUrl()));
		page.setRequest(request);
		webDriverPool.returnToPool(webDriver);
		return page;
	}

	private void checkInit() {
		if (webDriverPool == null) {
			synchronized (this) {
				webDriverPool = new WebDriverPool(poolSize);
			}
		}
	}

	@Override
	public void setThread(int thread) {
		this.poolSize = thread;
	}

	@Override
	public void close() throws IOException {
		webDriverPool.closeAll();
	}
}



三、關於Selenium 的介紹

0、官網參考資料:

1、Selenium 是什麼

Selenium 是Web的自動化測試工具,可以模擬使用者與瀏覽器互動,進行存取網站。

Selenium是一個瀏覽器自動化的大型專案。

它提供用於模擬使用者與瀏覽器互動的擴充套件、用於擴充套件瀏覽器分配的分發伺服器,以及用於實現W3C WebDriver 規範的基礎結構,使您可以為所有主要 Web 瀏覽器編寫可互換的程式碼。Selenium 的核心是WebDriver,它是一個編寫指令集的介面,可以在許多瀏覽器中互換執行。

2、Selenium 作用:

自動化測試:自動化測試工具,可以模擬使用者與瀏覽器互動,進行存取網站。

爬蟲:因為Selenium可以控制瀏覽器傳送請求,並獲取網頁資料,因此可以應用於爬蟲領域。

Selenium 可以根據我們的指令,讓瀏覽器自動載入頁面,獲取需要的資料,甚至頁面截圖,或者判斷網站上某些動作是否發生。

3、Selenium 實際情況

Selenium是一個Web的自動化測試工具,最初是為網站自動化測試而開發的,Selenium 可以直接執行在瀏覽器上,它支援所有主流的瀏覽器。

Selenium 自己不帶瀏覽器,不支援瀏覽器的功能,它需要與第三方瀏覽器結合在一起才能使用。

■ 主流的瀏覽器驅動WebDriver:PhantomJS、chromedriver

▪ PhantomJS:

PhantomJS 是一個基於Webkit的「無介面」(headless)瀏覽器,它會把網站載入到記憶體並執行頁面上的 JavaScript,因為不會展示圖形介面,所以執行起來比完整的瀏覽器要高效。

如果我們把 Selenium 和 PhantomJS 結合在一起,就可以執行一個非常強大的網路爬蟲了,這個爬蟲可以處理 JavaScrip、Cookie、headers,以及任何我們真實使用者需要做的事情。

▪ chromedriver:

注意 :chromedriver的版本要與你使用的chrome版本對應!

chromedriver版本	  支援的Chrome版本
v2.46				v71-73
v2.45				v70-72
v2.44				v69-71
v2.43				v69-71
v2.42				v68-70
v2.41				v67-69
v2.40				v66-68
v2.39				v66-68
v2.38				v65-67
v2.37				v64-66
v2.36				v63-65
v2.35				v62-64
v2.34				v61-63
v2.33				v60-62
v2.32				v59-61
v2.31				v58-60
v2.30				v58-60
v2.29				v56-58
v2.28				v55-57
v2.27				v54-56
v2.26				v53-55
v2.25				v53-55
v2.24				v52-54
v2.23				v51-53
v2.22				v49-52
v2.21				v46-50
v2.20				v43-48
v2.19				v43-47
v2.18				v43-46
v2.17				v42-43
v2.13				v42-45
v2.15				v40-43
v2.14				v39-42
v2.13				v38-41
v2.12				v36-40
v2.11				v36-40
v2.10				v33-36
v2.9				v31-34
v2.8				v30-33
v2.7				v30-33
v2.6				v29-32
v2.5				v29-32
v2.4				v29-32

4、Selenium+chromedriver 的使用:

(1) 準備工作:

Selenium:匯入依賴包

chromedriver:看著你電腦的谷歌瀏覽器版本,下載對應的chromedriver 驅動包

(2) 使用:

public class FirstScriptTest {

    @Test
    public void eightComponents() {
        //通過DesiredCapabilities、options 可以給driver 設定一個選項,例如代理,禁止載入圖片、去掉介面模式等
        //參考:ChromeDriver:https://sites.google.com/a/chromium.org/chromedriver/capabilities
        String downloadsPath = "d:\\data\\downloads";
		HashMap<String, Object> chromePrefs = new HashMap<String, Object>();
		chromePrefs.put("download.default_directory", downloadsPath);
		ChromeOptions options = new ChromeOptions();
		Proxy proxy = new Proxy();
		// 需要增加設定ssl協定
		proxy.setHttpProxy(VpnServerUtils.getVpnServer()).setSslProxy(VpnServerUtils.getVpnServer());
//		proxy.setHttpProxy(VpnServerUtils.getVpnServer());
		options.setCapability("proxy",proxy);
		System.out.println("~~~~~~~~~~~~~~~~~proxy: " + proxy.getHttpProxy());
		options.setExperimentalOption("prefs", chromePrefs);
		DesiredCapabilities caps = new DesiredCapabilities();
		caps.setCapability(ChromeOptions.CAPABILITY, options);
        
        WebDriver driver = new ChromeDriver(caps);
        //瀏覽器驅動器請求載入頁面
        driver.get("https://www.selenium.dev/selenium/web/web-form.html");
		
        //查詢元素
        String title = driver.getTitle();
        assertEquals("Web form", title);

        driver.manage().timeouts().implicitlyWait(Duration.ofMillis(500));

        WebElement textBox = driver.findElement(By.name("my-text"));
        WebElement submitButton = driver.findElement(By.cssSelector("button"));

        textBox.sendKeys("Selenium");
        submitButton.click();//點選事件

        WebElement message = driver.findElement(By.id("message"));
        String value = message.getText();
        assertEquals("Received!", value);
	    //結束對談
        driver.quit();
    }
}




如果本文對你有幫助的話記得給一樂點個贊哦,感謝!