零基礎寫Java知乎爬蟲之獲取知乎編輯推薦內容
知乎是一個真實的網絡問答社區(qū),社區(qū)氛圍友好、理性、認真,連接各行各業(yè)的精英。他們分享著彼此的專業(yè)知識、經驗和見解,為中文互聯(lián)網源源不斷地提供高質量的信息。
首先花個三五分鐘設計一個Logo=。=作為一個程序員我一直有一顆做美工的心!
好吧做的有點小湊合,就先湊合著用咯。
接下來呢,我們開始制作知乎的爬蟲。
首先,確定第一個目標:編輯推薦。
網頁鏈接:http://www.zhihu.com/explore/recommendations
我們對上次的代碼稍作修改,先實現(xiàn)能夠獲取該頁面內容:
import java.io.*;
import java.net.*;
import java.util.regex.*;
public class Main {
static String SendGet(String url) {
// 定義一個字符串用來存儲網頁內容
String result = "";
// 定義一個緩沖字符輸入流
BufferedReader in = null;
try {
// 將string轉成url對象
URL realUrl = new URL(url);
// 初始化一個鏈接到那個url的連接
URLConnection connection = realUrl.openConnection();
// 開始實際的連接
connection.connect();
// 初始化 BufferedReader輸入流來讀取URL的響應
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
// 用來臨時存儲抓取到的每一行的數(shù)據
String line;
while ((line = in.readLine()) != null) {
// 遍歷抓取到的每一行并將其存儲到result里面
result += line;
}
} catch (Exception e) {
System.out.println("發(fā)送GET請求出現(xiàn)異常!" + e);
e.printStackTrace();
}
// 使用finally來關閉輸入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
static String RegexString(String targetStr, String patternStr) {
// 定義一個樣式模板,此中使用正則表達式,括號中是要抓的內容
// 相當于埋好了陷阱匹配的地方就會掉下去
Pattern pattern = Pattern.compile(patternStr);
// 定義一個matcher用來做匹配
Matcher matcher = pattern.matcher(targetStr);
// 如果找到了
if (matcher.find()) {
// 打印出結果
return matcher.group(1);
}
return "Nothing";
}
public static void main(String[] args) {
// 定義即將訪問的鏈接
String url = " // 訪問鏈接并獲取頁面內容
String result = SendGet(url);
// 使用正則匹配圖片的src內容
//String imgSrc = RegexString(result, "src=\"(.+?)\"");
// 打印結果
System.out.println(result);
}
}
運行一下木有問題,接下來就是一個正則匹配的問題了。
首先我們先來獲取該頁面的所有的問題。
右擊標題,審查元素:
啊哈,可以看到標題其實是一個a標簽,也就是一個超鏈接,而其中能夠和其他超鏈接區(qū)分開的,應該就是那個class了,也就是類選擇器。
于是我們的正則語句就出來了:question_link.+?href=\"(.+?)\"
調用RegexString函數(shù),并給它傳參:
public static void main(String[] args) {
// 定義即將訪問的鏈接
String url = " // 訪問鏈接并獲取頁面內容
String result = SendGet(url);
// 使用正則匹配圖片的src內容
String imgSrc = RegexString(result, "question_link.+?>(.+?)<");
// 打印結果
System.out.println(imgSrc);
}
啊哈,可以看到我們成功抓到了一個標題(注意,只是一個):
等一下啊這一大堆的亂七八糟的是什么玩意?!
別緊張=。=它只是字符亂碼而已。
編碼問題可以參見:HTML字符集
一般來說,對中文支持較好的主流編碼是UTF-8,GB2312和GBK編碼。
網頁可以通過meta標簽的charset來設置網頁編碼,譬如:
<meta charset="utf-8" />
我們右擊,查看頁面源代碼:
可以看到,知乎采用的是UTF-8編碼。
在這里和大家解釋一下查看頁面源代碼和審查元素的區(qū)別。
查看頁面源代碼是顯示整個頁面的所有代碼,沒有按照HTML的標簽進行排版,相當于是直接查看源碼,這種方式對于查看整個網頁的信息,比如meta比較有用。
審查元素,或者有的瀏覽器叫查看元素,是針對你右擊的元素進行查看,比如一個div或者img,比較適用于單獨查看某個對象的屬性和標簽。
好的,我們現(xiàn)在知道了問題出在了編碼上,接下來就是對抓取到的內容進行編碼轉換了。
在java中實現(xiàn)很簡單,只需要在InputStreamReader里面指定編碼方式就行:
// 初始化 BufferedReader輸入流來讀取URL的響應
in = new BufferedReader(new InputStreamReader(
connection.getInputStream(),"UTF-8"));
此時再運行程序,便會發(fā)現(xiàn)可以正常顯示標題了:
好的!非常好!
但是現(xiàn)在才只有一個標題,我們需要的是所有的標題。
我們將正則稍加修改,把搜索到的結果存儲到一個ArrayList里面:
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.regex.*;
public class Main {
static String SendGet(String url) {
// 定義一個字符串用來存儲網頁內容
String result = "";
// 定義一個緩沖字符輸入流
BufferedReader in = null;
try {
// 將string轉成url對象
URL realUrl = new URL(url);
// 初始化一個鏈接到那個url的連接
URLConnection connection = realUrl.openConnection();
// 開始實際的連接
connection.connect();
// 初始化 BufferedReader輸入流來讀取URL的響應
in = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "UTF-8"));
// 用來臨時存儲抓取到的每一行的數(shù)據
String line;
while ((line = in.readLine()) != null) {
// 遍歷抓取到的每一行并將其存儲到result里面
result += line;
}
} catch (Exception e) {
System.out.println("發(fā)送GET請求出現(xiàn)異常!" + e);
e.printStackTrace();
}
// 使用finally來關閉輸入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
static ArrayList<String> RegexString(String targetStr, String patternStr) {
// 預定義一個ArrayList來存儲結果
ArrayList<String> results = new ArrayList<String>();
// 定義一個樣式模板,此中使用正則表達式,括號中是要抓的內容
Pattern pattern = Pattern.compile(patternStr);
// 定義一個matcher用來做匹配
Matcher matcher = pattern.matcher(targetStr);
// 如果找到了
boolean isFind = matcher.find();
// 使用循環(huán)將句子里所有的kelvin找出并替換再將內容加到sb里
while (isFind) {
//添加成功匹配的結果
results.add(matcher.group(1));
// 繼續(xù)查找下一個匹配對象
isFind = matcher.find();
}
return results;
}
public static void main(String[] args) {
// 定義即將訪問的鏈接
String url = " // 訪問鏈接并獲取頁面內容
String result = SendGet(url);
// 使用正則匹配圖片的src內容
ArrayList<String> imgSrc = RegexString(result, "question_link.+?>(.+?)<");
// 打印結果
System.out.println(imgSrc);
}
}
這樣就能匹配到所有的結果了(因為直接打印了ArrayList所以會有一些中括號和逗號):
OK,這樣就算是完成了知乎爬蟲的第一步。
但是我們可以看出來,用這樣的方式是沒有辦法抓到所有的問題和回答的。
我們需要設計一個Zhihu封裝類,來存儲所有抓取到的對象。
Zhihu.java源碼:
import java.util.ArrayList;
public class Zhihu {
public String question;// 問題
public String zhihuUrl;// 網頁鏈接
public ArrayList<String> answers;// 存儲所有回答的數(shù)組
// 構造方法初始化數(shù)據
public Zhihu() {
question = "";
zhihuUrl = "";
answers = new ArrayList<String>();
}
@Override
public String toString() {
return "問題:" + question + "\n鏈接:" + zhihuUrl + "\n回答:" + answers + "\n";
}
}
再新建一個Spider類來存放一些爬蟲常用的函數(shù)。
Spider.java源碼:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Spider {
static String SendGet(String url) {
// 定義一個字符串用來存儲網頁內容
String result = "";
// 定義一個緩沖字符輸入流
BufferedReader in = null;
try {
// 將string轉成url對象
URL realUrl = new URL(url);
// 初始化一個鏈接到那個url的連接
URLConnection connection = realUrl.openConnection();
// 開始實際的連接
connection.connect();
// 初始化 BufferedReader輸入流來讀取URL的響應
in = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "UTF-8"));
// 用來臨時存儲抓取到的每一行的數(shù)據
String line;
while ((line = in.readLine()) != null) {
// 遍歷抓取到的每一行并將其存儲到result里面
result += line;
}
} catch (Exception e) {
System.out.println("發(fā)送GET請求出現(xiàn)異常!" + e);
e.printStackTrace();
}
// 使用finally來關閉輸入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
static ArrayList<Zhihu> GetZhihu(String content) {
// 預定義一個ArrayList來存儲結果
ArrayList<Zhihu> results = new ArrayList<Zhihu>();
// 用來匹配標題
Pattern questionPattern = Pattern.compile("question_link.+?>(.+?)<");
Matcher questionMatcher = questionPattern.matcher(content);
// 用來匹配url,也就是問題的鏈接
Pattern urlPattern = Pattern.compile("question_link.+?href=\"(.+?)\"");
Matcher urlMatcher = urlPattern.matcher(content);
// 問題和鏈接要均能匹配到
boolean isFind = questionMatcher.find() && urlMatcher.find();
while (isFind) {
// 定義一個知乎對象來存儲抓取到的信息
Zhihu zhuhuTemp = new Zhihu();
zhuhuTemp.question = questionMatcher.group(1);
zhuhuTemp.zhihuUrl = " // 添加成功匹配的結果
results.add(zhuhuTemp);
// 繼續(xù)查找下一個匹配對象
isFind = questionMatcher.find() && urlMatcher.find();
}
return results;
}
}
最后一個main方法負責調用。
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// 定義即將訪問的鏈接
String url = " // 訪問鏈接并獲取頁面內容
String content = Spider.SendGet(url);
// 獲取該頁面的所有的知乎對象
ArrayList<Zhihu> myZhihu = Spider.GetZhihu(content);
// 打印結果
System.out.println(myZhihu);
}
}
Ok這樣就算搞定了。運行一下看看結果:
好的效果不錯。
接下來就是訪問鏈接然后獲取到所有的答案了。
下一回我們再介紹。
好了,以上就是簡單的介紹了如何使用java來抓取知乎的編輯推薦的內容的全部過程了,非常詳盡,也很簡單易懂,對吧,有需要的小伙伴可以參考下,自由擴展也沒問題哈
相關文章
SpringBoot中使用Filter和Interceptor的示例代碼
這篇文章主要介紹了SpringBoot中使用Filter和Interceptor的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-06-06Spring Web MVC和Hibernate的集成配置詳解
這篇文章主要介紹了Spring Web MVC和Hibernate的集成配置詳解,具有一定借鑒價值,需要的朋友可以參考下2017-12-12java.lang.NoClassDefFoundError錯誤解決辦法
這篇文章主要介紹了java.lang.NoClassDefFoundError錯誤解決辦法的相關資料,需要的朋友可以參考下2017-06-06SpringBoot概述及在idea中創(chuàng)建方式
SpringBoot提供了一種快速使用Spring的方式,基于約定大于配置的思想,可以讓開發(fā)人員不必在配置與邏輯業(yè)務之間進行思維的切換,這篇文章主要介紹了SpringBoot概述及在idea中創(chuàng)建方式,需要的朋友可以參考下2022-09-09SpringCloud Hystrix-Dashboard儀表盤的實現(xiàn)
這篇文章主要介紹了SpringCloud Hystrix-Dashboard儀表盤的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08Java中Future、FutureTask原理以及與線程池的搭配使用
這篇文章主要為大家詳細介紹了Java中Future、FutureTask原理以及與線程池的搭配使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-09-09