通常我們使用Java提供的HttpURLConnection或者Apache的HttpClient獲取的網頁原始碼都是直觀可見的,其程式碼的內容和通過瀏覽器右鍵網頁->點選檢視網頁原始碼的內容一致。
但是現在越來越多的網站使用Js來動態生成內容來提高相應速度,而HttpClient只是返回後端相應的response的請求主體,並沒有返回瀏覽器生成的網頁,所以對於Js生成的內容HttpClient是獲取不了的。
對於獲取Js生成的網頁,我們主要通過模擬瀏覽器的執行,渲染response的請求主體最終得到對應的內容,得到的內容和通過瀏覽器右鍵網頁->點選檢查/檢視元素的內容一致。
我們這裡講的模擬方法大概有兩種:
- 一種是使用Selenium
- 一種是使用HtmlUnit
抓取目標
我們這次的目標是獲取bilibili動態生成的動畫列表,左上是抓取的目標列表,左下是瀏覽器渲染的html內容,右面是伺服器返回的response的正文。通過對比,我們可以看出目標列表是Js生成。
使用Selenium獲取頁面
Selenium是一個用於Web應用自動化測試的工具,更多的介紹就谷歌。這裡我們主要用作模擬頁面的執行並將結果返回,對於網頁截圖的功能也是可行的。
Selenium支援模擬很多瀏覽器,但是我們這裡只模擬PhantomJS,因為PhantomJS 是一個指令碼化的無介面 WebKit,以 JavaScript 為指令碼語言實現各項功能。由於是無介面的,所以速度效能方面會較好。
1.下載
使用PhantomJS需要到官網下載最新的客戶端,這裡使用phantomjs-2.1.1-windows.zip
2.maven依賴引入:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.53.0</version>
</dependency>
<dependency>
<groupId>com.codeborne</groupId>
<artifactId>phantomjsdriver</artifactId>
<version>1.2.1</version>
<exclusions>
<exclusion>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-remote-driver</artifactId>
</exclusion>
<exclusion>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
</exclusion>
</exclusions>
</dependency>
3.示例程式碼
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriverService;
import org.openqa.selenium.remote.DesiredCapabilities;
import java.util.ArrayList;
/**
* @author GinPonson
*/
public class TestSelenium {
static final String HOST = "127.0.0.1";
static final String PORT = "80";
static final String USER = "gin";
static final String PWD = "12345";
public static void main(String[] args){
System.setProperty("phantomjs.binary.path", "D:\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe");
DesiredCapabilities capabilities = DesiredCapabilities.phantomjs();
//設定代理或者其他引數
ArrayList<String> cliArgsCap = new ArrayList<>();
//cliArgsCap.add("--proxy=http://"+HOST+":"+PORT);
//cliArgsCap.add("--proxy-auth=" + USER + ":" + PWD);
//cliArgsCap.add("--proxy-type=http");
capabilities.setCapability(PhantomJSDriverService.PHANTOMJS_CLI_ARGS, cliArgsCap);
//capabilities.setCapability("phantomjs.page.settings.userAgent", "");
WebDriver driver = new PhantomJSDriver(capabilities);
driver.get("http://www.bilibili.com/video/bangumi-two-1.html");
System.out.println(driver.getPageSource());
driver.quit();
}
}
4.其他功能
- 設定引數或者代理:去掉上面的註釋,就可以使用自己的代理了。
- 操作頁面,返回操作後頁面內容:不多說了,這裡介紹一下可以做。
- 頁面截圖:返回瀏覽器的全屏截圖。
使用HtmlUnit獲取頁面
HtmlUnit功能上算是是Selenium的一個子集,Selenium有對應的HtmlUnit實現。HtmlUnit是用Java寫的無介面的瀏覽器,正因為其沒有介面,因此執行的速度還是可以的。
1.maven依賴引入
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<version>2.25</version>
</dependency>
2.Java程式碼
/**
* @author GinPonson
*/
public class TestHtmlUnit {
static final String HOST = "127.0.0.1";
static final String PORT = "80";
static final String USER = "gin";
static final String PWD = "12345";
public static void main(String[] args) throws Exception{
WebClient webClient = new WebClient();
//設定代理
//ProxyConfig proxyConfig = webClient.getOptions().getProxyConfig();
//proxyConfig.setProxyHost(HOST);
//proxyConfig.setProxyPort(Integer.valueOf(PORT));
//DefaultCredentialsProvider credentialsProvider = (DefaultCredentialsProvider) webClient.getCredentialsProvider();
//credentialsProvider.addCredentials(USER, PWD);
//設定引數
//webClient.getOptions().setCssEnabled(false);
//webClient.getOptions().setJavaScriptEnabled(false);
webClient.getOptions().setThrowExceptionOnScriptError(false);
HtmlPage page = webClient.getPage("http://www.bilibili.com/video/bangumi-two-1.html");
System.out.println(page.asXml());
webClient.close();
}
}
3.其他功能
- 設定引數或者代理:去掉上面的註釋,就可以使用自己的代理了。
- 操作頁面,返回操作後頁面內容:不多說了,這裡介紹一下可以做。
- 解析頁面
總結
PhantomJS和HtmlUnit模擬瀏覽器頁面的生成功能都不錯,PhantomJS作為一個無介面的WebKit,渲染頁面的功能非常完善,而且帶有瀏覽器截圖功能,能模擬登入操作。HtmlUnit使用Rhino引擎來解析Js,有時候解析速度非常慢,就像上面的例子,費了很長時間,但是HtmlUnit可以獲取頁面,解析元素一套做完(當然解析元素還是使用Jsoup好),是不錯的工具。
HtmlUnit遇到錯誤後,前後處理相差7分鐘,可能是我不會用QAQ
歡迎補充:)