以前也用過爬蟲,比如使用nutch爬取指定種子,基于爬到的數(shù)據(jù)做搜索,還大致看過一些源碼。當(dāng)然,nutch對(duì)于爬蟲考慮的是十分全面和細(xì)致的。每當(dāng)看到屏幕上唰唰過去的爬取到的網(wǎng)頁信息以及處理信息的時(shí)候,總感覺這很黑科技。正好這次借助梳理Spring MVC的機(jī)會(huì),想自己弄個(gè)小爬蟲,簡(jiǎn)單沒關(guān)系,有些小bug也無所謂,我需要的只是一個(gè)能針對(duì)某個(gè)種子網(wǎng)站能爬取我想要的信息就可以了。有Exception就去解決,可能是一些API使用不當(dāng),也可能是遇到了http請(qǐng)求狀態(tài)異常,又或是數(shù)據(jù)庫讀寫有問題,就是在這個(gè)報(bào)exception和解決exception的過程中,JewelCrawler(兒子的小名)已經(jīng)可以能夠獨(dú)立的爬取數(shù)據(jù),并且還有一項(xiàng)基于Word2Vec算法做個(gè)情感分析的小技能。

  后面可能還會(huì)有未知的Exception等著解決,也有一些性能需要優(yōu)化,比如和數(shù)據(jù)庫的交互,數(shù)據(jù)的讀寫等等。但是目測(cè)年內(nèi)沒有太多精力放這上面了,所以今天做一個(gè)簡(jiǎn)單的總結(jié),而且前兩篇主要側(cè)重的是功能和結(jié)果,這篇來說說JewelCrawler是如何誕生的,并將代碼放到Github上(源碼地址在文章最后),有興趣的可以關(guān)注下(僅供交流學(xué)習(xí),請(qǐng)勿他用,考慮下douban君。多一點(diǎn)真誠(chéng),少一點(diǎn)傷害)

 

環(huán)境介紹

  開發(fā)工具:Intellij idea 14

  數(shù)據(jù)庫: Mysql 5.5 + 數(shù)據(jù)庫管理工具Navicat(可用來連接查詢數(shù)據(jù)庫)

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

  語言:Java

  Jar包管理:Maven

  版本管理:Git

 

目錄結(jié)構(gòu)

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 

  其中

  com.ansj.vec是Word2Vec算法的Java版本實(shí)現(xiàn)

  com.jackie.crawler.doubanmovie是爬蟲實(shí)現(xiàn)模塊,其中又包括

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

  有些包是空的,因?yàn)檫@些模塊還沒有用上,其中

    constants包是存放常量類

    crawl包存放爬蟲入口程序

    entity包映射數(shù)據(jù)庫表的實(shí)體類

    test包存放測(cè)試類

    utils包存放工具類

 

  resource模塊存放的是配置文件和資源文件,比如

    beans.xml:Spring上下文的配置文件

    seed.properties:種子文件

    stopwords.dic:停用詞庫

    comment12031715.txt:爬取的短評(píng)數(shù)據(jù)

    tokenizerResult.txt:使用IKAnalyzer分詞后的結(jié)果文件

    vector.mod:基于Word2Vec算法訓(xùn)練的模型數(shù)據(jù)

 

  test模塊是測(cè)試模塊,用于編寫UT.

 

數(shù)據(jù)庫配置

  1. 添加依賴的包

  JewelCrawler使用的maven管理,所以只需要在pom.xml中添加相應(yīng)的依賴就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.1.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>commons-pool</groupId>
    <artifactId>commons-pool</artifactId>
    <version>1.6</version>
</dependency>
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.38</version>
</dependency>

  

  2. 聲明數(shù)據(jù)源bean

  我們需要在beans.xml中聲明數(shù)據(jù)源的bean

1
2
3
4
5
6
7
<context:property-placeholder location="classpath*:*.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

注意: 這里是綁定了外部配置文件jdbc.properties,具體數(shù)據(jù)源的參數(shù)從該文件讀取。

  如果遇到問題“SQL [insert into user(id) values(?)]; Field 'name' doesn't  have a default value;”解決方法是設(shè)置表的相應(yīng)字段為自增長(zhǎng)字段。

 

解析頁面遇到的問題

  對(duì)于爬到的網(wǎng)頁數(shù)據(jù)需要解析dom結(jié)構(gòu),拿到自己想要的數(shù)據(jù),期間遇到如下錯(cuò)誤

  org.htmlparser.Node不識(shí)別

  解決方法:添加jar包依賴

