国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Gecco的網(wǎng)絡(luò)爬蟲例子

raoyi / 1284人閱讀

摘要:到了這個時候,我們已經(jīng)可以把京東的分類首頁的手機模塊給抓取下來,并且保存成。

GeccoSpider爬蟲例子

前些天,想要用爬蟲抓取點東西,但是網(wǎng)上很多爬蟲都是使用python語言的,本人只會java,因此,只能找相關(guān)java的爬蟲資料,在開源中國的看到國內(nèi)的大神寫的一個開源的爬蟲框架,并下源碼研究了一下,發(fā)現(xiàn)跟官網(wǎng)描述的一樣,夠簡單,簡潔易用!有興趣的朋友可以到官網(wǎng)了解下!

我這個例子也是在查看了官網(wǎng)的《教您使用java爬蟲gecco抓取JD全部商品信息》這篇博客之后,自己動手實現(xiàn)的,并且加入了持久化操作,由于京東的商品比較具有層次結(jié)構(gòu),類似一棵樹,因此,傳統(tǒng)的SQL數(shù)據(jù)庫很顯然不能很好存儲,于是我選用文檔型的NoSQL數(shù)據(jù)庫MongoDB在Monogo里存儲類似json的數(shù)據(jù),很容易表達出數(shù)據(jù)之間的層次關(guān)系。下面記錄一下我的實現(xiàn)過程,并且向Gecco作者大神致敬,也建議對這方面有興趣的朋友去官網(wǎng)查看作者的博客,會有更大的收獲,畢竟小弟水平有限,這里寫的也只是個人理解后實現(xiàn)的!

環(huán)境準(zhǔn)備

jdk 我使用的是jdk1.8.0_74

IDE eclipse4.6

jar jar包有點多,主要是依賴包,所有的依賴包都在源碼中的lib目錄下。這里就不一一貼出來了

DB mongoDB 3.2.10

mongo driver 3.3

程序入口

程序從cn.succy.geccospider.engine.jd.JDEngine這個類開始

public class JDEngine {

    public static void main(String[] args) {
        String url = "https://www.jd.com/allSort.aspx";
        String classpath = "cn.succy.geccospider";
        HttpRequest request = new HttpGetRequest(url);
        request.setCharset("gb2312");
        // 如果pipeline和htmlbean不在同一個包,classpath就要設(shè)置到他們的共同父包
        // 本引擎主要是把京東分類的頁面手機板塊給抓取過來封裝成htmlbean
        GeccoEngine.create().classpath(classpath).start(request).interval(2000).run();

        // 本引擎是負(fù)責(zé)抓取每一個細(xì)目對應(yīng)的頁面的第一頁的所有商品列表的數(shù)據(jù),開啟5個線程同時抓取,提升效率
        GeccoEngine.create().classpath(classpath).start(AllSortPipeline.cateRequests).thread(5)
                .interval(2000).run();
    }
}

在這段代碼里邊,總共用了兩個引擎,第一個先是抓取京東分類的入口url里邊的版塊入口 https://www.jd.com/allSort.aspx,在程序啟動的時候,底層會在指定的classpath包路徑下,尋找有> @Gecco注解的類,并且url和注解matchUrl對應(yīng),這個類就是抓取到的數(shù)據(jù)要映射成的HtmlBean,里邊的屬性可以通過注解把這個url下符合條件的節(jié)點對應(yīng)起來,從而,可以把我們想要的數(shù)據(jù)通過一個HtmlBean給封裝起來了。要注意一點,classpath應(yīng)該設(shè)置到能包含所有有類注解的類的包路經(jīng),如果同時兩個子包里邊的類都存在類注解,那么,這個classpath應(yīng)該就是設(shè)置到他們的共同父包下,以此類推……interval(2000)方法是指,隔多長時間執(zhí)行一次抓取,單位毫秒。下面我們看一下京東的分類頁面的結(jié)構(gòu),并且看一下我要抓取的是那一部分!

