1. 程式人生 > >jsoup爬蟲技術及爬取微博資料例項

jsoup爬蟲技術及爬取微博資料例項

  最近實現了一個爬取微博資料的小程式,藉此對爬蟲技術 jsoup的使用,以及實際開發過程中的細節進行總結。

  首先,對於網路爬蟲的理解,它是一種能夠自動下載網頁、解析網頁的程式。網路中的資訊分散在數以億計的網頁中,而這些網頁中的資料儲存於數以百萬計的伺服器中。現實中的使用者只需通過在瀏覽器中訪問超連結便可以獲取資訊。爬蟲便可以通過模擬瀏覽器的方式,將多個超連結對應的網頁資訊收集起來。而Jsoup要做的,就是幫我們完成這樣一個程式。它是一個 Java 的開源HTML解析器,可直接解析某個URL地址,它提供了一套非常省力的 API,可通過 DOM,CSS 以及類似於 jQuery 的操作方法來取出和操作資料。它可以幫我們完成:

1. 從一個URL,檔案或字串中解析HTML  2. 使用DOM或CSS選擇器來查詢、取出資料  3. 對HTML元素、屬性、文字進行操作  4. 清除不受信任的HTML (來防止XSS攻擊)

 jsoup 可以從包括字串、URL 地址以及本地檔案來載入 HTML 文件,並生成 Document 物件例項。下面貼出程式碼對幾種方式進行解析:

// 從 URL中載入 HTML 文件
	String url = "https://s.weibo.com/";
	Document doc = Jsoup.connect(url).get();

	// 從字串中輸入 HTML 文件
	String html = "<html><head><title>MyPaper</title></head>" + "<body><p>這是一個頁面</p></body></html>";
	Document doc = Jsoup.parse(html);

	// 從檔案中載入 HTML 文件
	File input = new File("MyPage.html");try
	{
		Document doc3 = Jsoup.parse(input, "UTF-8", "https://s.weibo.com/");

	}catch(
	IOException e)
	{

		e.printStackTrace();
	}
    

而對於解析出來的Document物件,Element物件則提供了一系列類似於DOM的方法來查詢元素,抽取並處理其中的元素:

//通過標籤裡的id,tag,className等進行查詢:
    getElementById(String id)

    getElementsByTag(String tag)

    getElementsByClass(String className)

    getElementsByAttribute(String key) (and related methods)

    Element siblings: siblingElements(), firstElementSibling(), lastElementSibling(); nextElementSibling(), previousElementSibling()

    Graph: parent(), children(), child(int index)

    
    //定位後對所在標籤和元素進行操作
    attr(String key) :獲取屬性
    attr(String key, String value) :設定屬性
    attributes() :獲取所有屬性
    text() : 獲取文字內容
    text(String value) : 設定文字內容
    html() : 獲取元素內HTML
    html(String value) : 設定元素內的HTML內容
    outerHtml() : 獲取元素外HTML內容
    data() : 獲取資料內容

下面用一個爬取微博資料的例項進行講解:

需求 :從資料來源介面如下所示:http://www.weibo.com 爬取:

 微博(微博ID,微博暱稱,微博內容,釋出時間,釋出平臺,轉發數,評論數,點贊數)

首先分析需要爬取的目標網頁的url地址:

因此從url中進行載入的語句可寫為:

				String word = "雙一流";
				String url = "https://s.weibo.com/weibo?q=" + word + "&Refer=index&page=" + i;
				Document doc = Jsoup.connect(url).userAgent("ie7:mozilla/4.0 (compatible; msie 7.0b; windows nt 6.0)")// 模擬瀏覽器訪問
						.timeout(3000)// 設定超時
						.get();

下面對網頁進行分析,為下一步使用Element物件抽取處理元素做準備:

可以注意到每一個微博動態塊位於一個 action-type=feed_list_item 的div塊中,但每篇熱門文章也位於action-type=feed_list_item 的div塊中,這是我們需要進行過濾的,對於解析出來的Document物件,Element物件則提供了一系列類似於DOM的方法來查詢元素,抽取並處理其中的元素,下面是選取的其中一個 動態塊原始碼 :

