正則表達式在遠程網頁下載中的應用

摘  要:分析了遠程網頁的結構特徵,闡述了正則表達式在網頁下載中的應用,提出了運用正則表達式匹配替換多餘HTML源文件和直接在HTML源文件中匹配提取元數據的兩種獲取遠程數據的方法,同時完成了數據解析、提取及保存的整個過程,並將文章所附有的附件、圖片及音頻等文件下載到本地服務器。  
關鍵詞: 正則表達式;元數據;字符串處理;匹配替換  
1 引言  
    目前,博客作爲一種新型的交流平臺,已廣泛地應用於互聯網中,然而,由於博客平臺本身的特點,其數據大多爲非線性,不便於轉化爲XML或PDF格式的文檔,也給數據的擴充及存取帶來了極大的不便。爲了解決這種非線性數據自動轉換爲線性數據的問題。本文以敏思博客平臺的教研創羣組  http://jycbl.group.blogms.com/ )爲例,採用正則表達式自動識別、解析遠程網頁數據的方法,專門開發了一個的博客網頁下載軟件。軟件不但可以把博客文章的標題、作者、內容及評論等文字提取出來,而且還可以利用C#強大的文件處理功能,將文章所附有的附件、圖片及音頻等文件下載到本地服務器。  
2 正則表達式  
    正則表達式由美國數學家Stephen Kleene於1956年提出,主要用於描述正則集代數。現在,正則表達式標準已經成爲ISO(國際標準化組織)的國際標準,已經被廣泛地應用於字符格式匹配等信息技術領域。  
    正則表達式提供了一種從字符集合中搜尋特定字符串的機制[1]。它是由普通字符(例如字符a到z)以及特殊字符(稱爲元字符)組成的文字模式。該模式描述在查找文字主體時待匹配的一個或多個字符串。按照實現的功能集合分爲兩種:基本的正則表達式(BRE)和擴展的正則表達式(ERE)[2]。正則表達式已經超出了某種語言或某個系統的侷限,成爲人們廣爲接受的概念和功能。許多程序中都使用了正則表達式,如xsh、vi等UNIX平臺下的程序。正則表達式還被很多其他規範所採納,如HTML和XML。支持正則表達式的語言也很多,比如PHP 、C# 、JavaScript、VBScript、Perl等。  
    正則表達式最基本的三種功能是:匹配、替換和提取。使用匹配功能,可以把用特殊字符串表達的匹配模式與數據文件、程序輸入或者WEB頁面的表單輸入等目標對象進行比較,根據比較結果,執行相應的程序。替換文本功能,用於在文檔中使用匹配模式來標識特定文字,然後將其刪除或進行替換。提取子符串功能,用於根據模式匹配,從字符串中提取一個子字符串。  
3 遠程網頁的特徵以及結構分析  
    在應用正則表達式提取數據之前,必須對網頁的結構進行詳細的分析,根據網頁的結構特徵來構造最合適的正則表達式。下面列出要處理的遠程網頁的一部分源文件:  

   


    以上是一段描述一篇文章的標題、作者、發表日期、點擊次數及回覆次數的源文件,它是一種半結構化的格式[3],各元素之間用“<”和“>”分割開,現在所要做的就是將該文章的標題、作者及點擊次數等信息從該源文件中提取出來。根據源文件的特徵,通過觀察判斷,可以看出除了發表日期以外,其他所需要的信息如標題、作者、點擊次數及回覆次數都屬於“<”和“>”之外的內容,故在提取這些信息時,只需要將“<”和“>”之內的源文件去除,剩下的就是所需要的信息。如對以上那段源文件,可以先利用網頁裏文章列表的開始標誌“<!--Begin FCS: Blog.stdsub.TagGroupLog -->”和結束標誌“<!-- End FCS:Blog.stdsub. TagCBlogLog Page -->”,進一步縮小信息提取的範圍,然後構造正則表達式將多餘的源文件去除,最後就可以得到以下的元數據:  
    文章標題:計算機族的眼睛保養  
    文章作者:葉子  
    點擊次數及回覆次數:12/2            
    對於文章的發表日期,元數據不在“<”和“>”之間而是做爲單元格“title”屬性一部分內容時,必須運用另一種提取方法,也就是構造正則表達式將匹配的數據直接提取出來,但運用正則表達式時,要儘可能的縮小源文件的範圍,以提高正則表達式的匹配效率。  
