最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

零基礎(chǔ)寫Java知乎爬蟲之獲取知乎編輯推薦內(nèi)容

 更新時(shí)間:2014年11月07日 10:33:33   投稿:hebedich  
上篇文章我們拿百度首頁(yè)做了個(gè)小測(cè)試,今天我們來(lái)個(gè)復(fù)雜的,直接抓取知乎編輯推薦的內(nèi)容,小伙伴們可算松了口氣,終于進(jìn)入正題了,哈哈。

知乎是一個(gè)真實(shí)的網(wǎng)絡(luò)問答社區(qū),社區(qū)氛圍友好、理性、認(rèn)真,連接各行各業(yè)的精英。他們分享著彼此的專業(yè)知識(shí)、經(jīng)驗(yàn)和見解,為中文互聯(lián)網(wǎng)源源不斷地提供高質(zhì)量的信息。

首先花個(gè)三五分鐘設(shè)計(jì)一個(gè)Logo=。=作為一個(gè)程序員我一直有一顆做美工的心!


好吧做的有點(diǎn)小湊合,就先湊合著用咯。

接下來(lái)呢,我們開始制作知乎的爬蟲。

首先,確定第一個(gè)目標(biāo):編輯推薦。

網(wǎng)頁(yè)鏈接:http://www.zhihu.com/explore/recommendations

我們對(duì)上次的代碼稍作修改,先實(shí)現(xiàn)能夠獲取該頁(yè)面內(nèi)容:

import java.io.*;
import java.net.*;
import java.util.regex.*;
public class Main {
 static String SendGet(String url) {
  // 定義一個(gè)字符串用來(lái)存儲(chǔ)網(wǎng)頁(yè)內(nèi)容
  String result = "";
  // 定義一個(gè)緩沖字符輸入流
  BufferedReader in = null;
  try {
   // 將string轉(zhuǎn)成url對(duì)象
   URL realUrl = new URL(url);
   // 初始化一個(gè)鏈接到那個(gè)url的連接
   URLConnection connection = realUrl.openConnection();
   // 開始實(shí)際的連接
   connection.connect();
   // 初始化 BufferedReader輸入流來(lái)讀取URL的響應(yīng)
   in = new BufferedReader(new InputStreamReader(
     connection.getInputStream()));
   // 用來(lái)臨時(shí)存儲(chǔ)抓取到的每一行的數(shù)據(jù)
   String line;
   while ((line = in.readLine()) != null) {
    // 遍歷抓取到的每一行并將其存儲(chǔ)到result里面
    result += line;
   }
  } catch (Exception e) {
   System.out.println("發(fā)送GET請(qǐng)求出現(xiàn)異常!" + e);
   e.printStackTrace();
  }
  // 使用finally來(lái)關(guān)閉輸入流
  finally {
   try {
    if (in != null) {
     in.close();
    }
   } catch (Exception e2) {
    e2.printStackTrace();
   }
  }
  return result;
 }
 static String RegexString(String targetStr, String patternStr) {
  // 定義一個(gè)樣式模板,此中使用正則表達(dá)式,括號(hào)中是要抓的內(nèi)容
  // 相當(dāng)于埋好了陷阱匹配的地方就會(huì)掉下去
  Pattern pattern = Pattern.compile(patternStr);
  // 定義一個(gè)matcher用來(lái)做匹配
  Matcher matcher = pattern.matcher(targetStr);
  // 如果找到了
  if (matcher.find()) {
   // 打印出結(jié)果
   return matcher.group(1);
  }
  return "Nothing";
 }
 public static void main(String[] args) {
  // 定義即將訪問的鏈接
  String url = "  // 訪問鏈接并獲取頁(yè)面內(nèi)容
  String result = SendGet(url);
  // 使用正則匹配圖片的src內(nèi)容
  //String imgSrc = RegexString(result, "src=\"(.+?)\"");
  // 打印結(jié)果
  System.out.println(result);
 }
}

運(yùn)行一下木有問題,接下來(lái)就是一個(gè)正則匹配的問題了。

首先我們先來(lái)獲取該頁(yè)面的所有的問題。

右擊標(biāo)題,審查元素:

啊哈,可以看到標(biāo)題其實(shí)是一個(gè)a標(biāo)簽,也就是一個(gè)超鏈接,而其中能夠和其他超鏈接區(qū)分開的,應(yīng)該就是那個(gè)class了,也就是類選擇器。

于是我們的正則語(yǔ)句就出來(lái)了:question_link.+?href=\"(.+?)\"

