程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> ASP.NET >> 關於ASP.NET >> 一次批量修改博客文章的經驗(下):操作過程

一次批量修改博客文章的經驗(下):操作過程

編輯:關於ASP.NET

獲取所有文章ID

首先,我們便要下載所有文章了,這又該怎麼做呢?雖然MetaWeblog API提供了 getRecentPosts方法用來獲取最近的文章,但是這個接口卻並不好用。例如,它只能用來 獲取最新的幾篇文章內容,但對我來說,我想修改的其實是很久之前的文章。那麼,難道 要我下載全部500多篇文章才行嗎?後來我統計了一下,所有文章大小存成文本文件大約 有10M,一個請求下載 10M內容還是有些誇張的——而且還看不到進度。因此,我最後打 算“曲線救國”,先著手獲得所有公開文章的ID,再通過getPost接口獲得文章內容。

MetaWeblog API並不提供獲取所有文章ID的接口,但這並不影響我們從網頁上直接進 行抓取。我們從博客園提供的“月份匯總”頁面入手,即這樣的一張頁面。博客園的月份 匯總的URL非常有規律,獲得它的HTML內容之後即可使用正則表達式來捕獲文章ID了。您 可能會想,一篇文章可能會取別名(這樣URL上就不顯示ID了),而網頁上各種URL也很多 ,有什麼辦法可以准確而方便地分析出文章ID嗎?其實這個問題很簡單,因為博客園為每 篇文章都放置了一個“編輯”鏈接,它的URL是.../EditPosts.aspx?postid=1633416,對 我們來說再方便不過了。

於是下載和捕獲文章ID的方法可謂手到擒來:

type WebClient with

   member c.GetStringAsync(url) =
     async {
       let completeEvent = c.DownloadStringCompleted 
       do c.DownloadStringAsync(new Uri(url))
       let! args = Async.AwaitEvent(completeEvent)
       return args.Result
     }

let downloadPostIdsAsync (beginMonth : DateTime) (endMonth :  DateTime) =

   let downloadPostIdsAsync' (m : DateTime) =
     async {
       let webClient = new WebClient()
       let url = sprintf  "http://www.cnblogs.com/JeffreyZhao/archive/%i/%i.html" m.Year  m.Month

       let! html = webClient.GetStringAsync(url)

       let regex = @"EditPosts\.aspx\?postid=(\d+)"
       return [ for m in Regex.Matches(html, regex) ->  m.Groups.Item(1).Value |> Int32.Parse ]
     }

   async {
     let! lists =
       Seq.initInfinite (fun i -> beginMonth.AddMonths(i))
       |> Seq.takeWhile (fun m -> m <= endMonth)
       |> Seq.map downloadPostIdsAsync'
       |> Async.Parallel

     lists
     |> List.concat
     |> List.sort
     |> List.map (fun i -> i.ToString())
     |> fun lines -> File.WriteAllLines("postIds.txt",  lines)
   }

下載文章ID的任務由downloadPostIdsAsync函數完成,它接受beginMonth和endMonth 兩個DateTime參數來表示月份的區間,我們將從中獲取所有的文章ID。 downloadPostIdsAsync函數會生成一個異步工作流,執行這個工作流便會將所有的文章 ID進行排序,並保存至postIds.txt文件中去,一行一個。獲取單月的文章ID由內部的 downloadPostIdsAsync'這個輔助函數負責,它會構造出下載單個月份文章ID的異步工作 流,再由外部函數合並而成——換句話說,所有月份的文章將同時進行異步下載,提高效 率。

我們可以在main方法中執行downloadPostIdsAsync函數,這樣postIds.txt文件中便會 出現所有的文章ID了:

System.Net.ServicePointManager.DefaultConnectionLimit <-  10

Blogging.downloadPostIdsAsync (new DateTime(2006, 9, 1)) (new  DateTime(2008, 12, 1))
|> Async.RunSynchronously

由於WebClient基於WebRequest對象實現,而WebRequest受到ServicePointManager控 制,因此我們要設置其DefaultConnectionLimit屬性來打開對單個域名的限制——並控制 對並發連接的數量進行限制,以免對服務器產生太大壓力(當然我們其實工作量本不大, 且博客園也不會那麼脆弱)。當然,這個限制也可以通過配置進行更改。

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