原創|其它|編輯:郝浩|2009-07-30 10:09:37.000|閱讀 2525 次
概述:需求分析:本人最近做一個項目,項目中需要從新聞的索引頁(就是上面有很多鏈接的那種網頁),獲取新聞正文頁源碼,并將新聞正文頁源碼保存到本地數據庫中。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
需求分析:本人最近做一個項目,項目中需要從新聞的索引頁(就是上面有很多鏈接的那種網頁),獲取新聞正文頁源碼,并將新聞正文頁源碼保存到本地數據庫中。
但是由于網絡穩定性的原因,總會出現 404 page not found 類型的error。(但是網頁是確確實實存在的)。而且這種錯誤,往往是在程序運行一段時間后出現的,覺得很不可思議。我在網絡上查這種問題的解決方案時,發現沒有一種管用的。本人現在已經成功解決該問題,遂將自己的解決方案寫下來和大家分享與探討。
解決方案核心:一旦出現這種錯誤,程序中就遞歸調用下載函數本身。代碼說明如下:
public static string GetDataFromUrl(string url, int nRetryTimes)
{
if (nRetryTimes == 0)
return string.Empty;
string result = string.Empty;
try
{
result=GetDataFromUrl(url);
}
catch (System.Exception exc)
{
if(exc.Message.IndexOf("404")!=-1)
{
result=GetDataFromUrl(url,nRetryTimes-1);
}
}
return result;
}
其中nRetryTimes 代表出現這種錯誤后,函數遞歸調用自己的次數,也可以理解為遞歸終止的條件。GetDataFromUrl(string url)函數代碼如下:
public static string GetDataFromUrl(string url)
{
string str = string.Empty;
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
//設置http頭
request.AllowAutoRedirect = true;
request.AllowWriteStreamBuffering = true;
request.Referer = "";
request.Timeout = 10000000;
request.UserAgent = "";
;
request.KeepAlive = false;//to avoid the error of time out
HttpWebResponse response = null;
response = (HttpWebResponse)request.GetResponse();
//根據http應答的http頭來判斷編碼
string characterSet = response.CharacterSet;
Encoding encode;
if (characterSet != "")
{
if (characterSet == "ISO-8859-1")
{
characterSet = "gb2312";
}
encode = Encoding.GetEncoding(characterSet);
}
else
{
encode = Encoding.Default;
}
//聲明一個內存流來保存http應答流
Stream receiveStream = response.GetResponseStream();
MemoryStream mStream = new MemoryStream();
byte[] bf = new byte[255];
int count = receiveStream.Read(bf, 0, 255);
while (count > 0)
{
mStream.Write(bf, 0, count);
count = receiveStream.Read(bf, 0, 255);
}
receiveStream.Close();
mStream.Seek(0, SeekOrigin.Begin);
//從內存流里讀取字符串
StreamReader reader = new StreamReader(mStream, encode);
char[] buffer = new char[1024];
count = reader.Read(buffer, 0, 1024);
while (count > 0)
{
str += new String(buffer, 0, count);
count = reader.Read(buffer, 0, 1024);
}
//從解析出的字符串里判斷charset,如果和http應答的編碼不一直
//那么以頁面聲明的為準,再次從內存流里重新讀取文本
Regex reg =
new Regex(@"<meta[\s\S]+?charset=(.*?)""[\s\S]+?>",
RegexOptions.Multiline | RegexOptions.IgnoreCase);
MatchCollection mc = reg.Matches(str);
if (mc.Count > 0)
{
string tempCharSet = mc[0].Result("$1");
if (string.Compare(tempCharSet, characterSet, true) != 0)
{
encode = Encoding.GetEncoding(tempCharSet);
str = string.Empty;
mStream.Seek(0, SeekOrigin.Begin);
reader = new StreamReader(mStream, encode);
buffer = new char[255];
count = reader.Read(buffer, 0, 255);
while (count > 0)
{
str += new String(buffer, 0, count);
count = reader.Read(buffer, 0, 255);
}
}
}
reader.Close();
mStream.Close();
if (response != null)
response.Close();
return str;
}
值得說明的是:盡管采用了此方法,當你查看數據庫的時候,你還是會發現有些正文源碼沒有下載下來。拿我的數據表單來說:我的數據庫表單的各個屬性如下 ArticlePageId,--數據表的主鍵。ArticlePageTitle--新聞標題,ArticlePageUrl,--新聞正文頁URL,ArticlePageSource--新聞正文頁源碼,也就是從ArticlePageUrl下載的源碼。如果ArticlePageSource字段為空,則表明,下載失敗。于是,我又加了一個打補丁的模塊。代碼如下:
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:博客園