調(diào)用RegexString函數(shù),并給它傳參:

 public static void main(String[] args) {
  // 定義即將訪問的鏈接
  String url = "
  // 訪問鏈接并獲取頁(yè)面內(nèi)容
  String result = SendGet(url);
  // 使用正則匹配圖片的src內(nèi)容
  String imgSrc = RegexString(result, "question_link.+?>(.+?)<");
  // 打印結(jié)果
  System.out.println(imgSrc);
 }

啊哈,可以看到我們成功抓到了一個(gè)標(biāo)題(注意,只是一個(gè)):

等一下啊這一大堆的亂七八糟的是什么玩意?!

別緊張=。=它只是字符亂碼而已。

編碼問題可以參見:HTML字符集

一般來(lái)說,對(duì)中文支持較好的主流編碼是UTF-8,GB2312和GBK編碼。

網(wǎng)頁(yè)可以通過meta標(biāo)簽的charset來(lái)設(shè)置網(wǎng)頁(yè)編碼,譬如:

<meta charset="utf-8" />

我們右擊,查看頁(yè)面源代碼:

可以看到,知乎采用的是UTF-8編碼。

在這里和大家解釋一下查看頁(yè)面源代碼和審查元素的區(qū)別。

查看頁(yè)面源代碼是顯示整個(gè)頁(yè)面的所有代碼,沒有按照HTML的標(biāo)簽進(jìn)行排版,相當(dāng)于是直接查看源碼,這種方式對(duì)于查看整個(gè)網(wǎng)頁(yè)的信息,比如meta比較有用。

審查元素,或者有的瀏覽器叫查看元素,是針對(duì)你右擊的元素進(jìn)行查看,比如一個(gè)div或者img,比較適用于單獨(dú)查看某個(gè)對(duì)象的屬性和標(biāo)簽。

好的,我們現(xiàn)在知道了問題出在了編碼上,接下來(lái)就是對(duì)抓取到的內(nèi)容進(jìn)行編碼轉(zhuǎn)換了。

在java中實(shí)現(xiàn)很簡(jiǎn)單,只需要在InputStreamReader里面指定編碼方式就行:

// 初始化 BufferedReader輸入流來(lái)讀取URL的響應(yīng)
   in = new BufferedReader(new InputStreamReader(
     connection.getInputStream(),"UTF-8"));

此時(shí)再運(yùn)行程序,便會(huì)發(fā)現(xiàn)可以正常顯示標(biāo)題了:

好的!非常好!

但是現(xiàn)在才只有一個(gè)標(biāo)題,我們需要的是所有的標(biāo)題。

我們將正則稍加修改,把搜索到的結(jié)果存儲(chǔ)到一個(gè)ArrayList里面:

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.regex.*;
public class Main {
 static String SendGet(String url) {
  // 定義一個(gè)字符串用來(lái)存儲(chǔ)網(wǎng)頁(yè)內(nèi)容
  String result = "";
  // 定義一個(gè)緩沖字符輸入流
  BufferedReader in = null;
  try {
   // 將string轉(zhuǎn)成url對(duì)象
   URL realUrl = new URL(url);
   // 初始化一個(gè)鏈接到那個(gè)url的連接
   URLConnection connection = realUrl.openConnection();
   // 開始實(shí)際的連接
   connection.connect();
   // 初始化 BufferedReader輸入流來(lái)讀取URL的響應(yīng)
   in = new BufferedReader(new InputStreamReader(
     connection.getInputStream(), "UTF-8"));
   // 用來(lái)臨時(shí)存儲(chǔ)抓取到的每一行的數(shù)據(jù)
   String line;
   while ((line = in.readLine()) != null) {
    // 遍歷抓取到的每一行并將其存儲(chǔ)到result里面
    result += line;
   }
  } catch (Exception e) {
   System.out.println("發(fā)送GET請(qǐng)求出現(xiàn)異常!" + e);
   e.printStackTrace();
  }
  // 使用finally來(lái)關(guān)閉輸入流
  finally {
   try {
    if (in != null) {
     in.close();
    }
   } catch (Exception e2) {
    e2.printStackTrace();
   }
  }
  return result;
 }
 static ArrayList<String> RegexString(String targetStr, String patternStr) {
  // 預(yù)定義一個(gè)ArrayList來(lái)存儲(chǔ)結(jié)果
  ArrayList<String> results = new ArrayList<String>();
  // 定義一個(gè)樣式模板,此中使用正則表達(dá)式,括號(hào)中是要抓的內(nèi)容
  Pattern pattern = Pattern.compile(patternStr);
  // 定義一個(gè)matcher用來(lái)做匹配
  Matcher matcher = pattern.matcher(targetStr);
  // 如果找到了
  boolean isFind = matcher.find();
  // 使用循環(huán)將句子里所有的kelvin找出并替換再將內(nèi)容加到sb里
  while (isFind) {
   //添加成功匹配的結(jié)果
   results.add(matcher.group(1));
   // 繼續(xù)查找下一個(gè)匹配對(duì)象
   isFind = matcher.find();
  }
  return results;
 }
 public static void main(String[] args) {
  // 定義即將訪問的鏈接
  String url = "
  // 訪問鏈接并獲取頁(yè)面內(nèi)容
  String result = SendGet(url);
  // 使用正則匹配圖片的src內(nèi)容
  ArrayList<String> imgSrc = RegexString(result, "question_link.+?>(.+?)<");
  // 打印結(jié)果
  System.out.println(imgSrc);
 }
}

