柚子快報激活碼778899分享:網(wǎng)絡(luò)爬蟲——Jsoup的使用
柚子快報激活碼778899分享:網(wǎng)絡(luò)爬蟲——Jsoup的使用
這里寫目錄標(biāo)題
1、Jsoup簡介2、jar包下載3、請求URL4、設(shè)置頭信息4.1、單個設(shè)置4.2、批量設(shè)置4.3、添加User-Agent庫和Referer庫
5、提交請求參數(shù)6、超時設(shè)置7、代理服務(wù)器的使用8、響應(yīng)轉(zhuǎn)輸出流(圖片、PDF等的下載)9、HTTPS請求認(rèn)證10、大文件內(nèi)容獲取問題
1、Jsoup簡介
Jsoup 是一款基于 Java 語言的開源項(xiàng)目,主要用于請求 URL 獲取網(wǎng)頁內(nèi)容、解析 HTML 和 XML 文檔。使用 Jsoup 可以非常輕松地構(gòu)建一些輕量級網(wǎng)絡(luò)爬蟲。
2、jar包下載
基于 pom.xml 文件的配置信息,可以下載 Jsoup 的 jar 包(版本是 1.11.3)。在 Jsoup 項(xiàng)目中,共包含 7 個 package
3、請求URL
org.jsoup.Jsoup 類可以用來處理連接操作。在 org.jsoup.Jsoup 類中提供了 connect(String url)方法來創(chuàng)建一個新連接,該方法的實(shí)現(xiàn)依賴于 Java 網(wǎng)絡(luò)通信包 java.net。在創(chuàng)建連接之后,可通過具體請求方法(如 GET 和 POST)獲取 URL 對應(yīng) 的 HTML 文件。
下面程序?yàn)?Jsoup 請求該網(wǎng)頁的一種方式,這里使用 get()方法執(zhí)行請求,該方法返回一個 Document 類型的對象,使用 Element 類中的 html()方法可以將 Document 類型的對象轉(zhuǎn)化為 String 類型。
public static void main(String[] args) throws IOException {
//創(chuàng)建連接
Connection connection = Jsoup.connect("http://www.baidu.com");
//請求網(wǎng)頁,也可以使用POST請求
Document document = connection.get();
//輸出HTML
System.out.println(document.html());
}
另外,也可以利用 Jsoup 先獲取響應(yīng) Response,再獲取 HTML 內(nèi)容,在獲取響應(yīng)時,method(Method method)方法中的參數(shù)為具體的 HTTP 請求方法, 這里共有 8 種。
在下面的程序中,設(shè)置的請求方法為 GET。程序的輸出 結(jié)果如圖所示,具體包括請求的 URL、響應(yīng)狀態(tài)碼、響應(yīng)數(shù)據(jù)類型、響應(yīng)狀態(tài)信 息以及 HTML 文件。如果將程序中的請求方法設(shè)置成 HEAD,重新運(yùn)行程序,則 會發(fā)現(xiàn)無法輸出 HTML 文件,但能獲取響應(yīng)頭信息。
public static void main(String[] args) throws IOException {
//獲取響應(yīng)
Connection.Response response = Jsoup.connect("http://www.baidu.com")
.method(Connection.Method.GET).execute();
URL url = response.url();//查看請求的URL
System.out.println("請求的URL為:" + url);
int statusCode = response.statusCode();//獲取響應(yīng)狀態(tài)碼
System.out.println("響應(yīng)狀態(tài)碼:" + statusCode);
String contentType = response.contentType();//獲取響應(yīng)數(shù)據(jù)類型
System.out.println("響應(yīng)類型為:" + contentType);
String statusMessage = response.statusMessage();//響應(yīng)信息
System.out.println("響應(yīng)信息為:" + statusMessage);
//判斷響應(yīng)狀態(tài)碼是否為200
if (statusCode == 200) {
//通過這種方式可以獲得響應(yīng)的HTML文件
String html = new String(response.bodyAsBytes(), "utf8");
//獲取HTML內(nèi)容,但對應(yīng)的是Document類型
Document document = response.parse();
//這里HTML和Document數(shù)據(jù)是一樣的,但Document是經(jīng)過格式化的
System.out.println(html);
System.out.println(document);
}
}
4、設(shè)置頭信息
在網(wǎng)絡(luò)爬蟲中,經(jīng)常需要設(shè)置一些頭信息。設(shè)置頭信息的作用是偽裝網(wǎng)絡(luò)爬蟲, 使得網(wǎng)絡(luò)爬蟲請求網(wǎng)頁更像瀏覽器訪問網(wǎng)頁,進(jìn)而降低了網(wǎng)絡(luò)爬蟲被網(wǎng)站封鎖的風(fēng)險。 Jsoup 中提供了兩種設(shè)置頭信息的方法,如下所示。
Connection header(String name, String value);
Connection headers(Map
4.1、單個設(shè)置
第一種方法每次只可以設(shè)置一個請求頭,如果要設(shè)置多個請求頭,需要多次調(diào)用 此方法;
public class JsoupConnectHeader {
public static void main(String[] args) throws IOException {
Connection connect = Jsoup.connect("http://www.baidu.com");
//設(shè)置一個請求頭
Connection conheader = connect.header("User-Agent", "Mozilla 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36");
Document document = conheader.get();
System.out.println(document);
}
}
4.2、批量設(shè)置
第二種方法可以添加多個請求頭至 Map 集合。
public class JsoupConnectHeaderMap {
public static void main(String[] args) throws IOException {
Connection connect = Jsoup.connect("http://www.baidu.com");
//設(shè)置多個請求頭
Map
header.put("Host", "www.********.com.cn"); header.put("User-Agent", " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239. 108 Safari/537.36");
header.put("Accept", "text/html,application/xhtml+xml, application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
header.put("Accept-Language", "zh-cn,zh;q=0.5");
header.put("Accept-Encoding", "gzip, deflate");
header.put("Cache-Control", "max-age=0");
header.put("Connection", "keep-alive");
Connection conheader = connect.headers(header);
Document document = conheader.get();
System.out.println(document);
}
}
4.3、添加User-Agent庫和Referer庫
public class JsoupConnectHeaderList {
public static void main(String[] args) throws IOException {
Connection connect = Jsoup.connect("http://www.baidu.com");
//實(shí)例化靜態(tài)類
Builder builder = new Builder(); //請求網(wǎng)頁添加不同Host,也可以不設(shè)置
builder.host = "www.********.com.cn"; //將Builder中的信息添加到Map集合中
Map
header.put("User-Agent", builder.userAgentList.get(new Random().nextInt(builder.userAgentSize)) );
header.put("Accept", builder.accept);
header.put("Referer", builder.refererList.get(new Random().nextInt(builder.refererSize)));
header.put("Accept-Language", builder.acceptLanguage); header.put("Accept-Encoding", builder.acceptEncoding);
//設(shè)置頭
Connection conheader = connect.headers(header);
Document document = conheader.get(); //發(fā)送GET請求
System.out.println(document); //輸出HTML
}
/**
* 封裝請求頭信息的靜態(tài)類 */
static class Builder{
//設(shè)置User-Agent庫;根據(jù)需求添加更多User-Agent
String[] userAgentStrs = {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50",
"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0",
"Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; InfoPath.3; rv:11.0) like Gecko",
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)",
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)",
"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"};
List
int userAgentSize = userAgentList.size();
//設(shè)置Referer庫;根據(jù)需求添加更多Referer
String[] refererStrs = {"https://www.*****.com/",
"https://www.*****.com/",
"http://www.****.com",
"https://www.**.com/"};
List
int refererSize = refererList.size();
//設(shè)置accept、accept-Language及accept-Encoding
String accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8";
String acceptLanguage = "zh-cn,zh;q=0.5";
String acceptEncoding = "gzip, deflate";
String host;
}
}
5、提交請求參數(shù)
網(wǎng)頁提交表單數(shù)據(jù),涉及一系列請求參數(shù)。GET 請求的參數(shù),是通過 URL 傳遞 的,通常以“?key1=value1&key2=value2”的形式進(jìn)行傳遞。POST 請求的參數(shù),通常 是放在 POST 請求的消息體中,格式一般為 JSON。
Jsoup 提供了 5 種添加請求參數(shù)的方法,如下所示。
Connection data(String key, String value);
Connection data(String... keyvals);
Connection data(Map
Connection data(String key, String filename, InputStream inputStream);
Connection data(String key, String filename, InputStream inputStream, String contentType);
Connection data(Collection
在這 5 種方法中,使用較多的是前 3 種方法。
//第一種方式
Connection connect = Jsoup.connect("http://www.*****.com/ems.php");
//添加參數(shù)
connect.data("wen","EH629625211CS").data("action", "ajax");
Connection.Response response = connect.method(Connection.Method.GET).ignoreContentType(true).execute();
//獲取數(shù)據(jù),轉(zhuǎn)換成HTML格式
Document document = response.parse();
System.out.println(document);
//第二種方式
Connection connect = Jsoup.connect("http://www.*****.com/ems.php"); //添加參數(shù)
connect.data("wen", "EH629625211CS", "action", "ajax");
Connection.Response response = connect.method(Connection.Method.GET).ignoreContentType (true).execute();
//獲取數(shù)據(jù),轉(zhuǎn)換成HTML格式
Document document = response.parse();
System.out.println(document);
//第三種方式
Connection connect = Jsoup.connect("http://www.*****.com/ems.php");
//添加參數(shù)
Map
data.put("wen", "EH629625211CS");
data.put("action", "ajax");
//獲取響應(yīng)
Connection.Response response = connect.data(data).method(Connection.Method.GET).ignoreContentType(true).execute();
//獲取數(shù)據(jù),轉(zhuǎn)換成HTML格式
Document document = response.parse();
System.out.println(document);
6、超時設(shè)置
在網(wǎng)絡(luò)異常情況下,可能會發(fā)生連接超時,進(jìn)而導(dǎo)致程序僵死而不繼續(xù)往下 執(zhí)行。針對連接超時問題,Jsoup 在請求 URL 時,可以由用戶自行設(shè)置毫秒級超時時間。如果不使用 timeout 方法設(shè)置超時時間,則超時時間默認(rèn)為 30 毫秒。
public class TimeOutDemo {
public static void main(String[] args) throws IOException {
//基于 timeout 設(shè)置超時時間
Connection.Response response = Jsoup.connect("https://*******.com/")
.method(Connection.Method.GET).timeout(3*1000)
.execute();
Document document = Jsoup.connect("https://*******.com/")
.timeout(10*1000).get();
}
}
7、代理服務(wù)器的使用
在一般情況下,使用瀏覽器可以直接連接 Internet 站點(diǎn)獲取網(wǎng)絡(luò)信息,而代理服 務(wù)器(Proxy Server)是網(wǎng)絡(luò)上提供轉(zhuǎn)接功能的服務(wù)器。代理服務(wù)器是介于客戶端和 Web 服務(wù)器之間的另一臺服務(wù)器,基于代理服務(wù)器,瀏覽器不再直接從 Web 服務(wù)器 獲取數(shù)據(jù),而是向代理服務(wù)器發(fā)出請求,信號會先送發(fā)到代理服務(wù)器,由代理服務(wù)器 取回瀏覽器所需要的信息??梢詫⒋砗唵卫斫鉃橹薪?。
在網(wǎng)絡(luò)爬蟲中,使用代理服務(wù)器訪問網(wǎng)頁內(nèi)容,能夠高度隱藏爬蟲的真實(shí) IP 地址, 從而防止網(wǎng)絡(luò)爬蟲被服務(wù)器封鎖。另外,普通網(wǎng)絡(luò)爬蟲使用固定 IP 地址請求時,往往 需要設(shè)置隨機(jī)休息時間,而通過代理服務(wù)器卻不需要,從而提高了數(shù)據(jù)采集的效率。 目前,代理服務(wù)器可以來源于提供免費(fèi)代理服務(wù)的一些網(wǎng)站或接口網(wǎng)站,但這些免 費(fèi)代理 IP 地址的穩(wěn)定性較差。另外,也可通過付費(fèi)的方式獲取商業(yè)級代理,其提供 的代理 IP 地址可用率較高,穩(wěn)定性較強(qiáng)。
在 Jsoup 中,提供了兩種方式設(shè)置代理服務(wù)器,如下所示。
Connection proxy(Proxy proxy);
Connection proxy(String host, int port);
在設(shè)置代理服務(wù)器時,需要知道代理服務(wù)器的 IP 地址以及端 口。在本案例中,只使用了一個代理服務(wù)器請求網(wǎng)頁,代理服務(wù)器的 IP 地址為 “171.221.239.11”,端口為 808。在實(shí)際應(yīng)用中,往往需要構(gòu)建代理服務(wù)器庫,不斷 地切換代理服務(wù)器去請求 URL 庫。
public class JsoupConnectProxy1 {
public static void main(String[] args) throws IOException {
//使用第一種方式設(shè)置代理
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("171.221.239.11", 808));
Connection connection = Jsoup.connect("http://www.********.com.cn/b.asp")
.proxy(proxy);
Connection.Response response = connection.method(Connection.Method.GET)
.timeout(10*1000).execute();
//獲取響應(yīng)狀態(tài)碼
int statusCode = response.statusCode();
System.out.println("響應(yīng)狀態(tài)碼為:" + statusCode);
}
}
public class JsoupConnectProxy2 {
public static void main(String[] args) throws IOException {
//使用第二種方式設(shè)置代理
Connection connection = Jsoup.connect("http://www.********.com.cn/b.asp")
.proxy("171.221.239.11",808);
Connection.Response response = connection.method(Connection.Method.GET)
.timeout (10*1000).execute();
//獲取響應(yīng)狀態(tài)碼
int statusCode = response.statusCode();
System.out.println("響應(yīng)狀態(tài)碼為:" + statusCode);
}
}
8、響應(yīng)轉(zhuǎn)輸出流(圖片、PDF等的下載)
使用 Jsoup 下載圖片、PDF 和壓縮等文件時,需要將響應(yīng)轉(zhuǎn)化成輸出流。轉(zhuǎn)化成 輸出流的目的是增強(qiáng)寫文件的能力,即以字節(jié)為單位寫入指定文件。
以圖片下載為例,使用 bodyStream()方法將響應(yīng)轉(zhuǎn)化成輸出流,并以緩 沖流的方式寫入指定文件。另外,針對圖片和 PDF 等文件,在執(zhí)行 URL 請求獲取 Response 時,必須通過 ignoreContentType(boolean ignoreContentType)方法設(shè)置忽略響 應(yīng)內(nèi)容的類型,否則會報錯。
public class JsoupConnectInputstream {
public static void main(String[] args) throws IOException {
String imageUrl = "http://i-4.******.com/2018/6/11/KDE5Mngp/ae0c2d4d-04fb-4066-872c-a8c7a7c4ea4f.jpg";
Connection connect = Jsoup.connect(imageUrl);
Connection.Response response = connect.method(Connection.Method.GET).
ignoreContentType(true).execute();
System.out.println("文件類型為:" + response.contentType());
//響應(yīng)轉(zhuǎn)化成輸出流
BufferedInputStream bufferedInputStream = response.
bodyStream();
//保存圖片
saveImage(bufferedInputStream,"image/1.jpg");
}
/**
* 保存圖片操作
* @param in 輸入流
* @param savePath 保存的文件目錄
* @throws IOException
*/
static void saveImage(BufferedInputStream in, String savePath) throws IOException {
byte[] buffer = new byte[1024];
int len = 0;
//創(chuàng)建緩沖流
FileOutputStream fileOutStream = new FileOutputStream(new File(savePath));
BufferedOutputStream bufferedOut = new BufferedOutputStream(fileOutStream);
//圖片寫入
while ((len = in.read(buffer, 0, 1024)) != -1) {
bufferedOut.write(buffer, 0, len);
}
//緩沖流釋放與關(guān)閉
bufferedOut.flush();
bufferedOut.close();
}
}
9、HTTPS請求認(rèn)證
以 https://為前綴的 URL 使用的是 HTTPS 協(xié)議。HTTPS 在 HTTP 的基礎(chǔ)上加入了 SSL(安全套接層)。SSL 的作用是保障網(wǎng)絡(luò)通信的安全性,其廣泛應(yīng)用于客戶端與服 務(wù)器之間的身份認(rèn)證和加密數(shù)據(jù)傳輸。
SSL 支持雙向認(rèn)證(服務(wù)器認(rèn)證與客戶端認(rèn)證),將服務(wù)器證書下載到客戶端, 再將客戶端的證書返回到服務(wù)器。目前,訪問網(wǎng)站并不常用客戶端證書,大部分用戶 都沒有自己的客戶端證書,但 HTTPS 總要求使用客戶端證書。其中,使用最多的客 戶端證書是 X.509 證書。
查看 Jsoup 源碼,發(fā)現(xiàn)在 org.jsoup.helper.HttpConnection 類中提供實(shí)現(xiàn)信任管理器的 initUnSecureTSL()方法。使用這種方法,可以成功請求以 https:// 為前綴的 URL。
但仔細(xì)閱讀 org.jsoup.helper.HttpConnection 類中的 createConnection()方法對應(yīng)的 源碼時,發(fā)現(xiàn) initUnSecureTSL()方法的調(diào)用是需要一定條件的,只有在 req.validateTLSCertificates()執(zhí)行的結(jié)果為 false 的情況下,才 會執(zhí)行 initUnSecureTSL()方法。而 validateTLSCertificates()方法實(shí)際返回的是靜態(tài)類 Request 中的 validateTSLCertificates 成員變量(默認(rèn)情況下為 true)。
因此,需要將 validateTSLCertificates 的值設(shè)置為 false 才能調(diào)用 initUnSecureTSL() 方法。在 org.jsoup.helper.HttpConnection 類中提供了設(shè)置 validateTSLCertificates 值的 方法:
public Connection validateTLSCertificates(boolean value) {
req.validateTLSCertificates(value);
return this;
}
Connection connect = Jsoup.connect("https://cn.*******.com")
.validateTLSCertificates(false);
Document document = connect.get();
System.out.println(document);
另外,也可以在 Jsoup 創(chuàng)建 Connection 連接之前,調(diào)用自己編寫的創(chuàng)建信任管理 器(不驗(yàn)證證書)的方法,也可以成功地請求以 https:// 為前綴的 URL。
public class JsoupConnectSSLInit {
public static void main(String[] args) throws IOException {
initUnSecureTSL();
String url = "https://cn.*******.com";
//創(chuàng)建連接
Connection connect = Jsoup.connect(url); //請求網(wǎng)頁
Document document = connect.get(); //輸出HTML System.out.println(document.html());
}
private static void initUnSecureTSL() {
// 創(chuàng)建信任管理器(不驗(yàn)證證書)
final TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
//檢查客戶端證書
public void checkClientTrusted(final X509Certificate[] chain, final String authType) {
//do nothing 接受任意客戶端證書
}
//檢查服務(wù)器端證書
public void checkServerTrusted(final X509Certificate[] chain, final String authType) {
//do nothing 接受任意服務(wù)端證書
}
//返回受信任的X509證書
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
};
try {
// 創(chuàng)建SSLContext對象,并使用指定的信任管理器初始化
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
//基于信任管理器,創(chuàng)建套接字工廠
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
//為HttpsURLConnection配置套接字工廠
HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory);
} catch (Exception e) {
e.printStackTrace();
}
}
}
10、大文件內(nèi)容獲取問題
在采集數(shù)據(jù)時,經(jīng)常會遇到一些較大的文件,如包含大量文本信息的 HTML 文件、 大小超過 10M 的圖片、PDF 和 ZIP 等文件。在默認(rèn)情況下,Jsoup 最大只能獲取 1M的文件。因此,直接使用 Jsoup 請求包含大量文本信息的 HTML 文件,將導(dǎo)致獲取的 內(nèi)容不全;請求下載大小超過 1M 的圖片和 ZIP 等文件,將導(dǎo)致文件無法查看或解壓。
但在 Jsoup 中,可以使用 maxBodySize(int bytes)設(shè)置請求文件大小限制,來避免這種 問題的出現(xiàn)。另外,在請求大文件時,設(shè)置的超時 時間也需盡量長些。
public class JsoupConnectBodySize1 {
public static void main(String[] args) throws IOException {
String url = "https://www-us.******.org/dist//httpd/httpd-2.4.37.tar.gz";
//超時時間設(shè)置長一些,下載大文件
Connection.Response response = Jsoup.connect(url)
.timeout(10*60*1000)
.maxBodySize(Integer.MAX_VALUE)
.method(Connection.Method.GET)
.ignoreContentType(true)
.execute();
//如果響應(yīng)成功,則執(zhí)行下面的操作
if (response.statusCode() == 200) {
//響應(yīng)轉(zhuǎn)化成輸出流
BufferedInputStream bufferedInputStream = response.bodyStream();
//保存圖片
saveFile(bufferedInputStream,"image/httpd-2.4.37.tar.gz");
}
}
static void saveFile(BufferedInputStream inputStream, String savePath) throws IOException {
//一次最多讀取1KB
byte[] buffer = new byte[1024];
int len = 0;
//創(chuàng)建緩沖流
FileOutputStream fileOutStream = new FileOutputStream(new File(savePath));
BufferedOutputStream bufferedOut = new BufferedOutputStream(fileOutStream);
//文件寫入
while ((len = inputStream.read(buffer, 0, 1024)) != -1) {
bufferedOut.write(buffer, 0, len);
}
//緩沖流釋放與關(guān)閉
bufferedOut.flush(); bufferedOut.close();
}
}
柚子快報激活碼778899分享:網(wǎng)絡(luò)爬蟲——Jsoup的使用
參考文章
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。