知乎是一個真實的網路問答社區,社區氛圍友善、理性、認真,連結各行各業的精英。他們分享彼此的專業知識、經驗和見解,為中文網路源源不絕地提供高品質的資訊。
先花個三、五分鐘設計一個Logo=。 =身為一個程式設計師我一直有一顆做美工的心!
好吧做的有點小湊合,就先湊合著用咯。
接下來呢,我們開始製作知乎的爬蟲類。
首先,確定第一個目標:編輯推薦。
網頁連結:http://www.zhihu.com/explore/recommendations
我們對上次的程式碼稍作修改,先實作能夠取得該頁面內容:
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()));
// 用來暫時儲存抓取到的每一行的數據
String line;
while ((line = in.readLine()) != null) {
// 遍歷抓取到的每一行並將其儲存到result裡面
result += line;
}
} catch (Exception e) {
System.out.println("發送GET請求出現異常!" + 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 = "http://www.zhihu.com/explore/recommendations";
// 造訪連結並取得頁面內容
String result = SendGet(url);
// 使用正規符合圖片的src內容
//String imgSrc = RegexString(result, "src=/"(.+?)/"");
// 列印結果
System.out.println(result);
}
}
運行一下木有問題,接下來就是一個正規匹配的問題了。
首先我們先來取得該頁面的所有的問題。
右鍵點擊標題,審查元素:
啊哈,可以看到標題其實是一個a標籤,也就是一個超鏈接,而其中能夠和其他超鏈接區分開的,應該就是那個class了,也就是類選擇器。
於是我們的正規語句就出來了:question_link.+?href=/"(.+?)/"
呼叫RegexString函數,並給它傳參:
public static void main(String[] args) {
// 定義即將訪問的鏈接
String url = "http://www.zhihu.com/explore/recommendations";
// 造訪連結並取得頁面內容
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編碼。
在這裡和大家解釋一下查看頁面原始碼和審查元素的差異。
查看頁面原始碼是顯示整個頁面的所有代碼,沒有按照HTML的標籤進行排版,相當於是直接查看源碼,這種方式對於查看整個網頁的信息,例如meta比較有用。
審查元素,或有的瀏覽器叫查看元素,是針對你右鍵的元素進行查看,例如一個div或img,比較適用於單獨查看某個物件的屬性和標籤。
好的,我們現在知道了問題出在了編碼上,接下來就是將抓取到的內容編碼轉換了。
在java中實作很簡單,只需要在InputStreamReader裡面指定編碼方式就行:
// 初始化BufferedReader輸入流來讀取URL的回應
in = new BufferedReader(new InputStreamReader(
connection.getInputStream(),"UTF-8"));
此時再執行程序,便會發現可以正常顯示標題了:
好的!非常好!
但現在才只有一個標題,我們需要的是所有的標題。
我們將正規稍加修改,把搜尋到的結果儲存到一個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"));
// 用來暫時儲存抓取到的每一行的數據
String line;
while ((line = in.readLine()) != null) {
// 遍歷抓取到的每一行並將其儲存到result裡面
result += line;
}
} catch (Exception e) {
System.out.println("發送GET請求出現異常!" + 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();
// 使用循環將句子裡所有的kelvin找出並替換再將內容加到sb裡
while (isFind) {
//新增成功匹配的結果
results.add(matcher.group(1));
// 繼續尋找下一個匹配對象
isFind = matcher.find();
}
return results;
}
public static void main(String[] args) {
// 定義即將訪問的鏈接
String url = "http://www.zhihu.com/explore/recommendations";
// 造訪連結並取得頁面內容
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;// 儲存所有回答的陣列
// 建構方法初始化數據
public Zhihu() {
question = "";
zhihuUrl = "";
answers = new ArrayList<String>();
}
@Override
public String toString() {
return "問題:" + question + "/n連結:" + zhihuUrl + "/n回答:" + answers + "/n";
}
}
再新建一個Spider類別來存放一些爬蟲常用的函數。
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"));
// 用來暫時儲存抓取到的每一行的數據
String line;
while ((line = in.readLine()) != null) {
// 遍歷抓取到的每一行並將其儲存到result裡面
result += line;
}
} catch (Exception e) {
System.out.println("發送GET請求出現異常!" + 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 = "http://www.zhihu.com" + urlMatcher.group(1);
// 新增成功匹配的結果
results.add(zhuhuTemp);
// 繼續尋找下一個匹配對象
isFind = questionMatcher.find() && urlMatcher.find();
}
return results;
}
}
最後一個main方法負責呼叫。
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// 定義即將訪問的鏈接
String url = "http://www.zhihu.com/explore/recommendations";
// 造訪連結並取得頁面內容
String content = Spider.SendGet(url);
// 取得該頁面的所有的知乎對象
ArrayList<Zhihu> myZhihu = Spider.GetZhihu(content);
// 列印結果
System.out.println(myZhihu);
}
}
Ok這樣就算搞定了。運行一下看看結果:
好的效果不錯。
接下來就是訪問連結然後獲取到所有的答案了。
下一回我們再介紹。
好了,以上就是簡單的介紹瞭如何使用java來抓取知乎的編輯推薦的內容的全部過程了,非常詳盡,也很簡單易懂,對吧,有需要的小伙伴可以參考下,自由擴展也沒問題哈