這樣就能匹配到所有的結(jié)果了(因?yàn)橹苯哟蛴×薃rrayList所以會(huì)有一些中括號(hào)和逗號(hào)):


OK,這樣就算是完成了知乎爬蟲的第一步。

但是我們可以看出來(lái),用這樣的方式是沒有辦法抓到所有的問題和回答的。

我們需要設(shè)計(jì)一個(gè)Zhihu封裝類,來(lái)存儲(chǔ)所有抓取到的對(duì)象。

Zhihu.java源碼:

import java.util.ArrayList;
public class Zhihu {
 public String question;// 問題
 public String zhihuUrl;// 網(wǎng)頁(yè)鏈接
 public ArrayList<String> answers;// 存儲(chǔ)所有回答的數(shù)組
 // 構(gòu)造方法初始化數(shù)據(jù)
 public Zhihu() {
  question = "";
  zhihuUrl = "";
  answers = new ArrayList<String>();
 }
 @Override
 public String toString() {
  return "問題:" + question + "\n鏈接:" + zhihuUrl + "\n回答:" + answers + "\n";
 }
}

再新建一個(gè)Spider類來(lái)存放一些爬蟲常用的函數(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) {
  // 定義一個(gè)字符串用來(lái)存儲(chǔ)網(wǎng)頁(yè)內(nèi)容
  String result = "";
  // 定義一個(gè)緩沖字符輸入流
  BufferedReader in = null;
  try {
   // 將string轉(zhuǎn)成url對(duì)象
   URL realUrl = new URL(url);
   // 初始化一個(gè)鏈接到那個(gè)url的連接
   URLConnection connection = realUrl.openConnection();
   // 開始實(shí)際的連接
   connection.connect();
   // 初始化 BufferedReader輸入流來(lái)讀取URL的響應(yīng)
   in = new BufferedReader(new InputStreamReader(
     connection.getInputStream(), "UTF-8"));
   // 用來(lái)臨時(shí)存儲(chǔ)抓取到的每一行的數(shù)據(jù)
   String line;
   while ((line = in.readLine()) != null) {
    // 遍歷抓取到的每一行并將其存儲(chǔ)到result里面
    result += line;
   }
  } catch (Exception e) {
   System.out.println("發(fā)送GET請(qǐng)求出現(xiàn)異常!" + e);
   e.printStackTrace();
  }
  // 使用finally來(lái)關(guān)閉輸入流
  finally {
   try {
    if (in != null) {
     in.close();
    }
   } catch (Exception e2) {
    e2.printStackTrace();
   }
  }
  return result;
 }
 static ArrayList<Zhihu> GetZhihu(String content) {
  // 預(yù)定義一個(gè)ArrayList來(lái)存儲(chǔ)結(jié)果
  ArrayList<Zhihu> results = new ArrayList<Zhihu>();
  // 用來(lái)匹配標(biāo)題
  Pattern questionPattern = Pattern.compile("question_link.+?>(.+?)<");
  Matcher questionMatcher = questionPattern.matcher(content);
  // 用來(lái)匹配url,也就是問題的鏈接
  Pattern urlPattern = Pattern.compile("question_link.+?href=\"(.+?)\"");
  Matcher urlMatcher = urlPattern.matcher(content);
  // 問題和鏈接要均能匹配到
  boolean isFind = questionMatcher.find() && urlMatcher.find();
  while (isFind) {
   // 定義一個(gè)知乎對(duì)象來(lái)存儲(chǔ)抓取到的信息
   Zhihu zhuhuTemp = new Zhihu();
   zhuhuTemp.question = questionMatcher.group(1);
   zhuhuTemp.zhihuUrl = "
   // 添加成功匹配的結(jié)果
   results.add(zhuhuTemp);
   // 繼續(xù)查找下一個(gè)匹配對(duì)象
   isFind = questionMatcher.find() && urlMatcher.find();
  }
  return results;
 }
}

