網(wǎng)絡(luò)爬蟲
網(wǎng)絡(luò)爬蟲(WEB crawler),是一種按照一定的規(guī)則,自動(dòng)地抓取萬維網(wǎng)信息的程序或者腳本。
1. 爬蟲入門程序
導(dǎo)入依賴(下面列的程序用的是這個(gè)依賴,是版本5,我是從Maven中直接copy最新版的,沒想那么多,但4點(diǎn)多的用的人多點(diǎn),而且網(wǎng)上資料也多點(diǎn),所以還是推薦大家用4點(diǎn)多的吧,但是下面用的是5的,下面代碼部分也沒啥差別就獲取狀態(tài)碼的地方4本是getStatusLine().getStatusCode()然后5的話就是直接getCode(),還有就是5在設(shè)置請求參數(shù)的時(shí)候好像沒有設(shè)置socket超時(shí)選項(xiàng),4有,也有可能是我沒找到):
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>
雖然下面程序用的是5,但還是推薦大家用4吧,人用的多,有問題的話網(wǎng)上也好查找錯(cuò)。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
public class CrawlerFirst {
public static void main(String[] args) throws IOException, ParseException {
// 1. 打開瀏覽器,創(chuàng)建HttpClient對象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 2. 輸入網(wǎng)址,發(fā)起get請求創(chuàng)建HttpGet對象
HttpGet httpGet = new HttpGet("http://www.itcast.cn");
// 3. 按回車,發(fā)起請求,返回響應(yīng),使用HttpClient對象發(fā)起請求
CloseableHttpResponse response = httpClient.execute(httpGet);
// 4. 解析響應(yīng),獲取數(shù)據(jù)
System.out.println(response.getCode());// 狀態(tài)碼
if(response.getCode() == 200){
HttpEntity entity = response.getEntity();
String content = EntityUtils.toString(entity,"utf-8");// 得告訴編碼為utf-8,不然html代碼中文部分會(huì)亂碼
System.out.println(content);// 這輸出結(jié)果是那個(gè)頁面的html字符串
}
}
}
網(wǎng)絡(luò)爬蟲
1. 網(wǎng)絡(luò)爬蟲的介紹
? 在大數(shù)據(jù)時(shí)代,信息的采集是一項(xiàng)非常重要的工作,而互聯(lián)網(wǎng)的數(shù)據(jù)是海量的,如果單純靠人力進(jìn)行信息采集,不僅低效繁瑣,搜集的成本也會(huì)提高。如何自動(dòng)高效地獲取互聯(lián)網(wǎng)中我們感興趣的信息并為小編所用是一個(gè)重要的問題,而爬蟲技術(shù)就是為了解決這些問題而生的。
? 網(wǎng)絡(luò)爬蟲(Web Crawler)也叫做網(wǎng)絡(luò)機(jī)器人,可以代替人們自動(dòng)地在互聯(lián)網(wǎng)中進(jìn)行數(shù)據(jù)信息的采集與整理。它是一種按照一定的規(guī)則,自動(dòng)地抓取萬維網(wǎng)信息的程序或者腳本,可以自動(dòng)采集所有其能夠訪問到的頁面內(nèi)容,以獲取相關(guān)數(shù)據(jù)。
? 從功能上來講,爬蟲一般分為數(shù)據(jù)采集,處理,儲(chǔ)存
三個(gè)部分。爬蟲從一個(gè)或若干個(gè)初始網(wǎng)頁的URL開始,獲取初始化網(wǎng)頁上的URL,在抓取網(wǎng)頁的過程中,不斷從當(dāng)前頁面上抽取心的URL放入隊(duì)列,直到滿足系統(tǒng)的一定停止條件。
2. 為什么學(xué)習(xí)網(wǎng)絡(luò)爬蟲
- 可以實(shí)現(xiàn)搜索引擎
- 我們學(xué)會(huì)了爬蟲編寫之后,就可以利用爬蟲自動(dòng)地采集互聯(lián)網(wǎng)中的信息,采集回來后進(jìn)行相應(yīng)的存儲(chǔ)或處理,在需要搜索某些信息的時(shí)候,只需要在采集回來的信息中進(jìn)行搜索,即實(shí)現(xiàn)了私人的搜索引擎。
- 大數(shù)據(jù)時(shí)代,可以讓我們獲取更多的數(shù)據(jù)源
- 在進(jìn)行大數(shù)據(jù)分析或者進(jìn)行數(shù)據(jù)挖掘的時(shí)候,需要有數(shù)據(jù)源進(jìn)行分析。我們可以從某些提供數(shù)據(jù)統(tǒng)計(jì)的網(wǎng)站獲得,也可以從某些文獻(xiàn)或內(nèi)容資料中獲得,但是這些獲得數(shù)據(jù)的方式,有時(shí)很難滿足我們對數(shù)據(jù)的需求,而手動(dòng)從互聯(lián)網(wǎng)中去尋找這些數(shù)據(jù),則耗費(fèi)的精力過大。此時(shí)就可以利用爬蟲技術(shù),自動(dòng)地從互聯(lián)網(wǎng)中獲取我們感興趣的數(shù)據(jù)內(nèi)容,并將這些數(shù)據(jù)內(nèi)容爬取回來,作為我們的數(shù)據(jù)源,再進(jìn)行更深層次的數(shù)據(jù)分析,并獲得更有價(jià)值的信息。
- 可以更好地進(jìn)行搜索引擎優(yōu)化(SEO)
- 有利于就業(yè)。
- 從就業(yè)來說,爬蟲工程師方向是不錯(cuò)的選擇之一,因?yàn)槟壳芭老x工程師的需求越來越大,而能夠勝任這方面的崗位人員較少,所以屬于一個(gè)比較緊缺的職業(yè)方向,并且隨著大數(shù)據(jù)時(shí)代和人工智能的來臨,爬蟲技術(shù)的應(yīng)用將越來越廣泛,在未來會(huì)擁有很好的發(fā)展空間。
HttpClient
? 網(wǎng)絡(luò)爬蟲就是用程序幫助我們訪問網(wǎng)絡(luò)上的資源,我們一直以來都是使用 HTTP 協(xié)議訪問互聯(lián)網(wǎng)的網(wǎng)頁,網(wǎng)絡(luò)爬蟲需要編寫程序,在這里使用同樣的HTTP協(xié)議訪問網(wǎng)頁。
? 這里我們使用java的HTTP協(xié)議客戶端 HttpClient 這個(gè)技術(shù),來實(shí)現(xiàn)抓取網(wǎng)頁數(shù)據(jù)。HttpClient 是 Apache Jakarta Common 下的子項(xiàng)目,用來提供高效的、最新的、功能豐富的支持 HTTP 協(xié)議的客戶端編程工具包,并且它支持 HTTP 協(xié)議最新的版本和建議。
HttpClient 功能介紹:
- 實(shí)現(xiàn)了所有HTTP方法
- 支持自動(dòng)轉(zhuǎn)向
- 支持https協(xié)議
- 支持代理服務(wù)器
實(shí)現(xiàn)步驟:
- 打開瀏覽器==》創(chuàng)建HttpClient對象,通過HttpClients.createDefault()可以得到
- 根據(jù)對應(yīng)的請求方式創(chuàng)建HttpUriRequestBase子類對象,即HttpGet、HttpPost、HttpPut等等,構(gòu)造其實(shí)例的時(shí)候?qū)?url 參數(shù)進(jìn)去,這個(gè)url既可以是字符串,也可以是URL對象.
- 發(fā)送請求==》使用httpClient對象去執(zhí)行上面對應(yīng)的請求。執(zhí)行后會(huì)返回一個(gè)response對象。
- 使用response對象解析響應(yīng)獲取數(shù)據(jù)。
- 關(guān)閉資源
1. Get請求
public class HttpGetTest {
public static void main(String[] args) {
CloseableHttpResponse response = null;
// 1. 打開瀏覽器,創(chuàng)建httpClient對象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 2. 創(chuàng)建httpGet對象,設(shè)置url訪問地址
HttpGet httpGet = new HttpGet("https://www.51cto.com/");
// 3. 使用httpClient發(fā)送請求,獲取response
try {
response = httpClient.execute(httpGet);
// 4. 解析響應(yīng)
if (response.getCode()==200) {
String content = EntityUtils.toString(response.getEntity(), "utf-8");
System.out.println(content.length());
}
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}finally {
if(response!=null){
try {
response.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if(httpClient!=null){
try {
httpClient.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
}
2. 帶參數(shù)的GET請求
- 先創(chuàng)建httpClient實(shí)例
- 然后去得到uri對象,這個(gè)uri對象是通過URIBuilder對象構(gòu)建的,創(chuàng)建URIBuilder對象
- 添加參數(shù)(不同的HttpClient依賴它設(shè)置參數(shù)的方法可能不同,低一點(diǎn)的版本是setParameter,高點(diǎn)的就如下所寫),添加參數(shù)返回的是URIBuilder對象,所以可以鏈?zhǔn)降靥砑訁?shù)。
- 將uri對象(URIBuilder.build())傳給對應(yīng)的請求對象,訪問uri訪問地址。
- 執(zhí)行對應(yīng)的請求,獲取相應(yīng)結(jié)果集
- 處理數(shù)據(jù)
- 關(guān)閉資源
public class HttpGetWithParam {
public static void main(String[] args) throws IOException, ParseException, URISyntaxException {
// 1. 創(chuàng)建HttpClient實(shí)例
CloseableHttpClient httpClient = HttpClients.createDefault();
// 2. 根據(jù)相應(yīng)的請求構(gòu)造相應(yīng)的Uri對象
// 先創(chuàng)建 URLBuilder
URIBuilder uriBuilder = new URIBuilder("https://so.51cto.com/");
// 設(shè)置參數(shù)
uriBuilder.addParameter("keywords","java爬蟲").addParameter("sort","time");
// 創(chuàng)建httpGet對象,訪問url訪問地址
HttpGet httpGet = new HttpGet(uriBuilder.build());
// 3. 實(shí)現(xiàn)對應(yīng)url對象,使用httpClient;然后即可獲取到response
CloseableHttpResponse response = httpClient.execute(httpGet);
// 4. 拿到response對象即可獲取數(shù)據(jù)
if (response.getCode()==200) {
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity, "utf-8"));
}
response.close();
httpClient.close();
}
}
3. Post請求
與 Get 請求的差異,只是將uri對象的設(shè)置那步,本是HttpGet改為HttpPost即可。
public class HttpPostTest {
public static void main(String[] args) throws IOException, ParseException {
// 1. 創(chuàng)建httpClient對象
CloseableHttpClient httpClient = HttpClients.createDefault();
// 2. 創(chuàng)建HttpPost對象,設(shè)置uri訪問地址
HttpPost httpPost = new HttpPost("https://www.51cto.com/");
// 3. 執(zhí)行uri對象,然后獲取response對象
CloseableHttpResponse response = httpClient.execute(httpPost);
// 4. 處理響應(yīng)數(shù)據(jù)
if (response.getCode()==200) {
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity, "utf-8"));
}
// 5.關(guān)閉資源
httpClient.close();
response.close();
}
}
4. 帶參數(shù)的 Post 請求
uri 地址中沒有參數(shù),參數(shù) keys = java 放到表單中進(jìn)行提交。
帶參數(shù)的 Post 請求不同于帶參數(shù)的 Get 請求直接把 uri 查詢信息放 uri 上即可,我們需要將其參數(shù)內(nèi)容傳入到請求體中。
- 首先需要聲明一個(gè)List即可,其聲明的參數(shù)類型是
NameValuePair
,我們往集合中添加 NameValuePair 的實(shí)現(xiàn)類BasicNameValuePair
對象 - 然后再將其轉(zhuǎn)化成
HttpEntity
,下面是用的UrlEncodedFormEntity 實(shí)例
(HttpEntity 的實(shí)現(xiàn)類),因?yàn)槠錁?gòu)造方法中public UrlEncodedFormEntity(Iterable<? extends NameValuePair> parameters, Charset charset)
是允許傳入集合參數(shù)的,其他實(shí)現(xiàn)類像StringEntity是沒這個(gè)的。- 這里需注意一個(gè)點(diǎn):第二個(gè)參數(shù)是傳入
Charset實(shí)例對象
,而不是對應(yīng)的編碼字符串,人低版本都是重載后幫我們把傳進(jìn)去的字符串自動(dòng)去轉(zhuǎn)成實(shí)例對象,現(xiàn)在版本高了得我們自己轉(zhuǎn),真的是無語住了。使用 Charset.forName(“對應(yīng)編碼”) 即可。
- 這里需注意一個(gè)點(diǎn):第二個(gè)參數(shù)是傳入
- 然后我們將實(shí)體對象設(shè)置到httpPost uri對象中即可。
- 最后就是一致的操作,執(zhí)行uri,獲取結(jié)果,對結(jié)果處理,關(guān)閉資源…
public class HttpPostWithParam {
public static void main(String[] args) throws IOException, ParseException {
CloseableHttpClient httpClient = HttpClients.createDefault();
// 聲明List集合,封裝表單中的參數(shù)
List<NameValuePair> paramList = new ArrayList<NameValuePair>();
paramList.add(new BasicNameValuePair("keys","java"));
// paramList.add(new BasicNameValuePair("sort", "time"));
// 創(chuàng)建表單的 Entity 實(shí)體對象
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(paramList,Charset.forName("utf-8"));
// 設(shè)置表單的 Entity 實(shí)體對象到Post請求中
HttpPost httpPost = new HttpPost("https://www.itcast.cn/");
httpPost.setEntity(formEntity);
CloseableHttpResponse response = httpClient.execute(httpPost);
if (response.getCode()==200) {
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity, "utf-8"));
}
httpClient.close();
response.close();
}
}
5. 連接池
? 我們知道 HttpClient 實(shí)例對象相當(dāng)于我們的一個(gè)瀏覽器,以上我們每次發(fā)個(gè)請求都得創(chuàng)建一個(gè) HttpClient 對象,會(huì)有頻繁創(chuàng)建和銷毀的問題==》就相當(dāng)于打開瀏覽器訪問個(gè)頁面后又關(guān)掉,又打開瀏覽器,訪問完又關(guān)掉。
public class HttpClientPoolTest {
public static void main(String[] args) {
// 1. 創(chuàng)建連接池管理器
PoolingHttpClientConnectionManager httpClientPool = new PoolingHttpClientConnectionManager();
// 設(shè)置連接數(shù)
httpClientPool.setMaxTotal(100);
// 設(shè)置每個(gè)主機(jī)的最大連接數(shù)
httpClientPool.setDefaultMaxPerRoute(10);
// 2. 使用連接池管理器發(fā)起請求
doGet(httpClientPool);
doGet(httpClientPool);
doGet(httpClientPool);
httpClientPool.close();
}
private static void doGet(PoolingHttpClientConnectionManager httpClientPool) {
// 不是每次創(chuàng)建新的httpClient,而是從連接池中獲取httpClient對象
// 下面這段代碼的意義:先是從HttpClients工具類中通過custom方法獲取到HttpClientBuilder對象
// 然后通過給HttpClientBuilder中的PoolingHttpClientConnectionManager連接管理對象賦值
// 最后build一個(gè)httpClient對象出來(即使你不這樣去set連接池,你通過HttpClientBuild對象去build一個(gè)HttpClient實(shí)例也會(huì)去創(chuàng)建一個(gè))
try {
CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(httpClientPool).build();
HttpGet httpGet = new HttpGet("https://www.51cto.com/");
CloseableHttpResponse response = httpClient.execute(httpGet);
if (response.getCode() == 200) {
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity, "utf-8"));
}
response.close();
// httpClient.close(); httpClient由于是交給了連接池管理,所以這里就不用關(guān)閉了,換句話說關(guān)連接池就行
}catch(Exception e){
e.printStackTrace();
}
}
}
以下是再次調(diào)用 doGet 后 httpClient 實(shí)例對象的地址,都不相同=》說明每次創(chuàng)建對象都是由連接池所分配的。
注意:有人不明白為什么要設(shè)置最大連接數(shù)后,還要再設(shè)置一個(gè)每個(gè)主機(jī)的最大連接數(shù)。其實(shí)原因很簡單:設(shè)置了這個(gè)連接池后,是為了我們以后不必要在每個(gè)類中進(jìn)行重復(fù)創(chuàng)建和銷毀,那樣會(huì)浪費(fèi)空間,httpClient 實(shí)例對象的創(chuàng)建和銷毀都交給連接池去管理。同時(shí),當(dāng)我們在進(jìn)行網(wǎng)頁信息爬取時(shí)會(huì)有多個(gè)不同主機(jī) (“Host: www.csdn.net[\r][\n]”),像搜狐、新浪、騰訊…個(gè)人理解這樣保證了爬取的準(zhǔn)確和全面,就好比買菜。以自己擁有的錢數(shù),分成若干等份,去不同的菜點(diǎn)購取質(zhì)量好的菜。
如果不設(shè)置總連接數(shù)和每臺主機(jī)的最大連接數(shù)的話,以下參數(shù)是默認(rèn)值(版本5才有默認(rèn)值,4沒有,要自己設(shè)):
6. 請求參數(shù)
? 有時(shí)候因?yàn)榫W(wǎng)絡(luò),或者目標(biāo)服務(wù)器的原因,請求需要更長的時(shí)間才能完成,我們需要自定義相關(guān)時(shí)間。
public class HttpConfigTest {
public static void main(String[] args) throws IOException, ParseException {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("https://www.51cto.com/");
// 配置請求信息
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(Timeout.ofMilliseconds(1000L))// 創(chuàng)建連接的最長時(shí)間,毫秒
.setConnectionRequestTimeout(Timeout.ofMilliseconds(500L)).build();// 設(shè)置獲取連接的最長時(shí)間,毫秒
// 給請求設(shè)置請求信息
httpGet.setConfig(requestConfig);
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity, "utf-8"));
response.close();
httpClient.close();
}
}
Jsoup
? 我們使用 HttpClient 抓取到頁面數(shù)據(jù)之后,還需要對頁面進(jìn)行解析??梢允褂米址幚砉ぞ呓馕鲰撁?,也可以使用正則表達(dá)式,但是這些方法都會(huì)帶來很大的開發(fā)成本,所以我們需要使用一款專門解析 html 頁面的技術(shù)-》jsoup
。
1. jsoup 介紹
? jsoup 是一款 Java 的HTML 解析器
,全稱是 Java HTML Parser,可直接解析某個(gè) URL 地址、HTML 文本內(nèi)容。它提供了一套非常省力的 API,可以通過 DOM,CSS 以及類似于 jQuery 的操作方法來取出和操作數(shù)據(jù)。
jsoup 的主要功能:
- 從一個(gè) URL,文本或字符串中解析 HTML;
- 使用 DOM 或 CSS 選擇器來
查找、取出數(shù)據(jù)
; - 可
操作
HTML 元素、屬性、文本,和爬蟲木得關(guān)系;
加入 jsoup 的依賴:
<!-- https://mvnrepository.com/artifact/org.jsoup/jsoup -->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.15.3</version>
</dependency>
其他工具類依賴(common-io
=》處理文件需要、common-lang3=》需使用StringUtils處理字符串):
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
2.1 功能1.1-解析url
@Test
public void testUrl() throws Exception{
// 解析 url 地址,第一個(gè)參數(shù)是 URL對象,第二個(gè)參數(shù)是訪問時(shí)候的超時(shí)時(shí)間
Document doc = Jsoup.parse(new URL("https://www.51cto.com/"), 10000);
// 使用標(biāo)簽選擇器,獲取title標(biāo)簽中的內(nèi)容
String title = doc.getElementsByTag("title").first().text();
// 打印
System.out.println(title);// 技術(shù)成就夢想51CTO-中國領(lǐng)先的IT技術(shù)網(wǎng)站
}
注意:雖然使用 Jsoup 可以替代 HttpClient 直接發(fā)起請求抓取數(shù)據(jù),但是往往不會(huì)這樣用,因?yàn)閷?shí)際開發(fā)過程中,需要使用到多線程,連接池,代理
等等方式,而 jsoup 對這些的支持并不是很好,所以我們一般把 jsoup 僅僅作為 Html 解析工具使用。
2.2 功能1.2-解析字符串
使用 org.apache.commons.io.FileUtils 工具類去將html文件解析成字符串,然后用 jsoup 解析字符串。
@Test
public void testString() throws Exception {
// 使用工具類獲取文件,獲取字符串
String index = FileUtils.readFileToString(new File("C:\\Users\\myz03\\Desktop\\index.html"), "utf-8");
// 解析字符串
Document doc = Jsoup.parse(index);
// 使用標(biāo)簽選擇器,獲取td標(biāo)簽中的內(nèi)容
Elements tds = doc.getElementsByTag("td");
tds.forEach(td->{
System.out.println(td.text());
});
}
2.3 功能1.3-解析文件
和上面解析字符串的效果一樣。
@Test
public void testFile() throws Exception{
// 解析文件
Document doc = Jsoup.parse(new File("C:\\Users\\myz03\\Desktop\\index.html"));
// 使用標(biāo)簽選擇器,獲取td標(biāo)簽中的內(nèi)容
Elements tds = doc.getElementsByTag("td");
tds.forEach(td->{
System.out.println(td.text());
});
}
3.1 功能2.1-使用 dom 方式遍歷文檔
元素獲?。?/p>
- 根據(jù) id 查詢元素 getElementById;
- 根據(jù)標(biāo)簽獲取元素 getElementByTag;
- 根據(jù) class 獲取元素 getElementByClass;
- 根據(jù)屬性獲取元素 getElementByAttribute;
@Test
public void testDom() throws Exception{
/*
1. 根據(jù) id 查詢元素 getElementById;
2. 根據(jù)標(biāo)簽獲取元素 getElementByTag;
3. 根據(jù) class 獲取元素 getElementByClass;
4. 根據(jù)屬性獲取元素 getElementByAttribute;
*/
// 解析文件,獲取Document對象
Document doc = Jsoup.parse(new File("C:\\Users\\myz03\\Desktop\\index.html"));
// 獲取元素,根據(jù)id
Element div1Element = doc.getElementById("div1");
System.out.println(div1Element.text());
System.out.println("=====================");
// 獲取元素,根據(jù)tag
Elements tds = doc.getElementsByTag("td");
tds.forEach(td->{
System.out.println(td.text());
});
System.out.println("===================");
// 獲取元素,根據(jù)class
Elements a1s = doc.getElementsByClass("a1");
a1s.forEach(a1-> System.out.println(a1.text()));
System.out.println("======================");
// 獲取元素,根據(jù)屬性
Elements colspans = doc.getElementsByAttribute("colspan");
colspans.forEach(colspan-> System.out.println(colspan.text()));
}
從元素中獲取數(shù)據(jù)
- 從元素中獲取id;
- 從元素中獲取 className;
- 從元素中獲取屬性的值 attr;
- 從元素中獲取所有屬性 attributes;
- 從元素中獲取文本內(nèi)容 text;
@Test
public void testData() throws Exception{
Document doc = Jsoup.parse(new File("C:\\Users\\myz03\\Desktop\\index.html"),"utf-8");
// 根據(jù) id 獲取元素
Element div1 = doc.getElementById("div1");
StringJoiner content = new StringJoiner("、");
// 1. 從元素中獲取id;
content.add(div1.id());
// 2. 從元素中獲取 className;
content.add(div1.className());
// 3. 從元素中獲取屬性的值 attr;
content.add(div1.attr("id"));
// 4. 從元素中獲取所有屬性 attributes;
Attributes attributes = div1.attributes();
attributes.forEach(attribute -> content.add(attribute.getKey() + ":" + attribute.getValue()));
// 5. 從元素中獲取文本內(nèi)容 text;
content.add(div1.text());
System.out.println(content.toString());
}
3.2 功能2.2-Selector 選擇器概述
tagname:通過標(biāo)簽查找元素,比如:span
#id:通過 ID 查找元素,比如:# div1
.class:通過 class 名稱來查找元素,比如:.a1
[attribute]:利用屬性查找元素,比如:[target]
[attr=value]:利用屬性值來查找元素,比如:[target=_blank]文章來源:http://www.zghlxwxcb.cn/news/detail-453839.html
@Test
public void testSelector() throws Exception {
Document doc = Jsoup.parse(new File("C:\\Users\\myz03\\Desktop\\index.html"), "utf-8");
// 通過標(biāo)簽查找元素
Elements ths = doc.select("th");
ths.forEach(th-> System.out.println(th.text()));
System.out.println("=============");
// 通過ID來查找元素,#id
Element div1s = doc.select("#div1").first();
System.out.println(div1s.text());
System.out.println("=============");
// 通過class名稱來查找元素,.class
Elements a1s = doc.select(".a1");
a1s.forEach(a1-> System.out.println(a1.text()));
System.out.println("================");
// 通過attribute來查找元素,[attribute]
Elements colspans = doc.select("[colspan]");
colspans.forEach(colspan-> System.out.println(colspan.text()));
System.out.println("====================");
// 通過attribute=value來查找元素,[attribute=value]
Elements rowspans = doc.select("[rowspan=3]");
rowspans.forEach(rowspan-> System.out.println(rowspan.text()));
}
3.3 功能2.2plus-Selector 選擇器的組合使用
- el#id:元素+ID,比如:div#div1
- el.class:元素+class,比如:a.a1
- el[attr]:元素+屬性名,比如:td[colspan]
- 任意組合:比如:td[colspan].xxx
- ancestor child:查找某個(gè)元素下子元素,比如:div strong
- parent > child:查找某個(gè)父元素下的直接子元素:tr > td > a
- parent > *:查找某個(gè)父元素下的所有直接子元素
@Test
public void testSelectorPlus() throws Exception{
Document doc = Jsoup.parse(new File("C:\\Users\\myz03\\Desktop\\index.html"), "utf-8");
// el#id:元素+ID
Elements div1s = doc.select("div#div1");
div1s.forEach(div1-> System.out.println(div1.text()));
System.out.println("============");
// el.class:元素+class
Elements a1s = doc.select("a.a1");
a1s.forEach(a1-> System.out.println(a1.text()));
System.out.println("=============");
// el[attr]:元素+屬性名
Element colspan = doc.select("td[colspan]").first();
System.out.println(colspan.text());
System.out.println("===============");
// 任意組合
Elements tdA1s = doc.select("td[colspan].xxx");
tdA1s.forEach(tdA1-> System.out.println(tdA1.text()));
System.out.println("=================");
// ancestor child:查找某個(gè)元素下子元素
Elements divStrongs = doc.select("div strong");
System.out.println(divStrongs.first().text());
System.out.println("===============");
// parent > child:查找某個(gè)父元素下的直接子元素
Elements selects = doc.select("tr > th");
selects.forEach(select-> System.out.println(select.text()));
System.out.println("==========");
// parent > *:查找某個(gè)父元素下的所有直接子元素
Elements mytrs = doc.select(".mytr > *");
mytrs.forEach(mytr-> System.out.println(mytr.text()));
}
入門案例
由于有一定的代碼量,所以我放到了Gitee遠(yuǎn)程庫中,趕興趣可以去clone。
Java-Crawler文章來源地址http://www.zghlxwxcb.cn/news/detail-453839.html
到了這里,關(guān)于【Java-Crawler】HttpClient+Jsoup實(shí)現(xiàn)簡單爬蟲的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!