java知乎爬蟲寫作過程和思路

0.需要的知識(shí)點(diǎn)

  • 正則表達(dá)式
  • java多線程線程池池知識(shí)
  • httpclient網(wǎng)絡(luò)庫及json和html結(jié)構(gòu)

1.獲取主話題

在知乎中一共有33個(gè)主話題父款,在33個(gè)主話題下又有15776個(gè)子話題,因此我們首先要獲取到33個(gè)主話題
(ps:一開始打算用HttpURLConnection進(jìn)行網(wǎng)絡(luò)請(qǐng)求榴嗅,由于后面需要以post形式訪問并且提交form因此后面的代碼改用了httpclient進(jìn)行網(wǎng)絡(luò)請(qǐng)求)

圖中的data-id就是主話題的id
public static void getTopicId(){
        new Thread(new Runnable() {

            @Override
            public void run() {
                Connection connection;
                int id = 1;
                try {
                    URL url = new URL("https://www.zhihu.com/topics");
                    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                    conn.setRequestMethod("GET");
                    conn.connect();
                    BufferedReader bfr = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8"));
                    String line = null;
                    StringBuilder sb = new StringBuilder();
                    while ((line = (bfr.readLine())) != null){
                        sb.append(line);
                    }
                    String result = sb.toString();
                    String regex = "data-id=\"[0-9]{0,6}\"";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher m = pattern.matcher(result);
                    String regx = "href=\"#.*?\"";
                    Pattern p = Pattern.compile(regx);
                    Matcher mn = p.matcher(result);
                    while (m.find() && mn.find()){
                        String s = m.group();
                        s = s.substring(9,s.length() - 1);
                        String sn = mn.group();
                        sn = sn.substring(7,sn.length() - 1);
                        System.out.println(s + " " + sn);
                        connection = JDBCUtil.getConn();
                        PreparedStatement state = (PreparedStatement) connection.prepareStatement("insert into main_topic values(?,?,?)");
                        state.setInt(1, id++);
                        state.setInt(2, Integer.valueOf(s));
                        state.setString(3, sn);
                        state.execute();
                    }
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();
    }

2.獲取各個(gè)主話題下的分話題

通過抓包我們可以發(fā)現(xiàn)在分話題頁面通過post請(qǐng)求訪問到服務(wù)器來加載分話題,沒一次下拉到底部會(huì)多加載20個(gè)分話題,通過offset來控制熬粗,因此我們可以通過post請(qǐng)求服務(wù)器來獲得json數(shù)據(jù)


post請(qǐng)求結(jié)構(gòu)
通過postman模擬post請(qǐng)求得到返回?cái)?shù)據(jù)

由于返回的json數(shù)據(jù)中的中文為unicode編碼,因此運(yùn)用了Utils類中的方法來轉(zhuǎn)換為中文以便儲(chǔ)存到數(shù)據(jù)庫中

public static void getChildTopics(int topic_id,Connection conn) throws Exception{
        int offset = 0;;
        while (true){
            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
            CloseableHttpClient httpClient = HttpClients.custom()
                    .setRetryHandler(new DefaultHttpRequestRetryHandler())
                    .setConnectionManager(cm)
                    .build();
            HttpPost req = new HttpPost("https://www.zhihu.com/node/TopicsPlazzaListV2");
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("method", "next"));
            params.add(new BasicNameValuePair("params", "{\"topic_id\":" + topic_id + ",\"offset\":" + offset +",\"hash_id\":\"37492588249aa9b50ee49d1797e9af81\"}"));
            req.setEntity(new UrlEncodedFormEntity(params,Consts.UTF_8));
            HttpResponse resp = httpClient.execute(req);
            String sb = EntityUtils.toString(resp.getEntity());
            if (sb.length() < 25) break;
            String regex = "<strong>.*?<\\\\/strong>";
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(sb);
            String regx = "href=\\\\\"\\\\/topic\\\\/[0-9]+\\\\\"";
            Pattern p1 = Pattern.compile(regx);
            Matcher m1 = p1.matcher(sb);
            while (m.find() && m1.find()){
                String temp = m.group().substring(8, m.group().length() - 10);
                String sql = "insert into child_topic values(null,?,?,?)";
                PreparedStatement state = (PreparedStatement) conn.prepareStatement(sql);
                state.setInt(1,topic_id);
                state.setString(2,m1.group().substring(16, m1.group().length() - 2));
                state.setString(3,Utils.decodeUnicode(temp));
                state.execute();
            }
            offset += 20;
        }
    }

通過主話題id來獲取下面的子話題id

3.通過分話題id來獲取熱門問答

public static void loadOneTopicHotQA(int child_topic_id) throws Exception{
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        CloseableHttpClient httpClient = HttpClients.custom()
                .setRetryHandler(new DefaultHttpRequestRetryHandler())
                .setConnectionManager(cm)
                .build();
        HttpGet req = new HttpGet("https://www.zhihu.com/topic/" + child_topic_id + "/hot");
        HttpResponse resp = httpClient.execute(req);
        String result = EntityUtils.toString(resp.getEntity());
        //正則匹配打不出來余境,后面以截圖形式給出
        Pattern p_qa_id = Pattern.compile(regex_qa_id);
        Pattern p_qa_name = Pattern.compile(regex_qa_name);
        Pattern p_qa_username = Pattern.compile(regex_qa_username);
        Matcher m_qa_id = p_qa_id.matcher(result);
        Matcher m_qa_name = p_qa_name.matcher(result);
        Matcher m_qa_username = p_qa_username.matcher(result);
        while (m_qa_id.find() && m_qa_name.find() && m_qa_username.find()){
            String[] qanda_id = m_qa_id.group().split("/");
            String q_id = qanda_id[2];
            String a_id = qanda_id[4].substring(0, qanda_id[4].length() - 2);
            String q_name = m_qa_name.group().split("\n")[1];
            String temp = m_qa_username.group();
            String q_username = null;
            if (temp.contains("匿名用戶")) q_username = "匿名用戶";
            else if (temp.contains("知乎用戶")) q_username = "知乎用戶";
            else q_username = temp.substring(30, temp.length() - 1);
            HotQA qa = new HotQA(child_topic_id,Integer.valueOf(q_id), q_name, Integer.valueOf(a_id), q_username);
            DaoImpl daoimpl = new DaoImpl();
            daoimpl.save(qa, child_topic_id);
        }
    }

正則匹配

由于未登陸情況下可能會(huì)出現(xiàn)答主名字被替換為知乎用戶驻呐,因此要考慮答主名字為知乎用戶這種情況

4.爬到的數(shù)據(jù)能做什么

數(shù)據(jù)

5.擴(kuò)展

在DAO層中提供了返回指定話題最新動(dòng)態(tài)的方法,同時(shí)也包含了通過answer_id獲取指定回答的方法芳来,將來可能還會(huì)加入爬取用戶信息的功能含末。

6.感謝

感謝看到這里,如果不嫌棄的話給gayhub項(xiàng)目一個(gè)star唄即舌,關(guān)注一下我也是最最最最吼的
gayhub項(xiàng)目 可以直接點(diǎn)喲
另外大家可以也可以通過微博聯(lián)系我喲:關(guān)耳金名
如何使用及編程過程中踩過的坑

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末佣盒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子顽聂,更是在濱河造成了極大的恐慌肥惭,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,126評(píng)論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件紊搪,死亡現(xiàn)場離奇詭異务豺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)嗦明,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門笼沥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事奔浅」菽桑” “怎么了?”我有些...
    開封第一講書人閱讀 169,941評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵汹桦,是天一觀的道長鲁驶。 經(jīng)常有香客問我,道長舞骆,這世上最難降的妖魔是什么钥弯? 我笑而不...
    開封第一講書人閱讀 60,294評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮督禽,結(jié)果婚禮上脆霎,老公的妹妹穿的比我還像新娘。我一直安慰自己狈惫,他們只是感情好睛蛛,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胧谈,像睡著了一般忆肾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上菱肖,一...
    開封第一講書人閱讀 52,874評(píng)論 1 314
  • 那天客冈,我揣著相機(jī)與錄音,去河邊找鬼稳强。 笑死郊酒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的键袱。 我是一名探鬼主播,決...
    沈念sama閱讀 41,285評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼摹闽,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼蹄咖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起付鹿,我...
    開封第一講書人閱讀 40,249評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤澜汤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后舵匾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俊抵,經(jīng)...
    沈念sama閱讀 46,760評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評(píng)論 3 343
  • 正文 我和宋清朗相戀三年坐梯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徽诲。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,973評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖谎替,靈堂內(nèi)的尸體忽然破棺而出偷溺,到底是詐尸還是另有隱情,我是刑警寧澤钱贯,帶...
    沈念sama閱讀 36,631評(píng)論 5 351
  • 正文 年R本政府宣布挫掏,位于F島的核電站,受9級(jí)特大地震影響秩命,放射性物質(zhì)發(fā)生泄漏尉共。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評(píng)論 3 336
  • 文/蒙蒙 一弃锐、第九天 我趴在偏房一處隱蔽的房頂上張望袄友。 院中可真熱鬧,春花似錦拿愧、人聲如沸杠河。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽券敌。三九已至,卻和暖如春柳洋,著一層夾襖步出監(jiān)牢的瞬間待诅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評(píng)論 1 275
  • 我被黑心中介騙來泰國打工熊镣, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卑雁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,431評(píng)論 3 379
  • 正文 我出身青樓绪囱,卻偏偏與公主長得像测蹲,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鬼吵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理扣甲,服務(wù)發(fā)現(xiàn),斷路器齿椅,智...
    卡卡羅2017閱讀 134,722評(píng)論 18 139
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫琉挖、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,131評(píng)論 4 61
  • 翻譯約定 primary data: 主數(shù)據(jù)resource identifier object 資源標(biāo)識(shí)符對(duì)象r...
    sladeliu閱讀 2,401評(píng)論 0 2
  • 在《美國黑幫》片尾涣脚,丹澤爾華盛頓端著咖啡杯示辈,看著幾個(gè)街頭少年,對(duì)前來接他出獄的朋友說:Even a fool ge...
    edd9fce0bc86閱讀 526評(píng)論 0 2
  • 杏鮑菇炒肉絲 制作步驟 1遣蚀、杏鮑菇切絲矾麻,肉切絲纱耻,用生抽、淀粉腌漬15分鐘射富。 2膝迎、鍋內(nèi)燒開水,杏鮑菇過水煮一會(huì)兒胰耗,到...
    時(shí)光紀(jì)閱讀 170評(píng)論 0 1