1
2
3
4
5
<dependency>
    <groupId>org.htmlparser</groupId>
    <artifactId>htmlparser</artifactId>
    <version>1.6</version>
</dependency>

  

  org.apache.http.HttpEntity不識(shí)別

  解決方法:添加jar包依賴

1
2
3
4
5
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.2</version>
</dependency> 

  當(dāng)然這是期間遇到的問題,最后用的是Jsoup做的頁面解析。

 

maven倉庫下載速度慢

  之前使用的是默認(rèn)的maven中央倉庫,下載jar包的速度很慢,不知道是我的網(wǎng)絡(luò)問題還是其他原因,后來在網(wǎng)上找到了阿里云的maven倉庫,更新后,相比之前簡(jiǎn)直是秒下,吐血推薦。

1
2
3
4
5
6
7
8
<mirrors>
    <mirror>
      <id>alimaven</id>
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
      <mirrorOf>central</mirrorOf>       
    </mirror>
</mirrors>

  找到maven的settings.xml文件,添加這個(gè)鏡像即可。

 

讀取resource模塊下文件的一種方法

  比如讀取seed.properties文件

1
2
3
4
5
@Test
    public void testFile(){
        File seedFile = new File(this.getClass().getResource("/seed.properties").getPath());
        System.out.print("===========" + seedFile.length() + "===========" );
    }

  

有關(guān)正則表達(dá)式

  使用regrex正則表達(dá)式的時(shí)候,如果匹配上了定義的Pattern,則需要先調(diào)用matcher的find方法然后才能使用group方法找到子串。直接調(diào)用group方法是沒有辦法找到你想要的結(jié)果的。

  我看了下上面Matcher類的源碼

+ View Code

  原因是這樣的:這里如果不先調(diào)用find方法,直接調(diào)用group,可以發(fā)現(xiàn)group方法調(diào)用group(int group),該方法的方法體中有if first<0,顯然這里這個(gè)條件是成立的,因?yàn)閒irst的初始值就是-1,所以這里會(huì)拋異常。但是如果調(diào)用find方法,可以發(fā)現(xiàn),最終會(huì)調(diào)用search(nextSearchIndex),注意這里的nextSearchIndex已被last賦值,而last的值為0,再跳轉(zhuǎn)到search方法中

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
boolean search(int from) {
    this.hitEnd = false;
    this.requireEnd = false;
    from        = from < 0 0 : from;
    this.first  = from;
    this.oldLast = oldLast < 0 ? from : oldLast;
    for (int i = 0; i < groups.length; i++)
        groups[i] = -1;
    acceptMode = NOANCHOR;
    boolean result = parentPattern.root.match(this, from, text);
    if (!result)
        this.first = -1;
    this.oldLast = this.last;
    return result;
}

  這個(gè)nextSearchIndex傳給了from,而from在方法體中被賦值給了first,所以,調(diào)用了find方法之后,這個(gè)的first就不在是-1,也就不是拋異常了。

 

  源碼已經(jīng)上傳至Github:https://github.com/DMinerJackie/JewelCrawler

 

  以上說的問題比較碎,都是在遇到問題和解決問題的時(shí)候的一些總結(jié)。在具體操作的時(shí)候還會(huì)遇到其他問題,有問題或者建議的話歡迎提出來^^。

  最后放幾張截止目前爬取的數(shù)據(jù)

  Record表

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 

  其中存儲(chǔ)的是79032條,爬取過的網(wǎng)頁有48471條

 

  movie表

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 

  目前爬取了2964部影視作品

 

  comments表

seo優(yōu)化培訓(xùn),網(wǎng)絡(luò)推廣培訓(xùn),網(wǎng)絡(luò)營(yíng)銷培訓(xùn),SEM培訓(xùn),網(wǎng)絡(luò)優(yōu)化,在線營(yíng)銷培訓(xùn)

 

  爬取了29711條記錄

 

  如果您覺得閱讀本文對(duì)您有幫助,請(qǐng)點(diǎn)一下“推薦”按鈕,您的“推薦”將是我最大的寫作動(dòng)力!如果您想持續(xù)關(guān)注我的文章,請(qǐng)掃描二維碼,關(guān)注JackieZheng的微信公眾號(hào),我會(huì)將我的文章推送給您,并和您一起分享我日常閱讀過的優(yōu)質(zhì)文章。