在這張圖片里邊,我們可以看到,實際上我們要抓取的是先把圈出部分抓取出來,把每一塊封裝成一個AllSort對象,下面我們看一下這個類!

@Gecco(matchUrl = "https://www.jd.com/allSort.aspx", pipelines = { "allSortPipeline",
        "consolePipeline" })
public class AllSort implements HtmlBean {
    private static final long serialVersionUID = 3422937382621558860L;

    @Request
    private HttpRequest request;

    /**
     * 抓取手機模塊的數(shù)據(jù)
     */
    @HtmlField(cssPath = "div.category-items > div:nth-child(1) > div:nth-child(2) > div.mc > div.items > dl")
    private List cellPhone;

    public HttpRequest getRequest() {
        return request;
    }

    public void setRequest(HttpRequest request) {
        this.request = request;
    }

    public List getCellPhone() {
        return cellPhone;
    }

    public void setCellPhone(List cellPhone) {
        this.cellPhone = cellPhone;
    }
}

先看注解@Gecco ,這個注解里邊的matchUrl對應(yīng)的就是引擎開始爬的那個url,pipeline在我的理解是一個管道,玩過linux的朋友應(yīng)該知道linux的管道是什么,java里邊也有管道輸入輸出流,和這些相似,這里的大致意思是,當(dāng)這個類里邊的屬性都裝配好了之后,接著把這個類的對象當(dāng)成一個輸入條件,傳遞到pipline里邊配置好的pipleline類處理,pipeline類要實現(xiàn)一個叫做Pipeline的接口,并且通過@PipelineName注解指定這個pipeline叫啥名,關(guān)于Pipeline相關(guān)的,待會兒再說。實際上,在AllSort這個類里邊,把對應(yīng)選擇器選中的內(nèi)容,直接注入到一個叫做cellPhone的列表,關(guān)于這個待會兒再說。我們先看一下這個List cellPhone;裝載的到底是什么!

實際上,這里圈出的就是一個Category對象,手機模塊所有的Category就是List cellPhone!那么,Category到底是什么樣的一個東西呢?我們看一下這個類是怎么實現(xiàn)的就明白了!

public class Category implements HtmlBean {

    private static final long serialVersionUID = -1808704248579938878L;

    /**
     * 對應(yīng)的是大的分類名字,如手機通訊,運營商,手機配件等
     */
    @Text
    @HtmlField(cssPath = "dt > a")
    private String typeName;

    /**
     * 相對于上面的大的分類下的小類目名字
     */
    @HtmlField(cssPath = "dd > a")
    private List categories;

    public String getTypeName() {
        return typeName;
    }

    public void setTypeName(String typeName) {
        this.typeName = typeName;
    }

    public List getCategories() {
        return categories;
    }

    public void setCategories(List categories) {
        this.categories = categories;
    }
}

也就是如下圖所示的標(biāo)簽對應(yīng)的文本和url

細(xì)心的朋友應(yīng)該會發(fā)現(xiàn),這里的@HtmlField(cssPath = "dd > a")的選擇器直接從dd開始,那是因為,在gecco里邊,Category對象是作為上面AllSort的一部分,因此,選擇器可以承接上級,也就是說,

@HtmlField(cssPath = "div.category-items > div:nth-child(1) > div:nth-child(2) > div.mc > div.items > dl")
private List cellPhone;

已經(jīng)到了dl這一層,那么它里邊的Category里的元素就可以直接從dl下面開始獲取,所以會看到像注解@HtmlField(cssPath = "dd > a")這種樣子的選擇器。
到了這個時候,我們已經(jīng)可以把京東的分類首頁的手機模塊給抓取下來,并且保存成javaBean。好了,下面可以說說對于注解上面的pipeline到底是什么,怎么用了!
上面我們也有說到,pipeline是一個管道連接,也就是當(dāng)頁面的HtmlBean解析完成后,再以此執(zhí)行注解中配置的所有的pipeline,我們在AllSort中配置有兩個pipeline,分別是"allSortPipeline","consolePipeline",第二個是往控制臺輸出,輸出的格式是json的格式的,這個沒有什么好講的,這里面我想說一下的是第一個,這個是我自定義的。好,接下來先上代碼看一下這個類是怎么實現(xiàn)的。

