Jsoup實(shí)現(xiàn)習(xí)題知識(shí)點(diǎn)的初步標(biāo)注

背景

繼上次使用Jsoup簡(jiǎn)易爬取POJ題面之后界轩,我所在的校創(chuàng)小組最近又有了新任務(wù),就是要標(biāo)注算法題所涉及的知識(shí)點(diǎn)衔瓮。人工標(biāo)注肯定不現(xiàn)實(shí)浊猾,所以想到了模擬百度搜索并從CSDN博客上爬取相應(yīng)的題目解析,和預(yù)先定義好的知識(shí)點(diǎn)集合進(jìn)行匹配报辱,統(tǒng)計(jì)匹配成功次數(shù)与殃,按匹配次數(shù)從大到小排序,從而實(shí)現(xiàn)習(xí)題知識(shí)點(diǎn)的初步標(biāo)注碍现。下面以標(biāo)注HDU OJ的題目知識(shí)點(diǎn)為例:

定義知識(shí)點(diǎn)集合

在開始爬取之前幅疼,我們要預(yù)先定義用于匹配爬取結(jié)果的知識(shí)點(diǎn)集合。事實(shí)證明知識(shí)點(diǎn)集合的粒度和廣度對(duì)標(biāo)注結(jié)果影響很大昼接,所以如何定義一個(gè)合適的知識(shí)點(diǎn)集合還需要再三斟酌爽篷。這里我只是大致羅列了一些算法知識(shí)點(diǎn),保存在項(xiàng)目resource目錄的algorithm.txt中:

模擬
貪心
枚舉
遞歸
構(gòu)造
遞推
后綴數(shù)組
樹狀數(shù)組
差分約束
dp
BFS
DFS
迭代加深搜索
記憶化搜索
分治
排序
動(dòng)態(tài)規(guī)劃
最短路
拓?fù)渑判?最小生成樹
網(wǎng)絡(luò)流
二分
二分圖
數(shù)論
組合數(shù)學(xué)
計(jì)算幾何
博弈
線段樹
字典樹
并查集
KMP
AC自動(dòng)機(jī)
凸包
三分
GCD
擴(kuò)展歐幾里得
尺取法
RMQ
IDA*
背包
莫隊(duì)算法
Polya

定義知識(shí)點(diǎn)分類實(shí)體類

/**
 * 分類實(shí)體類
 */
public class Category {
    private int index;
    private int occurCount;


    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public int getOccurCount() {
        return occurCount;
    }

    public void setOccurCount(int occurCount) {
        this.occurCount = occurCount;
    }

    @Override
    public String toString() {
        return "Category{" +
                "name=" + Main.getCandidate().get(index) +
                ", occurCount=" + occurCount +
                '}';
    }
}

引入Jsoup依賴

由于構(gòu)建的是Maven項(xiàng)目慢睡,可以直接在pom.xml文件里引入Jsoup的相關(guān)依賴:

<dependency>
         <groupId>org.jsoup</groupId>
         <artifactId>jsoup</artifactId>
         <version>1.11.2</version>
</dependency>

定義爬蟲工具類

下面是整個(gè)項(xiàng)目的核心逐工,用于模擬百度搜索和爬取所需信息。

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/**
 * 爬蟲工具類
 */
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/**
 * 爬蟲工具類
 */
public class CrawlUtils {
    public static void crawl(int begin,int end) throws IOException {
        //用百度搜索關(guān)鍵詞HDU+題號(hào)+CSDN博客
        for (int pid = begin; pid <= end; pid++) {
            Document doc = Jsoup.connect("https://www.baidu.com/s?ie=utf-8&wd=HDU"
                    + pid + "CSDN博客").get();
            Elements elements = doc.select("h3.t");

            //處理公共資源漂辐,加鎖
            synchronized(CrawlUtils.class){
                List<String> arrayList = Main.getCandidate();
                Category[] c = Main.getCategories();
                for (int i = 0;i < c.length;i++) {
                    c[i] = new Category();
                    c[i].setIndex(i);
                    c[i].setOccurCount(0);
                }
                System.out.println("HDU" + pid + "分析結(jié)果:");
                //選取百度的前5個(gè)鏈接泪喊,分別解析
                for (int k = 0;k < 5;k++) {

                    //如果題號(hào)不匹配,直接跳過該鏈接
                    if(!elements.get(k).text().contains(String.valueOf(pid)))
                        continue;
                    String link = elements.get(k).selectFirst("a").attr("href");
                    //對(duì)于每個(gè)鏈接頁面髓涯,爬取article標(biāo)簽中的文本
                    String text = Jsoup.connect(link).timeout(30000).get().select("article").text();

                    //將文本和預(yù)先定義的算法集合進(jìn)行匹配袒啼,統(tǒng)計(jì)不同算法出現(xiàn)次數(shù)
                    for (int i = 0;i < arrayList.size();i++) {
                        int start = 0;
                        while(start < text.length() && text.indexOf(arrayList.get(i),start) != -1){
                            c[i].setOccurCount(c[i].getOccurCount() + 1);
                            start = text.indexOf(arrayList.get(i),start) + 1;
                        }
                    }

                }
                //按照出現(xiàn)次數(shù)從高到低排序
                Arrays.sort(c, new Comparator<Category>() {
                    public int compare(Category o1, Category o2) {
                        return o2.getOccurCount() - o1.getOccurCount();
                    }
                });
                //輸出出現(xiàn)次數(shù)大于1的算法標(biāo)簽
                int tot = 0;
                for(int i = 0;i < 50;i++){
                    if(c[i].getOccurCount() > 0){
                        System.out.println(c[i]);
                        tot++;
                    }
                }
                if(tot == 0){
                    System.out.println("未匹配到算法分類");
                }
                System.out.println();
            }

        }
    }
}