最后一個(gè)main方法負(fù)責(zé)調(diào)用。

import java.util.ArrayList;
public class Main {
 public static void main(String[] args) {
  // 定義即將訪問的鏈接
  String url = "
  // 訪問鏈接并獲取頁(yè)面內(nèi)容
  String content = Spider.SendGet(url);
  // 獲取該頁(yè)面的所有的知乎對(duì)象
  ArrayList<Zhihu> myZhihu = Spider.GetZhihu(content);
  // 打印結(jié)果
  System.out.println(myZhihu);
 }
}


Ok這樣就算搞定了。運(yùn)行一下看看結(jié)果:

好的效果不錯(cuò)。

接下來(lái)就是訪問鏈接然后獲取到所有的答案了。

下一回我們?cè)俳榻B。

好了,以上就是簡(jiǎn)單的介紹了如何使用java來(lái)抓取知乎的編輯推薦的內(nèi)容的全部過程了,非常詳盡,也很簡(jiǎn)單易懂,對(duì)吧,有需要的小伙伴可以參考下,自由擴(kuò)展也沒問題哈

相關(guān)文章

  • Netty源碼分析NioEventLoop處理IO事件相關(guān)邏輯

    Netty源碼分析NioEventLoop處理IO事件相關(guān)邏輯

    這篇文章主要介紹了Netty源碼分析NioEventLoop處理IO事件相關(guān)邏輯,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • JAVA實(shí)現(xiàn)經(jīng)典掃雷游戲的示例代碼

    JAVA實(shí)現(xiàn)經(jīng)典掃雷游戲的示例代碼

    windows自帶的游戲《掃雷》是陪伴了無(wú)數(shù)人的經(jīng)典游戲,本程序參考《掃雷》的規(guī)則進(jìn)行了簡(jiǎn)化,用java語(yǔ)言實(shí)現(xiàn),采用了swing技術(shù)進(jìn)行了界面化處理。感興趣的可以學(xué)習(xí)一下
    2022-01-01
  • mybatis中xml之trim屬性說明

    mybatis中xml之trim屬性說明

    這篇文章主要介紹了mybatis中xml之trim屬性說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java局域網(wǎng)聊天小程序

    java局域網(wǎng)聊天小程序

    這篇文章主要為大家詳細(xì)介紹了java局域網(wǎng)聊天小程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Java中生產(chǎn)者消費(fèi)者問題總結(jié)

    Java中生產(chǎn)者消費(fèi)者問題總結(jié)

    這篇文章主要介紹了Java中生產(chǎn)者消費(fèi)者問題總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • 一篇文章帶你入門Java多線程

    一篇文章帶你入門Java多線程

    這篇文章主要介紹了java多線程編程實(shí)例,分享了幾則多線程的實(shí)例代碼,具有一定參考價(jià)值,加深多線程編程的理解還是很有幫助的,需要的朋友可以參考下
    2021-08-08
  • Spring中@RequestMapping、@RestController和Postman

    Spring中@RequestMapping、@RestController和Postman

    本文介紹了Spring框架中常用的@RequestMapping和@RestController注解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-10-10
  • Java計(jì)算數(shù)學(xué)表達(dá)式代碼詳解

    Java計(jì)算數(shù)學(xué)表達(dá)式代碼詳解

    這篇文章主要介紹了Java計(jì)算數(shù)學(xué)表達(dá)式代碼詳解,具有一定借鑒價(jià)值,需要的朋友可以了解下。
    2017-12-12
  • Java文檔注釋用法+JavaDoc的使用說明

    Java文檔注釋用法+JavaDoc的使用說明

    這篇文章主要介紹了Java文檔注釋用法+JavaDoc的使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java EasyExcel實(shí)現(xiàn)動(dòng)態(tài)列解析和存表

    java EasyExcel實(shí)現(xiàn)動(dòng)態(tài)列解析和存表

    這篇文章主要為大家介紹了java EasyExcel實(shí)現(xiàn)動(dòng)態(tài)列解析和存表示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06

最新評(píng)論

抚远县| 庆云县| 淮阳县| 缙云县| 大英县| 神木县| 瑞丽市| 新民市| 新津县| 裕民县| 嘉黎县| 博湖县| 客服| 双柏县| 松江区| 佛坪县| 阿坝| 重庆市| 奇台县| 瓦房店市| 通辽市| 巨野县| 本溪市| 京山县| 修文县| 仁寿县| 北京市| 通海县| 错那县| 旌德县| 突泉县| 高尔夫| 渭源县| 平安县| 鄱阳县| 克东县| 新源县| 钟祥市| 嘉义县| 汉川市| 历史|