4  正則表達式在遠程網頁下載中的應用  
    軟件使用C#語言,運用Microsoft公司提供的SQL Server 2000作爲數據庫,第三方提供的正則表達式完成開發。提取元數據時,一般有兩種提取方法:一種是將匹配的數據去除,剩下有用的數據;另一種就是將匹配的數據直接提取出來。  
    Microsoft的.Net Framework類庫提供了System.Text.Regu larEx pressions命名空間,作爲正則表達式的編程接口,它提供了Regex類、Match類及Group類等。  
    Regex類包含了正則表達式,以及使用正則表達式的各種方法。Regex類不僅可以用來創建正則表達式,還可以操作文本數據。例如:搜索字符模式或進行復雜的查找和替換。若要把正則表達式利用於不同的字符串,就可以創建一個Regex對象,其主要方法有IsMatch()方法、Replace()方法、Split()方法等。Replace()方法用指定的字符串代替一個匹配模式,Split()方法在每次發現匹配的位置分拆字符串,返回一個字符數組。Match類表示單個正則表達式匹配的結果。Group類表示單個捕獲組的結果。  
    正則表達式主要有四類字符:首先是匹配字符,包含了需要搜索匹配的對象。例如,“.”號匹配任一字符,“[]”號匹配方括弧之間的任一字符,“[^]”號匹配不在方括弧之間的任一字符。其次是重複操作符,描述了查找一個特定字符的次數。例如,“?”號匹配某一部分一次,“*” 號匹配某一部分多次,“+”號匹配某一部分一次或多次,“[a]+”匹配一個或多個“a”字符,還有“{n}”,“{n,m}”等符號。第三種是錨,它指定了所要匹配的格式,有“^”、“$”、“/>”、“/<”、“b”等,當然還會有一些保留字符,需要用反斜槓來替換它們,比如“/”號,是個保留字符,如果要在表達式裏表示這個特定的字符,就得用“// ”這種形式。  
4.1 運用正則表達式去除多餘的源文件獲取元數據  
    針對以上那段源文件,在提取文章標題、作者、點擊次數及回覆次數時使用正則表達式去除多餘源文件的形式來提取數據。具體的提取過程以下:  
    第一步,構造正則表達式,去除多餘的源文件。  
Regex R = new Regex(@"<[^>]*",RegexOptions.Ignore Case);  
string RText = R.Replace(NewText,"$").Replace(">","");  
“<[^>]*”表示匹配“<”與“>”之間的所有內容。“NewText”是待處理的字符串,R.Replace(NewText,"$")就是表示將所匹配的內容替換成“$”。  
    第二步,構造正則表達式,清除所有包括空格、製表符、換頁符等空白字符。  
Regex R1 = new Regex(@"[/s]*",RegexOptions.Ignore Case);  
string R1Text = R1.Replace(RText,"");  
    第三步,構造正則表達式,將多個“$”替換成一個“$”,並清除頭尾的“$”及源文件中的“$ ”,最後得到以“$”爲分隔符的字符串,如“計算機族的眼睛保養$葉子$12/2”。   
Regex RR = new Regex("[$]+",RegexOptions.IgnoreCase);  
string RRText = RR.Replace(R1Text,"$").TrimStart($). TrimEnd($).Replace("$ ","");  
4.2 運用正則表達式從源文件中直接提取元數據  
    在運用正則表達式提取元數據之前,首先構造一個執行正則表達式提取元數據的函數GetUrlByReg(string InputStr,string RegStr,int GroupInt),此函數有三個參數,第一個爲待處理的字符串,第二個是根據要篩選的字符串構造的正則表達式,第三個是指定返回的字符串數組匹配項的位置。函數算法思路是先用指定的正則表達式初始化一個Regex類的實例,再用Regex實例的Match()方法返回指定的字符串匹配的結果,同時這裏初始化一個StringBuilder的實例,並將返回的字符串追加到該實例中,然後賦給字符串變量ReValue返回,具體如下:  
private string GetUrlByReg(string InputStr,string RegStr,int GroupInt)  
           {  
      //用修改模式的選項爲指定的正則表達式初始化並編譯 Regex 類的實例  
           Regex r = new Regex(RegStr,RegexOptions. Ignore Case);  
           //在指定的輸入字符串中搜索Regex構造函數中指定的正則表達式匹配項  
           Match m = r.Match(InputStr);  
           //初始化一個StringBuilder實例,並將此實例的字符串值設置爲 String.Empty  
           StringBuilder SB = new StringBuilder();  
           while(m.Success)  
{  
                             SB.Append(m.Groups[GroupInt].ToString());   
SB.Append("$");  //在每一個匹配項後追加一個“$”  
m = m.NextMatch();  
}  
string ReValue = SB.ToString();  //將實例字符串賦給ReValue  
SB.Remove(0,SB.ToString().Length);   
return ReValue;  
}  
    藉助這個自定義函數,就可以構造一些正則表達式來提取所需要的元數據。如對於上面所附的那一段源文件中文章發表日期的獲取就可以採用這種方式,應用如下:  