<!--card-wrap-->
<div class="card-wrap" action-type="feed_list_item" mid="4295851763028004" >
        <div class="card-top">
        <div class="card-top">
                                                                <h4 class="title"><i class="icon-title icon-star"></i><a href="/weibo?q=%E5%8F%8C%E4%B8%80%E6%B5%81&xsort=hot&Refer=hotmore" target="_blank" suda-data="key=tblog_search_weibo&value=seqid:15397465809059866363|type:1|t:0|pos:1-0|q:%E5%8F%8C%E4%B8%80%E6%B5%81|ext:cate:26,click:more">熱門</a></h4>
                    </div>
    </div>
        <div class="card">
        <div class="card-feed">
            <div class="avator">
                <a href="//weibo.com/1734530730?refer_flag=1001030103_" target="_blank" suda-data="key=tblog_search_weibo&value=seqid:15397465809059866363|type:1|t:0|pos:1-0|q:%E5%8F%8C%E4%B8%80%E6%B5%81|ext:cate:26,mpos:1,click:user_pic"><img src="//tvax2.sinaimg.cn/crop.0.0.996.996.50/6762d6aaly8fuuyo3xbt5j20ro0ro74w.jpg" /></a>
            </div>
            <!--微博內容-->
            <div class="content" node-type="like">
                <div class="info">
                    <div class="menu s-fr">
                        <a href="javascript:void(0);" action-type="fl_menu"><i class="wbicon">c</i></a>
                        <ul node-type="fl_menu_right" style="display:none;">
                            <li><a href="javascript:void(0);" onclick="javascript:window.open('//service.account.weibo.com/reportspam?rid=4295851763028004&amp;type=1&amp;from=10501&amp;url=&amp;bottomnav=1&amp;wvr=6', 'newwindow', 'height=700, width=550, toolbar =yes, menubar=no, scrollbars=yes, resizable=yes, location=no, status=no');">舉報</a></li>
                                                    </ul>
                    </div>
                    <div>
                        <a href="//weibo.com/1734530730?refer_flag=1001030103_" class="name" target="_blank" nick-name="大河報" suda-data="key=tblog_search_weibo&value=seqid:15397465809059866363|type:1|t:0|pos:1-0|q:%E5%8F%8C%E4%B8%80%E6%B5%81|ext:cate:26,mpos:1,click:user_name">大河報</a>
                        <a href="//verified.weibo.com/verify" target="_blank"  title="微博官方認證"><i class="icon-vip icon-vip-b"></i></a>
                        <!--廣告微博加關注按鈕 -->
                                            </div>
                </div>
                <p class="txt" node-type="feed_list_content" nick-name="大河報">
                    【大手筆!河南省財政廳2018年度安排“<em class="s-color-red">雙</em><em class="s-color-red">一流</em>”建設資金7.7億】建設世界<em class="s-color-red">一流</em>大學、<em class="s-color-red">一流</em>學科,簡稱&quot;<em class="s-color-red">雙</em><em class="s-color-red">一流</em>&quot;。河南省建設情況如何?16日,河南省人大召開專題會議,聽取河南省&quot;<em class="s-color-red">雙</em><em class="s-color-red">一流</em>&quot;建設情況。記者從會場瞭解到,鄭州大學、河南大學<em class="s-color-red">雙</em><em class="s-color-red">雙</em>進入&quot;<em class="s-color-red">雙</em><em class="s-color-red">一流</em>&quot;建設高校行列,省財政廳2018年度安排&quot;<em class="s-color-red">雙</em><em class="s-color-red">一流</em>&quot;建設資金 ​  <a href="//weibo.com/1734530730/GEdxCcHIM?refer_flag=1001030103_" action-type="fl_unfold" target="_blank">展開全文<i class="wbicon">c</i></a>                </p>
                                <p class="txt" node-type="feed_list_content_full" nick-name="大河報" style="display: none">
                    【大手筆!河南省財政廳2018年度安排“<em class="s-color-red">雙</em><em class="s-color-red">一流</em>”建設資金7.7億】建設世界<em class="s-color-red">一流</em>大學、<em class="s-color-red">一流</em>學科,簡稱&quot;<em class="s-color-red">雙</em><em class="s-color-red">一流</em>&quot;。河南省建設情況如何?16日,河南省人大召開專題會議,聽取河南省&quot;<em class="s-color-red">雙</em><em class="s-color-red">一流</em>&quot;建設情況。記者從會場瞭解到,鄭州大學、河南大學<em class="s-color-red">雙</em><em class="s-color-red">雙</em>進入&quot;<em class="s-color-red">雙</em><em class="s-color-red">一流</em>&quot;建設高校行列,省財政廳2018年度安排&quot;<em class="s-color-red">雙</em><em class="s-color-red">一流</em>&quot;建設資金7.7億元。<a href="http://t.cn/EzPKTgk"  target="_blank"><i class="wbicon">O</i>大手筆!河南省財政廳2018年度安排“<em class="s-color-red">雙</em><em class="s-color-red">一流</em>”建設資金7.7億</a> <a href="javascript:void(0);" action-type="fl_fold">收起全文<i class="wbicon">d</i></a>
                </p>
                                                <!--card解析-->
<div node-type="feed_list_media_prev">
    <div class="media media-piclist" node-type="fl_pic_list" action-data="uid=1734530730&mid=4295851763028004&pic_ids=6762d6aaly1fwaco8ljn5j20dw0990t1">
                <ul class="m3">
                                <li><img src="//ww1.sinaimg.cn/thumb150/6762d6aaly1fwaco8ljn5j20dw0990t1.jpg" action-data="uid=1734530730&pic_id=6762d6aaly1fwaco8ljn5j20dw0990t1" action-type="fl_pics" suda-data="key=tblog_search_weibo&value=weibo_ss_1_pic"></li>
                    </ul>
    </div>
</div>
<div node-type="feed_list_media_disp">
</div>


