文/dirain 出處/部落格園
以前寫了篇“百度視頻採集"的思路簡介,看到唯一一個人留言希望我總結一下新聞採集。今天就拿部落格園的熱門文章採集做個例子。說明前我得聲明一點,經過在部落格園混了幾個月後,發現部落格園首頁發布的文章一般都是高手,很有參考價值。可我是一個新手,我請大家此文章的任何質疑直接留言,因為您發現問題不說出來,可能我永遠會認為自己寫的是正確的。
下面進入正題。首先需要注意的是採集網頁上資料的唯一方式是必須擷取需要採集頁面的原始碼,這點想必大家很清楚。因為我們不知道對方網站的資料庫伺服器串連方式,我們只能在頁面的原始碼中找尋我們想要的東西。這無疑就是對大量字串進行處理,那麼我們如何處理這些含有大量html標記與內容的代碼呢?可能解決問題的方式有很多種,但我認為用Regex來解決這個問題會很好。
通過上面的話,我談到了兩個知識點,我們來總結一下流程。
1.擷取需要採集頁面的原始碼。
2.利用Regex處理這些代碼中我們想要的內容。
下面做一些準備工作,寫一個實體類儲存文章的資訊。例如:標題、作者、發布時間、瀏覽次數,等。
文章資訊實體類
Code[copy to clipboard]
CODE:using System;
using System.Collections.Generic;
using System.Text;
namespace Plug.Article.Entity
{
/**//// <summary>
/// 採集文章資訊,部分屬性可留空。標題與地址如為空白則預設賦值時引發異常
/// </summary>
[Serializable]
public class Article
{
private string category;
/**//// <summary>
/// 文章類別
/// </summary>
public string Category
{
get { return category; }
set { category = value; }
}
private string url;
/**//// <summary>
/// 文章串連地址
/// </summary>
public string Url
{
get
{
return url;
}
set
{
if (value == "" || value.Length <= 0)
{
throw new ApplicationException("文章的串連地址不可為空!");
}
url = value;
}
}
private string title;
/**//// <summary>
/// 文章標題
/// </summary>
public string Title
{
get
{
return title;
}
set
{
if (value == "" || value.Length <= 0)
{
throw new ApplicationException("文章的標題不可為空!");
}
title = value;
}
}
private int views;
/**//// <summary>
/// 文章瀏覽次數
/// </summary>
public int Views
{
get
{
return views;
}
set
{
views = value;
}
}
private int replys;
/**//// <summary>
/// 文章評論次數
/// </summary>
public int Replys
{
get
{
return replys;
}
set
{
replys = value;
}
}
private string datatime;
/**//// <summary>
/// 文章發布日期
/// </summary>
public string Datatime
{
get
{
return datatime;
}
set
{
datatime = value;
}
}
private string author;
/**//// <summary>
/// 文章作者
/// </summary>
public string Author
{
get
{
return author;
}
set
{
author = value;
}
}
private string site;
/**//// <summary>
/// 文章作者網站、文章採集網站
/// </summary>
public string Site
{
get
{
return site;
}
set
{
site = value;
}
}
}
}
擷取採集網頁原始碼的方式,也很簡單,我單獨做成了一個類。
擷取網頁原始碼
Code[copy to clipboard]
CODE:using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
namespace Plug.Article
{
/**//// <summary>
/// 網頁操作類
/// </summary>
public class HTML
{
/**//// <summary>
/// 擷取網頁原始碼
/// </summary>
/// <param name="url">URL路徑</param>
/// <returns></returns>
public string GetHTML(string url)
{
WebClient web = new WebClient();
byte[] buffer = web.DownloadData(url);
return Encoding.Default.GetString(buffer);
}
}
}
拿到原始碼,該進入關鍵步驟了,寫Regex採集資料。在採集之前我們需要瞭解網頁原始碼的特徵,如果都不知道我們想要什麼,恐怕無法寫出Regex。我們要採集的頁面是 http://www.cnblogs.com/TopPosts.aspx 這個頁面,部落格園文章閱讀熱門排行榜。今日閱讀排行、 昨日閱讀排行 等資訊。但我們要得到的只是如下資訊:
| · 我在外資公司的2個月 (閱讀:1909) (評論:21) (2008-6-25 13:44) |
yesry |
| · 為什麼盡量避免使用觸發器? (閱讀:1490) (評論:15) (2008-6-25 03:35) |
涼麵 |
| · Discuz!NT 系統架構分析 (閱讀:1391) (評論:18) (2008-6-25 12:35) |
韓龍 |
| · 硬碟那點事兒 (閱讀:1342) (評論:15) (2008-6-25 11:16) |
李戰 |
只需要得到標題、閱讀次數、評論、時間、作者即可。那麼我們就來分析一下關鍵資訊的原始碼特徵。
Code[copy to clipboard]
CODE: <tr>
<td style="width:80%">
· <a id="ctl00_cphMain_TopPostsPaged1_PostsRepeater_ctl01_lnkTitle" href="http://www.cnblogs.com/yesry/archive/2008/06/25/1229587.html" target="_blank">我在外資公司的2個月</a> <span class="title">(閱讀:1909) (評論:21) (2008-6-25 13:44)</span>
</td>
<td height="20">
<a id="ctl00_cphMain_TopPostsPaged1_PostsRepeater_ctl01_lnkAuthor" href="http://yesry.cnblogs.com/">yesry</a>
</td>
</tr>
這就是我們需要採集資訊的原始碼。在開始寫Regex之前我需要說明一點,我們都知道,這些內容也是動態產生的。所以它們的格式肯定是固定的。這樣我們就可以利用一個Regex正確的採集到該頁面所有資訊。我覺得沒必要在這片文章中詳細解釋Regex的含義,因為這需要多練習。
Code[copy to clipboard]
CODE:Regex regexarticles = new Regex(".+· <a\\s+id=\".+\" href=\"(?<url>.+)\"\\s+target=\"_blank\">(?<title>.+)</a> <span\\s+class=\".+\">\\(閱讀:(?<views>\\d+)\\).*\\(評論:(?<reply>\\d+)\\).*\\((?<time>.+)\\)</span>\\s*</td>\\s*<td\\s+height=\"\\d+\">\\s+<a\\s+id=\".+\" href=\"(?<blog>.+)\">(?<author>.+)</a>");
這些讓您可能閱讀起來很吃力,但我想學過Regex的人會嘲笑我,因為我的正則寫的不夠靈活。我要為沒有接觸過Regex的朋友簡單介紹下,我也只是剛入門。Regex就是通過描述字串的特徵來進行匹配。這也是我們為什麼需要分析頁面原始碼的原因。至於怎麼去匹配,其實也不難,我提供一些文章給各位參考。
Regex學習筆記:http://hedong.3322.org/archives/000244.html
Regex30分鐘入門:http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm
我就是通過這兩篇文章入門,並利用Regex寫出了我喜歡的程式。至於更多的文章可以去網路尋找。
上面說到的是關鍵的Regex,下面還需要說一下怎麼去取。
採集關鍵代碼
Code[copy to clipboard]
CODE: //網頁操作對象,我用來擷取網頁源碼
HTML html = new HTML();
//對部落格園每日排行資料進行採集
string htmlcode = html.GetHTML("http://www.cnblogs.com/TopPosts.aspx","utf-8");
//提取部落格園排行文章資訊的Regex
Regex regexarticles = new Regex(".+· <a\\s+id=\".+\" href=\"(?<url>.+)\"\\s+target=\"_blank\">(?<title>.+)</a> <span\\s+class=\".+\">\\(閱讀:(?<views>\\d+)\\).*\\(評論:(?<reply>\\d+)\\).*\\((?<time>.+)\\)</span>\\s*</td>\\s*<td\\s+height=\"\\d+\">\\s+<a\\s+id=\".+\" href=\"(?<blog>.+)\">(?<author>.+)</a>");
//所有匹配運算式的內容
MatchCollection marticles = regexarticles.Matches(htmlcode);
/**////遍曆匹配內容
foreach (Match m in marticles)
{
Entity.Article test = new Entity.Article();
test.Category = "部落格園熱門文章"; //設定分類
test.Title = m.Groups["title"].Value; //設定標題
test.Url = m.Groups["url"].Value; //設定串連
test.Views = int.Parse(m.Groups["views"].Value); //設定瀏覽次數
test.Replys = int.Parse(m.Groups["reply"].Value); //設定評論次數
test.Datatime = m.Groups["time"].Value; //設定發布時間
test.Author = m.Groups["author"].Value; //設定作者
test.Site = m.Groups["blog"].Value; //設定文章出處
list.Add(test);
}
MatchCollection marticles = regexarticles.Matches(htmlcode);
通過此句代碼擷取多個匹配的內容。
Code[copy to clipboard]
CODE:foreach (Match m in marticles)
迴圈時需要用Match類取一條匹配內容,m.Groups["title"].Value 取出指定分組中的資訊,這個分組是指(?<title>.+) ,“?<title>”這就是給匹配內容分組為title的代碼。代碼就是這樣了,沒有什麼技術含量,來總結一下做採集的一個流程吧。
1.取指定頁面的原始碼
2.分析原始碼中我們想要獲得內容的特徵
3.通過特徵寫出Regex進行匹配
4.遍曆匹配內容裝入集合
流程就是這樣,我把整個案例的代碼打包供大家參考,如有什麼問題請留言。
源碼下載:
採集出的資料可能與部落格園顯示順序不太一致,因為是整個頁面的文章,沒有做分類處理。但資料絕對是一致的。