程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> JAVA爬蟲挖取CSDN博客文章

JAVA爬蟲挖取CSDN博客文章

編輯:關於JAVA

JAVA爬蟲挖取CSDN博客文章。本站提示廣大學習愛好者:(JAVA爬蟲挖取CSDN博客文章)文章只能為提供參考,不一定能成為您想要的結果。以下是JAVA爬蟲挖取CSDN博客文章正文


前言

之前寫過一篇用jsoup爬取csdn博客的文章JAVA爬蟲挖取CSDN博客文章,事先博主還在上一家公司實習,由於公司辦公網絡需求代理才干訪問外網,那一篇的代碼邏輯與代理親密相關,能夠有些不熟習jsoup怎樣運用的冤家看了會覺得越看越懵懂,且事先以為爬取一切文章需求用到分頁,能夠會誤導讀者。所以明天再次整理那個篇博客的思緒,在沒有代理的網絡的環境下完成代碼功用,假如你的也是處在代理才干訪問外網的網絡,那麼參考本文最後一段的處理方案。

思緒和步驟

還是以《第一行代碼--安卓》的作者為例,將他在csdn發表的博客信息都挖取出來,由於郭神是我在大學時期比擬崇敬的對象之一。郭神的博客地址為郭霖博客
這裡寫圖片描述

在入手實驗之前,假定你曾經根本掌握了如下的技藝:JAVA根底編程,復雜的正則表達式,JS或許jQuery的編程才能,此外還學過http協議的一些知識。假如你還未掌握正則表達式,可以去我的JAVA正則表達式詳解博客看看,假如你還沒有掌握jQuery的根底知識,可以去我的jQuery實戰專欄入手實驗一番。假如上訴技藝你都掌握了,那麼就只差一個jsoup了,這個哥們是干嘛使的呢?用一句話來描繪:這哥們能使Java順序像jQuery那樣的語法來操作html的Dom節點元素,jsoup也有像jQuery一樣的選擇器功用,比方getElementById,getElemementsByClass等語法與JavaScript像極了,此外jsoup還有select選擇器功用。所以,這裡只需略微掌握jsoup語法就可以像JS操作Dom一樣的用Java來處置懇求到的html網頁。jsoup的中文官方教程地址http://www.open-open.com/jsoup/。

工欲善其事必先利其器。開端之前,你應該有一定的工具,比方一款熟習的ide,用來調試和檢查變量。一個web調試工具,如火狐的firebug之類的。總之,就是有一個java web順序員日常開發和調試運用的工具就差不多了。

第一步:新建一個Java Se項目。這個項目假如是一個Maven項目,那麼需求添加如下的依賴配置:

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

假如這個項目不是Maven項目,那麼你需求下載jsoup-1.10.2.jar包,然後在你的項目右鍵新建一個lib目錄,把下載的jar包放出來,並把jar包添加到classpath。
這裡寫圖片描述

第二步:剖析代碼編寫思緒:先創立一個Conection鏈接,這個鏈接包括向CSDN服務器發起懇求的url地址,userAgent參數,timeOut參數曾經Http懇求類型等。接著向服務器發送get懇求Document doc = conn.get();留意:很多網絡緣由招致這一步呈現異常,比方timeOut時間設置太短也會報錯,這裡我設置為5000毫秒。假如這一步你的順序沒有報錯,闡明曾經獲取了懇求的html文檔。然後我們可以將html的body標簽外面的內容賦值給遍歷Element數據類型的實例body。處置body標簽的內容jsoup正式出場,除了jsoup還會夾雜復雜的正則內容。