<!--/card解析-->
                                <p class="from" >
                                            <a href="//weibo.com/1734530730/GEdxCcHIM?refer_flag=1001030103_" target="_blank" suda-data="key=tblog_search_weibo&value=seqid:15397465809059866363|type:1|t:0|pos:1-0|q:%E5%8F%8C%E4%B8%80%E6%B5%81|ext:cate:26,mpos:1,click:wb_time">
                        10月16日 20:52
                        </a>
                                         來自 <a href="http://app.weibo.com/t/feed/1sxHP2" rel="nofollow">專業版微博</a>                </p>
            </div>
            <!--/微博內容-->
        </div>
        <div class="card-act">
            <ul>
                <li><a href="javascript:void(0);" action-type="login" suda-data="key=tblog_search_weibo&value=seqid:15397465809059866363|type:1|t:0|pos:1-0|q:%E5%8F%8C%E4%B8%80%E6%B5%81|ext:cate:26,mpos:1,click:fav">收藏</a></li>
                                <li><a href="javascript:void(0);" action-data="allowForward=1&mid=4295851763028004&name=大河報&uid=1734530730" action-type="login" suda-data="key=tblog_search_weibo&value=seqid:15397465809059866363|type:1|t:0|pos:1-0|q:%E5%8F%8C%E4%B8%80%E6%B5%81|ext:cate:26,mpos:1,click:repost">轉發 19</a></li>
                                <li><a href="javascript:void(0);" action-data="pageid=weibo&amp;suda-data=key%3Dtblog_search_weibo%26value%3Dweibo_h_1_p_p" suda-data="key=tblog_search_weibo&value=seqid:15397465809059866363|type:1|t:0|pos:1-0|q:%E5%8F%8C%E4%B8%80%E6%B5%81|ext:cate:26,mpos:1,click:comment" action-type="login">評論 46</a></li>
                <li><a title="贊" action-data="mid=4295851763028004" action-type="login" href="javascript:void(0);" suda-data="key=tblog_search_weibo&value=seqid:15397465809059866363|type:1|t:0|pos:1-0|q:%E5%8F%8C%E4%B8%80%E6%B5%81|ext:cate:26,mpos:1,click:like"><i class="icon-act icon-act-praise"></i> <em>29</em></a></li>
            </ul>
        </div>
        <div node-type="feed_list_repeat"></div>
            </div>
</div>
<!--/card-wrap-->

這裡以微博ID為例,進行分析,微博ID位於class="name"的a標籤中的href中,通過getElementsByClass("name").attr("href")獲取到href後,還需使用正則表示式獲取到十位數字的微博ID:

//<a href="//weibo.com/1734530730?refer_flag=1001030103_" class="name" target="_blank" nick-name="大河報" suda-data="key=tblog_search_weibo&value=seqid:15397465809059866363|type:1|t:0|pos:1-0|q:%E5%8F%8C%E4%B8%80%E6%B5%81|ext:cate:26,mpos:1,click:user_name">大河報</a>
String Href = link.getElementsByClass("name").attr("href");
String pattern = "/(\\d{10})";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(Href);
String Id;

if (m.find()) {
    Id = m.group(1);
} else {
    Id = "";
     }

下面是其他目標元素的獲取,以及置於exce中進行展示:

int k = 1;
Element content = doc.getElementById("pl_feedlist_index");
Elements links = content.getElementsByAttributeValue("action-type", "feed_list_item");
for (Element link : links) {
    try {
    	//此處結合下面catch中的  continue; 實現對“熱門文章”(和動態塊裡的標籤種類不同,會執行catch中的程式碼)過濾;
        String id_href = link.getElementsByClass("name").first().attr("href");
        String pattern = "/(\\d{10})";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(id_href);
        String Id;
        
        if (m.find()) {
            Id = m.group(1);
        } else {
            Id = "";
             }
        
       
        String Name = link.getElementsByClass("name").text();
        String Content = link.getElementsByClass("txt").text();
        String Time = link.getElementsByClass("from").first().getElementsByAttributeValue("target", "_blank").text();
        String PlatForm = link.getElementsByClass("from").first().getElementsByAttributeValue("rel", "nofollow").text();
        String Forward = link.getElementsByClass("card-act").first().getElementsByTag("li").get(1).text();
        String Comment = link.getElementsByClass("card-act").first().getElementsByTag("li").get(2).text();
        String Like = link.getElementsByClass("card-act").first().getElementsByTag("li").get(3).text();
       
        //填入excel中進行展示
    	row = sheet.createRow(k);
        row.createCell(0).setCellValue(Id);
    	row.createCell(1).setCellValue(Name);
    	row.createCell(2).setCellValue(Content); 	
    	row.createCell(3).setCellValue(Time);
    	row.createCell(4).setCellValue(PlatForm);
    	row.createCell(5).setCellValue(Forward);
    	row.createCell(6).setCellValue(Comment);
    	row.createCell(7).setCellValue(Like);                 
        k++;

    } catch (NullPointerException e) {
        continue;
    }
}

至此,微博資料的爬取完成!