string TextTime = GetUrlByReg(NewText,@"(發表日期:)+(/d+(年)/d+(月)/d+(日)/s/d+(:)/d+)",2).TrimEnd($);  
    “NewText”爲待提取的字符串,也就是以上所附的那一段源文件,第二個參數就是根據日期格式構造的正則表達式,“/d+”匹配一個或多個數字字符如“2006”,“/s”表示匹配一個空白字符,這樣類似“2006年6月21日 7:35”的日期格式都可以被匹配。在本軟件中,這方面應用的例子還有很多,如提取每個欄目訪問地址、欄目名稱、欄目ID號、內容中附有的圖片名稱等。以下爲返回圖片名稱的一條正則表達式:  
    string img = GetUrlByReg(TextContent,@"(IMG SRC= /"")+([.]*(([//](/w+))*([.])(jpg|gif|bmp)))",2).Trim End($). TrimStart(.);//返回內容中圖片名稱  
仔細分析以上的正則表達式就知道,該正則表達式共有三個匹配項,第一個是“(IMG SRC=/"")”,其中這是一個固定的字符串匹配,匹配一個“IMG SRC="”的字符串,第二個是“[.]*”,意思是可以匹配零個或多個“.”號,第三個是“(([//](/w+))*([.])(jpg|gif|bmp))”,這個正則表達式前半部分“([//](/w+))*”表示匹配多組一個“/”加一個或多個單詞的字符串,如“/abc/efg/picname”,後半部分“([.])(jpg|gif|bmp)”表示匹配一個“.”號加圖片文件擴展名。通過分析知道,整個表達式可以匹配如“IMG SRC="../blogpath/03/ 1000353733.jpg"”類似的字符串。獲取到圖片的相對路徑後,就可以利用C#的WebClient類的DownloadFile()方法將遠程服務器上的數據下載到本地服務器。  
4.3 正則表達式的設計誤區及思路  
    正則表達式的設計誤區主要有以下幾種。一是不能準確匹配。在設計匹配模式時,應充分明確各類字符的匹配意義,掌握常用的匹配技巧。例如“/S”表示匹配任何非空白字符,“/d”匹配一個數字字符,“/s”表示匹配任何空白字符等。二是思路不明確,碰到複雜的源文件無從下手。對於複雜的源文件,應該先尋找匹配的規律,化簡後分而治之。例如上文提到的圖片相對路徑的匹配,可以先把路徑源文件分爲三個部分,分別設計三種匹配模式,然後再連接起來。三是文檔範圍過大,匹配效率低。正則表達式在匹配文檔時是運用匹配模式與源文件逐一比較才得出匹配結果,效率相對較低,因此,在不影響匹配結果的情況下,儘可能的縮短被處理字符串的範圍。另外,在對遠程數據進行匹配時,最好在調試階段先把數據下載到本機調試,這樣開發的速度會快很多。構造匹配的正則表達式,也就是根據文檔的結構特徵,將相同或類似的信息歸類,再用一系列的字符集抽象表示文檔的過程。每一個正則表達式的構造都與所被處理的源文件的結構分不開的,所以在構造正則表達式之前,都必須對網頁的結構特徵進行詳細的分析,找出規律,排除干擾,才能設計出最理想的正則表達式。   
4.4 數據庫處理  
    數據庫共有三個表,分別是羣組基本信息表、文章相關信息表和評論表。羣組基本信息表主要是保存羣組欄目ID、欄目名稱、羣組名稱和羣組地址,文章相關信息表主要保存文章主題、內容、作者、發表時間、點擊次數及評論次數等,評論表主要保存文章ID、評論主題、評論內容、Email、網址及評論人等。  
5 結束語  
    目前,這個軟件已經下載了教研創羣組7千多篇文章,3萬多條文章評論,數據下載率在98%以上。一小部分文章未能下載是主要因爲網頁模板有所變化,或者網絡中斷,或者內容中含有特殊字符導致數據保存失敗等原因造成的。  
    一個理想的匹配模式的設計,需要反覆的實踐,而且它要求與被處理網頁的結構比較穩定、有規可循[4]。因此,該方法也有它的侷限性,如智能化程序不夠高,可移植性不夠好等,但是,由於正則表達式強大的解析、匹配能力,以及得到越來越多的語言的支持,所以在今後的應用中,仍會有很廣闊的前景。 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章