@PipelineName("allSortPipeline")
public class AllSortPipeline implements Pipeline {

    public static List cateRequests = new ArrayList<>();

    @Override
    public void process(AllSort allSort) {
        List cellPhones = allSort.getCellPhone();
        for (Category category : cellPhones) {
            // 獲取mongo的集合
            MongoCollection collection = MongoUtils.getCollection();
            // 把json轉(zhuǎn)成Document
            Document doc = Document.parse(JSON.toJSONString(category));
            // 向集合里邊插入一條文檔
            collection.insertOne(doc);
            List hrefs = category.getCategories();
            // 遍歷HrefBean,取出里邊保存的url
            for (HrefBean href : hrefs) {
                HttpRequest request = allSort.getRequest();
                // 把url保存起來,方便后面開啟一個新的引擎進行多線程抓取數(shù)據(jù)
                cateRequests.add(request.subRequest(href.getUrl()));
            }
        }
    }
}

最上面的注解就是給這個pipeline起個名字,接著是把數(shù)據(jù)先入庫,入庫的數(shù)據(jù)長得像這樣子:
{“typeName":"手機通訊","categories":[{"title":"手機","url":"……"},……]}這種樣子,接下來就可以順著剛剛提取出來的每一個小類目的url進行抓取他們對應(yīng)的頁面的數(shù)據(jù)了,我們先看一下手機這個小類目對應(yīng)的頁面長什么樣的!如下圖

這里邊的商品item就是我們想要抓取的數(shù)據(jù),每一頁有60條,對應(yīng)的每個頁面封裝成一個ProductList類,具體規(guī)則抽取在上面已經(jīng)提及到,在這里就不再提及怎么提取規(guī)則了,相信看到這里的朋友,應(yīng)該可以依葫蘆畫瓢了,下面貼出代碼,看一下ProductList的實現(xiàn)類!

@Gecco(matchUrl = "https://list.jd.com/list.html?cat={cat}", pipelines = { "consolePipeline",
        "filePipeline" ,"mongoPipeline"})
public class ProductList implements HtmlBean {

    private static final long serialVersionUID = -6580138290566056728L;

    /**
     * 獲取請求對象,從該對象中可以獲取抓取的是哪個url
     */
     @Request
     private HttpRequest request;

    // #plist > ul > li.gl-item > div.j-sku-item
    @HtmlField(cssPath = "#plist > ul > li.gl-item")
    private List details;

     public HttpRequest getRequest() {
     return request;
     }
    
     public void setRequest(HttpRequest request) {
     this.request = request;
     }

    public List getDetails() {
        return details;
    }

    public void setDetails(List details) {
        this.details = details;
    }

}

值得提一下的是,matchUrl里邊有一個{cat},這個是像url傳遞參數(shù),在HttpRequest里的url保存的就是填充參數(shù)之后url字符串,mongoPipeline就是對這里邊完成填充HtmlBean之后,執(zhí)行對應(yīng)mongoDB操作的pipeline,我們先看一下這個pipeline!

@PipelineName("mongoPipeline")
public class MongoPipeline implements Pipeline {

    @Override
    public void process(ProductList productList) {
        MongoCollection collection = MongoUtils.getCollection();
        HttpRequest req = productList.getRequest();
        // 從productList里邊獲取url,目的是為了從之前存進數(shù)據(jù)庫中找到對應(yīng)url的小類目
        String url = req.getUrl();
        // 把類目名對應(yīng)的商品詳情的列表獲取,例如,手機對應(yīng)到的頁面的60條記錄
        List details = productList.getDetails();
        // 轉(zhuǎn)成json字符串
        String jsonString = JSON.toJSONString(details);
        // 通過url找到數(shù)組里邊對應(yīng)url的類目,然后添加一個字段叫做details,并且把details的值
        // 給添加進去
        collection.updateOne(new Document("categories.url", url),
                Document.parse("{"$set":{"categories.$.details":" + jsonString + "}}"));
    }
}

上面代碼就可以實現(xiàn)通過獲取到請求對象里邊的url,因為url是唯一的,所以可以找到對應(yīng)的類目的信息,如下圖


這樣子就可以在這個記錄下面把抓取到的商品詳情列表插進去,表示該類目下面有這么多(60條)商品,保存進去之后,成下面的樣子。

我們看下ProductDetail怎么實現(xiàn)的,這也是一個普通的HtmlBean,和上面的沒有什么區(qū)別,都是規(guī)則抽取,然后把里邊想要的數(shù)據(jù)給注入到bean的屬性即可

public class ProductDetail implements HtmlBean {

    private static final long serialVersionUID = -6362237918542798717L;

    @Attr(value = "data-sku")
    @HtmlField(cssPath = "div.j-sku-item")
    private String pCode;

    @Image({ "data-lazy-img", "src" })
    @HtmlField(cssPath = "div.j-sku-item > div.p-img > a > img")
    private String pImg;

    
    //#plist > ul > li:nth-child(1) > div > div.p-price > strong:nth-child(1) > i
    @Text
    @HtmlField(cssPath = "div.j-sku-item > div.p-price > strong:nth-child(1) > i")
    private String pPrice;

    @Text
    @HtmlField(cssPath = "div.j-sku-item > div.p-name > a > em")
    private String pTitle;

    @Text
    @HtmlField(cssPath = "div.j-sku-item > div.p-comment > strong > a.comment")
    private String pComment;

    @Text
    @HtmlField(cssPath = "div.j-sku-item > div.p-shop > span > a")
    private String pShop;

    @Text
    @HtmlField(cssPath = "div.j-sku-item > div.p-icons > *")
    private List pIcons;

    public String getpCode() {
        return pCode;
    }

    public void setpCode(String pCode) {
        this.pCode = pCode;
    }

    public String getpImg() {
        return pImg;
    }

    public void setpImg(String pImg) {
        this.pImg = pImg;
    }

    public String getpPrice() {
        return pPrice;
    }

    public void setpPrice(String pPrice) {
        this.pPrice = pPrice;
    }

    public String getpTitle() {
        return pTitle;
    }

    public void setpTitle(String pTitle) {
        this.pTitle = pTitle;
    }

    public String getpComment() {
        return pComment;
    }

    public void setpComment(String pComment) {
        this.pComment = pComment;
    }

    public String getpShop() {
        return pShop;
    }

    public void setpShop(String pShop) {
        this.pShop = pShop;
    }

    public List getpIcons() {
        return pIcons;
    }

    public void setpIcons(List pIcons) {
        this.pIcons = pIcons;
    }

}

到這里,基本上就已經(jīng)實現(xiàn)了數(shù)據(jù)的抓取和入庫了,從整體上來看,就只有一條數(shù)據(jù),呈一棵樹一樣,這種結(jié)構(gòu)如果用SQL數(shù)據(jù)庫做的話,會存在大量自連接,造成很多數(shù)據(jù)冗余,因此,使用文檔數(shù)據(jù)庫是最好不過的了
如果這個對您有所幫助,請點個Star喲

源代碼

代碼已經(jīng)上傳到osc的代碼倉庫,由于本人網(wǎng)速不是非常好,因此并沒有使用maven管理項目,所有所需的jar包也都在項目源碼的lib包里邊,點擊源代碼下載

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/69803.html

相關(guān)文章

  • Gecco網(wǎng)絡(luò)爬蟲例子

    摘要:到了這個時候,我們已經(jīng)可以把京東的分類首頁的手機模塊給抓取下來,并且保存成。 GeccoSpider爬蟲例子 前些天,想要用爬蟲抓取點東西,但是網(wǎng)上很多爬蟲都是使用python語言的,本人只會java,因此,只能找相關(guān)java的爬蟲資料,在開源中國的看到國內(nèi)的大神寫的一個開源的爬蟲框架,并下源碼研究了一下,發(fā)現(xiàn)跟官網(wǎng)描述的一樣,夠簡單,簡潔易用!有興趣的朋友可以到官網(wǎng)了解下! 我這個例...

    Hydrogen 評論0 收藏0
  • 用JAVA做一個爬蟲程序——Gecco

    摘要:是一個開源的簡單的爬蟲框架主要是通過將獲取的網(wǎng)頁信息封裝成來進行爬取信息。作者也是一個新手。這篇文章只是提供一個入門的思路。開啟多少個線程抓取隔多長時間抓取次部分。是用來抓取元素的連接是指獲取得到的內(nèi)容。并且這個類需要實現(xiàn)。 Gecco是一個開源的簡單的java爬蟲框架主要是通過將獲取的網(wǎng)頁信息封裝成HtmlBean來進行爬取信息。作者也是一個新手。這篇文章只是提供一個入門的思路。如果...

    Tony 評論0 收藏0
  • Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---23、使用Urllib:分析Robots協(xié)議

    摘要:比如我們可以設(shè)置這就代表我們設(shè)置的規(guī)則對百度爬蟲是有效的。上一篇文章網(wǎng)絡(luò)爬蟲實戰(zhàn)使用解析鏈接下一篇文章網(wǎng)絡(luò)爬蟲實戰(zhàn)基本使用 上一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---22、使用Urllib:解析鏈接下一篇文章:Python3網(wǎng)絡(luò)爬蟲實戰(zhàn)---24、requests:基本使用 利用 Urllib 的 robotparser 模塊我們可以實現(xiàn)網(wǎng)站 Robots 協(xié)議的分析,本節(jié)我們來簡...

    kaka 評論0 收藏0
  • API例子:用Python驅(qū)動Firefox采集網(wǎng)頁數(shù)據(jù)

    摘要:開源即時網(wǎng)絡(luò)爬蟲項目將與基于的異步網(wǎng)絡(luò)框架集成,所以本例將使用采集淘寶這種含有大量代碼的網(wǎng)頁數(shù)據(jù),但是要注意本例一個嚴(yán)重缺陷用加載網(wǎng)頁的過程發(fā)生在中,破壞了的架構(gòu)原則。 showImg(https://segmentfault.com/img/bVyzAX); 1,引言 本文講解怎樣用Python驅(qū)動Firefox瀏覽器寫一個簡易的網(wǎng)頁數(shù)據(jù)采集器。開源Python即時網(wǎng)絡(luò)爬蟲項目將與S...

    Harriet666 評論0 收藏0
  • 關(guān)于Python爬蟲種類、法律、輪子一二三

    摘要:一般用進程池維護,的設(shè)為數(shù)量。多線程爬蟲多線程版本可以在單進程下進行異步采集,但線程間的切換開銷也會隨著線程數(shù)的增大而增大。異步協(xié)程爬蟲引入了異步協(xié)程語法。 Welcome to the D-age 對于網(wǎng)絡(luò)上的公開數(shù)據(jù),理論上只要由服務(wù)端發(fā)送到前端都可以由爬蟲獲取到。但是Data-age時代的到來,數(shù)據(jù)是新的黃金,毫不夸張的說,數(shù)據(jù)是未來的一切。基于統(tǒng)計學(xué)數(shù)學(xué)模型的各種人工智能的出現(xiàn)...

    lscho 評論0 收藏0

發(fā)表評論

0條評論

raoyi

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<