為提高爬取效率,我們采用了多線程爬蟲,即用多個(gè)線程同時(shí)爬取不同題目范圍的URL信息蚓再。特別要注意的是滑肉,在本例中多個(gè)爬蟲線程共用一個(gè)控制臺(tái),即控制臺(tái)屬于公共資源摘仅。在處理公共資源時(shí)(輸出爬取結(jié)果)靶庙,需要加鎖,否則多個(gè)線程的爬取結(jié)果將交替輸出娃属。但不可以對(duì)整個(gè)crawl方法加鎖六荒,這樣鎖的粒度太大,多線程爬蟲的效率沒有得到發(fā)揮矾端,即同一時(shí)刻只允許有一個(gè)線程爬取數(shù)據(jù)恬吕,其他線程都被同步阻塞,這顯然是不符合預(yù)想的须床。

定義爬蟲線程類

import java.io.IOException;

/**
 * 爬蟲線程
 */
public class CrawlerThread implements Runnable{
    private int start;
    private int end;

    public CrawlerThread(int start, int end) {
        this.start = start;
        this.end = end;
    }

    public void run() {
        try {
            CrawlUtils.crawl(start,end);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


}

編寫主方法開始爬取

為了提高效率,開了8個(gè)線程爬取渐裂。

import java.io.*;
import java.util.*;


public class Main {
    private static List<String> candidate = new ArrayList<String>(); //存放候選的算法分類
    private static Category[] categories = new Category[50];//保存不同分類豺旬,包括名稱和出現(xiàn)次數(shù)

    static {  //導(dǎo)入候選的算法分類
        InputStream is = null;
        try {
            is = new FileInputStream("./resource/algorithm.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(is,"GBK"));
            String line;
            while ((line = br.readLine()) != null) {
                candidate.add(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                br.close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

    public static void main(String[] args) throws IOException {
        //開8個(gè)線程爬取
        Thread th[] = new Thread[8];
        for(int i = 0;i < 8;i++){
            th[i] = new Thread(new CrawlerThread((i + 2) * 500,(i + 2) * 500 + 500));
            th[i].start();
        }
    }

    public static List<String> getCandidate() {
        return candidate;
    }

    public static void setCandidate(List<String> candidate) {
        Main.candidate = candidate;
    }

    public static Category[] getCategories() {
        return categories;
    }

    public static void setCategories(Category[] categories) {
        Main.categories = categories;
    }
}

爬取結(jié)果

爬取結(jié)果

附Github鏈接:https://github.com/Steven1997/AlgorithmCrawler

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市柒凉,隨后出現(xiàn)的幾起案子族阅,更是在濱河造成了極大的恐慌,老刑警劉巖膝捞,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坦刀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蔬咬,警方通過查閱死者的電腦和手機(jī)鲤遥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來林艘,“玉大人盖奈,你說我怎么就攤上這事『” “怎么了钢坦?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)啥酱。 經(jīng)常有香客問我爹凹,道長(zhǎng),這世上最難降的妖魔是什么镶殷? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任禾酱,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宇植。我一直安慰自己得封,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布指郁。 她就那樣靜靜地躺著忙上,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闲坎。 梳的紋絲不亂的頭發(fā)上疫粥,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音腰懂,去河邊找鬼梗逮。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绣溜,可吹牛的內(nèi)容都是我干的慷彤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼怖喻,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼底哗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锚沸,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤跋选,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后哗蜈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體前标,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年距潘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炼列。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绽昼,死狀恐怖唯鸭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情硅确,我是刑警寧澤目溉,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站菱农,受9級(jí)特大地震影響缭付,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜循未,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一陷猫、第九天 我趴在偏房一處隱蔽的房頂上張望秫舌。 院中可真熱鬧,春花似錦绣檬、人聲如沸足陨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽墨缘。三九已至,卻和暖如春零抬,著一層夾襖步出監(jiān)牢的瞬間镊讼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工平夜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝶棋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓忽妒,卻偏偏與公主長(zhǎng)得像玩裙,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子段直,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354