用firebug可以看到。首頁與博客文章相關的內容在這個div class="list_item_new"標簽上面,而這個div上面包括3個div,辨別是:div id="article_toplist" class="list"表示置頂的文章,div id="article_list" class="list"博文列表所在的div,div id="papelist" class="pagelist"底下分頁信息所在的div。拋開置頂這個div,我們只關注文章列表的div和分頁信息div。假如你細心的剖析,那麼會發現我們關懷的每篇文章而每篇文章的標簽如下div:`

這裡寫圖片描述
每篇文章占據的div,完好的html元素如下:

<div class="list_item article_item">
        <div class="article_title">   
         <span class="ico ico_type_Original"></span>


    <h1>
        <span class="link_title"><a href="/guolin_blog/article/details/51336415">
        Android提示微技巧,你真的理解Dialog、Toast和Snackbar嗎?            
        </a></span>
    </h1>
</div>

        <div class="article_description">
Dialog和Toast一切人一定都不會生疏的,這個我們平常用的真實是太多了。而Snackbar是Design Support庫中提供的新控件,有些冤家能夠曾經用過了,有些冤家能夠還沒去理解。但是你真的知道什麼時分應該運用Dialog,什麼時分應該運用Toast,什麼時分應該運用Snackbar嗎?本篇文章中我們就來學習一下這三者運用的機遇,另外還會引見一些額定的技巧...        </div>
            <div class="article_manage">
             <span class="link_postdate">2016-07-26 07:55</span>
    
   
        <span class="link_view" title="閱讀次數"><a href="/guolin_blog/article/details/51336415" title="閱讀次數">閱讀</a>(7458)</span>
        <span class="link_comments" title="評論次數"><a href="/guolin_blog/article/details/51336415#comments" title="評論次數" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_pinglun'])">評論</a>(45)</span>

    </div>

        <div class="clear"></div>
    </div>

細心剖析一下,這個div中涵蓋了文章的簡介,閱讀次數,銜接地址等等,總之,這個div才是重頭戲要獲取的數據都在這呢。
這裡寫圖片描述

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
 * java爬取csdn博客的復雜的案例,假如你只爬取某個博主的首頁文章,那麼參考本順序員
 * 假如你想爬取某位博主的一切文章,請參考Main.java
 * @author shizongger
 * @date 2017/02/09
 */
public class Main1 {
    
    //需求停止爬獲得博客首頁
//  private static final String URL = "http://blog.csdn.net/guolin_blog";
    private static final String URL = "http://blog.csdn.net/sinyu890807/article/list/2";
    
    public static void main(String[] args) throws IOException {
        
        //獲取url地址的http鏈接Connection
        Connection conn = Jsoup.connect(URL)    //博客首頁的url地址
                .userAgent("Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.0") //http懇求的閱讀器設置
                .timeout(5000)   //http銜接時長
                .method(Connection.Method.GET);  //懇求類型是get懇求,http懇求還是post,delete等方式
        //獲取頁面的html文檔
        Document doc = conn.get();
        Element body = doc.body();
        
        //將爬取出來的文章封裝到Artcle中,並放到ArrayList外面去
        List<Article> resultList = new ArrayList<Article>();

        Element articleListDiv = body.getElementById("article_list");
        Elements articleList = articleListDiv.getElementsByClass("list_item");
        for(Element article : articleList){
            Article articleEntity = new Article();
            Element linkNode = (article.select("div h1 a")).get(0);         
            Element desptionNode = (article.getElementsByClass("article_description")).get(0);
            Element articleManageNode = (article.getElementsByClass("article_manage")).get(0);

            articleEntity.setAddress(linkNode.attr("href"));
            articleEntity.setTitle(linkNode.text());
            articleEntity.setDesption(desptionNode.text());
            articleEntity.setTime(articleManageNode.select("span:eq(0").text());

            resultList.add(articleEntity);
        }
        
        //遍歷輸入ArrayList外面的爬取到的文章
        System.out.println("文章總數:" + resultList.size());
        for(Article article : resultList) {
            System.out.println("文章相對路勁地址:http://blog.csdn.net" + article.getAddress());
        }
    }
    
}

如今可以將以後頁數的文章發掘出來了,但是郭神的技術文章不止一頁啊,還要進一步分頁發掘。以前我是想Java的分頁思緒是怎樣寫的,我們可以逆著它的分頁思緒來。但是如今覺得與它怎樣分頁有關,但是假如你理解Java分頁那麼更好的了解接上去怎樣做。

要想爬取它的一切文章,可以對他的博客每一個頁面辨別停止懇求。
首頁地址可以是:

http://blog.csdn.net/guolin_blog

也可以是:

http://blog.csdn.net/guolin_blog/article/list/1

那麼第二頁當前的url地址如下:

http://blog.csdn.net/guolin_blog/article/list/index

index表示懇求的頁數。

如今的義務就是來抓取總頁數了。來來來,我們用firebug看一看。
這裡寫圖片描述

<div id="papelist" class="pagelist">
<span> 100條  共7頁</span><a href="/sinyu890807/article/list/1">首頁</a> <a href="/sinyu890807/article/list/3">上一頁</a> <a href="/sinyu890807/article/list/1">1</a> <a href="/sinyu890807/article/list/2">2</a> <a href="/sinyu890807/article/list/3">3</a> <strong>4</strong> <a href="/sinyu890807/article/list/5">5</a> <a href="/sinyu890807/article/list/6">...</a> <a href="/sinyu890807/article/list/5">下一頁</a> <a href="/sinyu890807/article/list/7">尾頁</a> 
    </div>

可以看到總頁數位於上訴div下的第一個span標簽,僥幸的是這個div有一個無獨有偶的id號,而這個span與div的關系是父節點與子節點的關系,獲取圖中紅圈內字符串的代碼是"body.getElementById("papelist").select("span:eq(0)").text();"。而span標簽外面的內容" 100條 共7頁"是漢字,空格和數字混合組成,這時分正則表達式閃亮退場。為了選取"共x頁"外面的x的值,正則的語法關鍵代碼是:String regex = ".+共(\d+)頁";

至此,就可以將郭霖的csdn技術博客都可以獲取了。此時你只需求將失掉的信息都封裝好,在需求的時分調用就行了。
完好代碼如下:
Article.java

/**
 * 文章的JavaBean.
 * date:2017-02-09
 */
public class Article {
  
    /**
     * 文章鏈接的絕對地址
     */
    private String address;

    /**
     * 文章標題
     */
    private String title;

    /**
     * 文章簡介
     */
    private String desption;

    /**
     * 文章發表時間
     */
    private String time;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDesption() {
        return desption;
    }

    public void setDesption(String desption) {
        this.desption = desption;
    }

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }
}

Main.java

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.jsoup.*;
import org.jsoup.nodes.*;
import org.jsoup.select.*;

import com.shizongger.javaspider.Article;

/**
 * @author shizongger
 * @date 2017/02/09
 */
public class Main {
    
    private static final String URL = "http://blog.csdn.net/guolin_blog";

    public static void main(String[] args) throws IOException {
        Connection conn = Jsoup.connect(URL)
                .userAgent("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0")
                .timeout(5000)
                .method(Connection.Method.GET);
        Document doc = conn.get();
        Element body = doc.body();

        //獲取總頁數
        String totalPageStr = body.getElementById("papelist").select("span:eq(0)").text();
        String regex = ".+共(\\d+)頁";
        totalPageStr = totalPageStr.replaceAll(regex, "$1");
        int totalPage = Integer.parseInt(totalPageStr);
        int pageNow = 1;

        List<Article> articleList = new ArrayList<Article>();
        for(pageNow = 1; pageNow <= totalPage; pageNow++){
            articleList.addAll(getArtitcleByPage(pageNow));
        }
        
        //遍歷輸入博主一切的文章
        for(Article article : articleList) {
            System.out.println("文章標題:" + article.getTitle());
            System.out.println("文章相對路勁地址:http://blog.csdn.net" + article.getAddress());
            System.out.println("文章簡介:" + article.getDesption());
            System.out.println("發表時間:" + article.getTime());
        }
    }

    public static List<Article> getArtitcleByPage(int pageNow) throws IOException{

        Connection conn = Jsoup.connect(URL + "/article/list/" + pageNow)
                .userAgent("Mozilla/5.0 (Windows NT 6.1; rv:47.0) Gecko/20100101 Firefox/47.")
                .timeout(5000)
                .method(Connection.Method.GET);
        Document doc = conn.get();
        Element body = doc.body();
        List<Article> resultList = new ArrayList<Article>();

        Element articleListDiv = body.getElementById("article_list");
        Elements articleList = articleListDiv.getElementsByClass("list_item");
        for(Element article : articleList){
            Article articleEntity = new Article();
            Element linkNode = (article.select("div h1 a")).get(0);         
            Element desptionNode = (article.getElementsByClass("article_description")).get(0);
            Element articleManageNode = (article.getElementsByClass("article_manage")).get(0);

            articleEntity.setAddress(linkNode.attr("href"));
            articleEntity.setTitle(linkNode.text());
            articleEntity.setDesption(desptionNode.text());
            articleEntity.setTime(articleManageNode.select("span:eq(0").text());

            resultList.add(articleEntity);
        }
        return resultList;
    }
}
兩個留意之處
  1. Conection的timeOut不宜過短。假如把timeOut設置為20毫秒,則會報錯。
    Exception in thread "main" java.net.SocketTimeoutException: connect timed out
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
    at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
    at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
    at java.net.Socket.connect(Socket.java:589)
    at sun.net.NetworkClient.doConnect(NetworkClient.java:175)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
    at sun.net.www.http.HttpClient.openServer(HttpClient.java:527)
    at sun.net.www.http.HttpClient.

2.當你處於內網時,需求代理才干發送http懇求,在Jsoup.connect(URL)之前,你必需設置代理。

        System.setProperty("http.maxRedirects", "50");
        System.getProperties().setProperty("proxySet", "true");
        String ip = "代理服務器地址";
        System.getProperties().setProperty("http.proxyHost", ip);
        System.getProperties().setProperty("http.proxyPort", "代理的端口");

本文可運轉案例托管在免積分下載地址,本文目的用於技術交流,望與天下Coder共勉!


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved