c#蜘蛛

C#寫一個採集器javascript

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Web;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;


namespace chinaz
{
 class Program
 {
 static void Main(string[] args)
 {

 string cookie = null;
 using (StreamReader sr = new StreamReader("cookie.txt"))
 {
 cookie = sr.ReadToEnd();
 sr.Close();
 }
 //string tmp = SRWebClient.GetPage(
 // "http://bbs.chinaz.com/Members.html?
 // page=1&sort=CreateDate&desc=true&keyword=",
 // Encoding.UTF8, cookie);
 int a = int.Parse(Console.ReadLine());
 int b = int.Parse(Console.ReadLine());
 string url = Console.ReadLine();

 Hashtable hash = new Hashtable();
 Encoding encoding = Encoding.GetEncoding(Console.ReadLine());

 for (int i = a; i <= b; i++)
 {
 string html = SRWebClient.GetPage(string.Format(url, i), encoding, cookie);
 //Console.WriteLine(html);
 if (html != null && html.Length > 1000)
 {
 Match m = Regex.Match(html,
 @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",
 RegexOptions.Compiled | RegexOptions.IgnoreCase);
 while (m != null && m.Value != null && m.Value.Trim() != string.Empty)
 {
 if (!hash.Contains(m.Value))
 {
 Console.WriteLine(m.Value);
 using (StreamWriter sw = new StreamWriter("mail.txt", true))
 {
 sw.WriteLine(m.Value);
 sw.Close();
 }
 hash.Add(m.Value, string.Empty);
 }
 m = m.NextMatch();
 }

 }
 }



 Console.Write("完成");
 Console.ReadLine();
 }
 }


 public class SRWebClient
 {
 public CookieCollection cookie;
 public SRWebClient()
 {
 cookie = null;
 }

 #region 從包含多個 Cookie 的字符串讀取到 CookieCollection 集合中
 private static void AddCookieWithCookieHead(
 ref CookieCollection cookieCol, string cookieHead, string defaultDomain)
 {
 if (cookieCol == null) cookieCol = new CookieCollection();
 if (cookieHead == null) return;
 string[] ary = cookieHead.Split(';');
 for (int i = 0; i < ary.Length; i++)
 {
 Cookie ck = GetCookieFromString(ary[i].Trim(), defaultDomain);
 if (ck != null)
 {
 cookieCol.Add(ck);
 }
 }
 }
 #endregion

 #region 讀取某一個 Cookie 字符串到 Cookie 變量中
 private static Cookie GetCookieFromString(
 string cookieString, string defaultDomain)
 {
 string[] ary = cookieString.Split(',');
 Hashtable hs = new Hashtable();
 for (int i = 0; i < ary.Length; i++)
 {
 string s = ary[i].Trim();
 int index = s.IndexOf("=");
 if (index > 0)
 {
 hs.Add(s.Substring(0, index), s.Substring(index + 1));
 }
 }
 Cookie ck = new Cookie();
 foreach (object Key in hs.Keys)
 {
 if (Key.ToString() == "path")
 ck.Path = hs[Key].ToString();

 else if (Key.ToString() == "expires")
 {
 //ck.Expires=DateTime.Parse(hs[Key].ToString();
 }
 else if (Key.ToString() == "domain")
 ck.Domain = hs[Key].ToString();
 else
 {
 ck.Name = Key.ToString();
 ck.Value = hs[Key].ToString();
 }
 }
 if (ck.Name == "") return null;
 if (ck.Domain == "") ck.Domain = defaultDomain;
 return ck;
 }
 #endregion



 /**/
 /// <TgData>
 /// <Alias>下載Web源代碼</Alias>
 /// </TgData>
 public string DownloadHtml(string URL, bool CreateCookie)
 {
 try
 {
 HttpWebRequest request = 
 HttpWebRequest.Create(URL) as HttpWebRequest;
 if (cookie != null)
 {
 request.CookieContainer = new CookieContainer();
 request.CookieContainer.Add(cookie);
 }
 request.AllowAutoRedirect = false;
 //request.MaximumAutomaticRedirections = 3;
 request.Timeout = 20000;

 HttpWebResponse res = (HttpWebResponse)request.GetResponse();
 string r = "";

 System.IO.StreamReader S1 = 
 new System.IO.StreamReader(res.GetResponseStream(),
 System.Text.Encoding.Default);
 try
 {
 r = S1.ReadToEnd();
 if (CreateCookie)
 cookie = res.Cookies;
 }
 catch (Exception er)
 {
 //Log l = new Log();
 //l.writelog("下載Web錯誤", er.ToString());
 }
 finally
 {
 res.Close();
 S1.Close();
 }

 return r;
 }

 catch
 {

 }

 return string.Empty;
 }

 /**/
 /// <TgData>
 /// <Alias>下載文件</Alias>
 /// </TgData>
 public long DownloadFile(string FileURL,
 string FileSavePath, bool CreateCookie)
 {
 long Filelength = 0;
 HttpWebRequest req = HttpWebRequest.Create(FileURL) as HttpWebRequest;

 if (cookie != null)
 {
 req.CookieContainer = new CookieContainer();
 req.CookieContainer.Add(cookie);
 }
 req.AllowAutoRedirect = true;

 HttpWebResponse res = req.GetResponse() as HttpWebResponse;
 if (CreateCookie)
 cookie = res.Cookies;
 System.IO.Stream stream = res.GetResponseStream();
 try
 {
 Filelength = res.ContentLength;

 byte[] b = new byte[512];

 int nReadSize = 0;
 nReadSize = stream.Read(b, 0, 512);

 System.IO.FileStream fs = System.IO.File.Create(FileSavePath);
 try
 {
 while (nReadSize > 0)
 {
 fs.Write(b, 0, nReadSize);
 nReadSize = stream.Read(b, 0, 512);
 }
 }
 finally
 {
 fs.Close();
 }
 }
 catch (Exception er)
 {
 //Log l = new Log();
 //l.writelog("下載文件錯誤", er.ToString());
 }
 finally
 {
 res.Close();
 stream.Close();
 }

 return Filelength;
 }

 /**/
 /// <TgData>
 /// <Alias>提交數據</Alias>
 /// </TgData>
 public string Request(string RequestPageURL,
 RequestData Data, bool CreateCookie)
 {
 StreamReader reader = null;
 HttpWebResponse response = null;
 HttpWebRequest request = null;
 try
 {
 string StrUrl = RequestPageURL;
 request = HttpWebRequest.Create(StrUrl) as HttpWebRequest;

 string postdata = Data.GetData();
 request.Referer = RequestPageURL;
 request.AllowAutoRedirect = false;
 request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; "+
 "Windows NT 5.2; SV1; Maxthon; "+
 ".NET CLR 1.1.4322; .NET CLR 2.0.50727)";
 request.Timeout = 20000;

 if (cookie != null)
 {
 request.CookieContainer = new CookieContainer();
 request.CookieContainer.Add(cookie);
 }

 Uri u = new Uri(StrUrl);

 if (postdata.Length > 0) //包含要提交的數據 就使用Post方式
 {
 request.ContentType = "application/x-www-form-urlencoded"; //做爲表單請求
 request.Method = "POST"; //方式就是Post

 //把提交的數據換成字節數組
 Byte[] B = System.Text.Encoding.UTF8.GetBytes(postdata);
 request.ContentLength = B.Length;

 System.IO.Stream SW = request.GetRequestStream(); //開始提交數據
 SW.Write(B, 0, B.Length);
 SW.Close();
 }

 response = request.GetResponse() as HttpWebResponse;
 if (CreateCookie)
 //cookie = response.Cookies;
 AddCookieWithCookieHead(ref cookie,
 response.Headers["Set-Cookie"], request.RequestUri.Host);
 reader = new StreamReader(response.GetResponseStream(), Encoding.Default);

 return reader.ReadToEnd();
 }
 catch (Exception ex)
 {
 string x = ex.StackTrace;
 }
 finally
 {
 if (response != null)
 response.Close();
 }

 return string.Empty;
 }


 public bool PostDownload(RequestData Data, out string file)
 {
 file = null;
 StreamReader reader = null;
 HttpWebResponse response = null;
 HttpWebRequest request = null;
 try
 {
 string StrUrl = "http://www.imobile.com.cn/wapdiyringdownload.php";
 request = HttpWebRequest.Create(StrUrl) as HttpWebRequest;

 string postdata = Data.GetData();
 request.Referer = StrUrl;
 request.AllowAutoRedirect = false;
 request.UserAgent = 
 "Mozilla/4.0 (compatible; MSIE 6.0; "+
 "Windows NT 5.2; SV1; Maxthon; "+
 ".NET CLR 1.1.4322; .NET CLR 2.0.50727)";
 request.Timeout = 20000;

 if (cookie != null)
 {
 request.CookieContainer = new CookieContainer();
 request.CookieContainer.Add(cookie);
 }

 Uri u = new Uri(StrUrl);

 if (postdata.Length > 0) //包含要提交的數據 就使用Post方式
 {
 request.ContentType = "application/x-www-form-urlencoded"; //做爲表單請求
 request.Method = "POST"; //方式就是Post

 //把提交的數據換成字節數組
 Byte[] B = System.Text.Encoding.UTF8.GetBytes(postdata);
 request.ContentLength = B.Length;

 System.IO.Stream SW = request.GetRequestStream(); //開始提交數據
 SW.Write(B, 0, B.Length);
 SW.Close();
 }

 response = request.GetResponse() as HttpWebResponse;
 string des = response.Headers["Content-Disposition"].Trim();
 file = des.Substring(des.IndexOf("filename=") + 9);
 file = new Random().Next(100).ToString() + "/" + file;

 System.IO.Stream stream = response.GetResponseStream();
 try
 {
 int Filelength = (int)response.ContentLength;

 byte[] b = new byte[512];

 int nReadSize = 0;
 nReadSize = stream.Read(b, 0, 512);

 System.IO.FileStream fs = System.IO.File.Create("f:/mobileMusic/" + file);
 try
 {
 while (nReadSize > 0)
 {
 fs.Write(b, 0, nReadSize);
 nReadSize = stream.Read(b, 0, 512);
 }
 }
 finally
 {
 fs.Close();
 }
 }
 catch (Exception er)
 {
 //Log l = new Log();
 //l.writelog("下載文件錯誤", er.ToString());
 }
 finally
 {
 response.Close();
 stream.Close();
 }
 }
 catch (Exception ex)
 {
 string x = ex.StackTrace;
 }
 finally
 {
 if (response != null)
 response.Close();
 }
 return true;
 }
 #region GetPage
 /// <summary>
 /// 獲取源代碼
 /// </summary>
 /// <param name="url"></param>
 /// <param name="coding"></param>
 /// <param name="TryCount"></param>
 /// <returns></returns>
 public static string GetPage(string url, Encoding encoding, int TryCount)
 {
 for (int i = 0; i < TryCount; i++)
 {
 string result = GetPage(url, encoding, null);
 if (result != null && result != string.Empty)
 return result;
 }

 return string.Empty;
 }

 /// <summary>
 /// 獲取源代碼
 /// </summary>
 /// <param name="url"></param>
 /// <param name="coding"></param>
 /// <returns></returns>
 public static string GetPage(string url, Encoding encoding, string cookie)
 {
 HttpWebRequest request = null;
 HttpWebResponse response = null;
 StreamReader reader = null;
 try
 {
 request = (HttpWebRequest)WebRequest.Create(url);
 request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2;)";
 request.Timeout = 20000;
 request.AllowAutoRedirect = false;
 if (cookie != null)
 request.Headers["Cookie"] = cookie;

 response = (HttpWebResponse)request.GetResponse();
 if (response.StatusCode == HttpStatusCode.OK && 
 response.ContentLength < 1024 * 1024)
 {
 reader = 
 new StreamReader(response.GetResponseStream(), encoding);
 string html = reader.ReadToEnd();

 return html;
 }
 }
 catch
 {
 }
 finally
 {

 if (response != null)
 {
 response.Close();
 response = null;
 }
 if (reader != null)
 reader.Close();

 if (request != null)
 request = null;

 }

 return string.Empty;
 }
 #endregion
 }

 public class RequestData
 {
 Hashtable hash = new Hashtable();

 public RequestData()
 {

 }

 public string GetData()
 {
 string r = "";

 foreach (string key in hash.Keys)
 {
 if (r.Length > 0) r += "&";
 r += key + "=" + hash[key];
 }

 return r;
 }

 public void AddField(string Field, string Value)
 {
 hash[Field] = Value;
 }


 }
}
 
View Code

C#抓取網站下的連接下的網頁數據怎麼作??php

1讀取此網站的頁面源代碼
2利用正則取得全部超鏈接的內容
3把取得的超鏈接內容循環,再次操做1,2的步驟,此次2中寫邏輯你想要的 數據

---讀取網頁源代碼---
protected void Page_Load(object sender, EventArgs e)
{
string strtemp;
strtemp = GetURLContent("http://go.microsoft.com/fwlink/?LinkId=25817", "utf-8");
//Response.ContentType = "application/x-www-form-urlencoded";
Response.Write(strtemp);
}
string GetURLContent(string url,string EncodingType)
{
string PetiResp = "";
Stream mystream;
//"http://go.microsoft.com/fwlink/?LinkId=25817"
//"utf-8"
System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(url);
req.AllowAutoRedirect = true;
System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)req.GetResponse();
if (resp.StatusCode == System.Net.HttpStatusCode.OK)
{
mystream = resp.GetResponseStream();
System.Text.Encoding encode = System.Text.Encoding.GetEncoding(EncodingType);
StreamReader readStream = new StreamReader(mystream, encode);
char[] cCont = new char[500];
int count = readStream.Read(cCont, 0, 256);
while (count > 0)
{
// Dumps the 256 characters on a string and displays the string to the console.
String str = new String(cCont, 0, count);
PetiResp += str;
count = readStream.Read(cCont, 0, 256);
}
resp.Close();
return PetiResp;
}
resp.Close();
return null;
}
View Code

spiderhtml

 
 
 
 
 
 
C#蜘蛛程序spider
 
技術說明書
 
 
 
 
山東大學 李若寒
liruohan399@163.com
2006-4-18
 
 
 
 
 
 
 
 
 
一. 開發背景
 
  提到搜索引擎,你們都不陌生,例如你們熟悉的google,百度,網絡的信息浩如煙海,搜索引擎如海中燈塔,在人得到知識過程當中起了極其巨大的做用.
 
然而網上的信息極其巨大,即便google這樣的搜索巨人也不能覆蓋所有頁面,事實上google每28天徹底更新一次數據庫,並且其注重的只是網上的靜態頁面,這部分只佔全球網頁的十分之一左右.
 
例如:當你想從山大網上找一些考研的信息,因爲對網站的不熟悉,不知道在哪部分找,而用google等搜索引擎搜索,找到的東西太多太雜,並且不少都不是山大網上的,不符合本身的初衷.這個時候,你就須要一個"蜘蛛程序",它能在很短的時間內,檢索某個網站的所有頁面,找尋你所須要的信息.
 
本軟件就是一個用c#寫成的蜘蛛程序,其核心組件spider.dll可獨立使用,若有須要,直接在你的程序裏添加對spider.dll的引用便可。
 
熟悉搜索引擎的同窗可能知道,google,baidu等網站就是利用蜘蛛程序將Web頁面收集到到本身的數據庫,以便用戶查詢。
 
不只僅是搜索引擎,我的用戶能夠用蜘蛛程序下載Web頁面以便脫機使用,網站開發者能夠利用蜘蛛程序掃描本身的Web檢查無效的連接……對於不一樣的用戶,蜘蛛程序有不一樣的用途。
 
 項目文檔裏有所有的源代碼,你能夠按照本身的要求修改源代碼以符合本身的要求
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
二. 軟件原理
 
蜘蛛程序,正如它的名字同樣,就象現實當中的蜘蛛在它的Web(蜘蛛網)上旅行,蜘蛛程序也按照相似的方式在Web連接織成的網上旅行。
 
蜘蛛程序須要一個初始連接(出發點),它會首先掃描起始頁面包含的連接,而後訪問這些連接指向的頁面,再分析和追蹤那些頁面包含的連接。從理論上看,最終蜘蛛程序會訪問到Internet上的每個頁面,由於Internet上幾乎每個頁面老是被其餘或多或少的頁面引用。
 
 
 
 
 
   原理圖
 

 
 
 
 
 
 
 
 
 
 
三.分析設計
如上圖所示,我將蜘蛛程序按程序流程分紅以下幾大主模塊
(1) 連接處理模塊:url類
 

 
(2) 鏈接模塊:http類
 
 

 
 
 
 
 
 
 
 
 
 
 
 
 
(3) Html解析模塊:HtmlAnalysis類,Attribute類,Attributelist類
 
 

 
(4) 存儲結構模塊:Hashtb類
 
隊列 UrlQueue: 先進先出表,用於存儲獲得的全部Url;
Hashtable UrlHash: 用於存儲訪問過的連接,以訪重複訪問
 
(5) 流程調用模塊:Spider類
  
  用於總體流程的調用,實現原理圖中的大循環
 
(6) 網頁重要度計算算法:
1. Value=10 ;
2. Value= Value – Url.Count(‘\’) + 2 ;
3. Value= Value - Url.Count(‘?’) - Url.Count(‘#’) ;
4. Return Value ;
 
 
View Code

是Internet上一種頗有用的程序,搜索引擎利用蜘蛛程序將Web頁面收集到數據 庫,企業利用蜘蛛程序監視競爭對手的網站並跟蹤變更,我的用戶用蜘蛛程序下載Webjava

是Internet上一種頗有用的程序,搜索引擎利用蜘蛛程序將Web頁面收集到數據 庫,企業利用蜘蛛程序監視競爭對手的網站並跟蹤變更,我的用戶用蜘蛛程序下載Web頁面以便脫機使用,開發者利用蜘蛛程序掃描本身的Web檢查無效的鏈 接……對於不一樣的用戶,蜘蛛程序有不一樣的用途。那麼,蜘蛛程序究竟是怎樣工做的呢?
蜘蛛是一種半自動的程序,就象現實當中的蜘蛛在它的Web(蜘蛛網)上旅行同樣,蜘蛛程序也按照相似的方式在Web連接織成的網上旅行。蜘蛛程序之 因此是半自動的,是由於它老是須要一個初始連接(出發點),但此後的運行狀況就要由它本身決定了,蜘蛛程序會掃描起始頁面包含的連接,而後訪問這些連接指 向的頁面,再分析和追蹤那些頁面包含的連接。從理論上看,最終蜘蛛程序會訪問到Internet上的每個頁面,由於Internet上幾乎每個頁面總 是被其餘或多或少的頁面引用。
本文介紹如何用C#語言構造一個蜘蛛程序,它可以把整個網站的內容下載到某個指定的目錄,程序的運行界面如圖一。你能夠方便地利用本文提供的幾個核心類構造出本身的蜘蛛程序。
C#特別適合於構造蜘蛛程序,這是由於它已經內置了HTTP訪問和多線程的能力,而這兩種能力對於蜘蛛程序來講都是很是關鍵的。下面是構造一個蜘蛛程序要解決的關鍵問題:
· HTML分析:須要某種HTML解析器來分析蜘蛛程序遇到的每個頁面。
· 頁面處理:須要處理每個下載獲得的頁面。下載獲得的內容可能要保存到磁盤,或者進一步分析處理。
· 多線程:只有擁有多線程能力,蜘蛛程序才能真正作到高效。
· 肯定什麼時候完成:不要小看這個問題,肯定任務是否已經完成並不簡單,尤爲是在多線程環境下。
1、HTML解析
C#語言自己不包含解析HTML的能力,但支持XML解析;不過,XML有着嚴格的語法,爲XML設計的解析器對HTML來講根本沒用,由於 HTML的語法要寬鬆得多。爲此,咱們須要本身設計一個HTML解析器。本文提供的解析器是高度獨立的,你能夠方便地將它用於其它用C#處理HTML的場 合。
本文提供的HTML解析器由ParseHTML類實現,使用很是方便:首先建立該類的一個實例,而後將它的Source屬性設置爲要解析的HTML文檔:
ParseHTML parse = new ParseHTML(); parse.Source = "<p>Hello World</p>";
接下來就能夠利用循環來檢查HTML文檔包含的全部文本和標記。一般,檢查過程能夠從一個測試Eof方法的while循環開始:
while(!parse.Eof()) { char ch = parse.Parse();
Parse方法將返回HTML文檔包含的字符--它返回的內容只包含那些非HTML標記的字符,若是遇到了HTML標記,Parse方法將返回0值,表示如今遇到了一個HTML標記。遇到一個標記以後,咱們能夠用GetTag()方法來處理它。
if(ch==0) { HTMLTag tag = parse.GetTag(); }
通常地,蜘蛛程序最重要的任務之一就是找出各個HREF屬性,這能夠藉助C#的索引功能完成。例如,下面的代碼將提取出HREF屬性的值(若是存在的話)。
Attribute href = tag["HREF"]; string link = href.Value; 得到Attribute對象以後,經過Attribute.Value能夠獲得該屬性的值。
2、處理HTML頁面
下面來看看如何處理HTML頁面。首先要作的固然是下載HTML頁面,這能夠經過C#提供的HttpWebRequest類實現:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(m_uri); response = request.GetResponse(); stream = response.GetResponseStream();
接下來咱們就從request建立一個stream流。在執行其餘處理以前,咱們要先肯定該文件是二進制文件仍是文本文件,不一樣的文件類型處理方式也不一樣。下面的代碼肯定該文件是否爲二進制文件。
if( !response.ContentType.ToLower().StartsWith("text/") ) { SaveBinaryFile(response); return null; } string buffer = "",line;
若是該文件不是文本文件,咱們將它做爲二進制文件讀入。若是是文本文件,首先從stream建立一個StreamReader,而後將文本文件的內容一行一行加入緩衝區。
reader = new StreamReader(stream); while( (line = reader.ReadLine())!=null ) { buffer+=line+"\r\n"; } 裝入整個文件以後,接着就要把它保存爲文本文件。 SaveTextFile(buffer);
下面來看看這兩類不一樣文件的存儲方式。
二進制文件的內容類型聲明不以"text/"開頭,蜘蛛程序直接把二進制文件保存到磁盤,沒必要進行額外的處理,這是由於二進制文件不包含HTML,所以也不會再有須要蜘蛛程序處理的HTML連接。下面是寫入二進制文件的步驟。
首先準備一個緩衝區臨時地保存二進制文件的內容。 byte []buffer = new byte[1024]; 接下來要肯定文件保存到本地的路徑和名稱。若是要把一個myhost.com網站的內容下載到本地 的c:\test文件夾,二進制文件的網上路徑和名稱是http://myhost.com/images/logo.gif,則 本地路徑和名稱應當是c:\test\images\logo.gif。與此同時,咱們還要確保c:\test目錄下已 經建立了images子目錄。這部分任務由convertFilename方法完成。 string filename = convertFilename( response.ResponseUri ); convertFilename方法分離HTTP地址,建立相應的目錄結構。肯定了輸出文件的名字和路徑之 後就能夠打開讀取Web頁面的輸入流、寫入本地文件的輸出流。 Stream outStream = File.Create( filename ); Stream inStream = response.GetResponseStream(); 接下來就能夠讀取Web文件的內容並寫入到本地文件,這能夠經過一個循環方便地完成。 int l; do { l = inStream.Read(buffer,0, buffer.Length); if(l>0) outStream.Write(buffer,0,l); } while(l>0); 寫入整個文件以後,關閉輸入流、輸出流。 outStream.Close(); inStream.Close();
比較而言,下載文本文件更容易一些。文本文件的內容類型老是以"text/"開頭。假設文件已被下載並保存到了一個字符串,這個字符串能夠用來分析網頁包含的連接,固然也能夠保存爲磁盤上的文件。下面代碼的任務就是保存文本文件。
string filename = convertFilename( m_uri ); StreamWriter outStream = new StreamWriter( filename ); outStream.Write(buffer); outStream.Close();
在這裏,咱們首先打開一個文件輸出流,而後將緩衝區的內容寫入流,最後關閉文件。
3、多線程
多線程使得計算機看起來就象可以同時執行一個以上的操做,不過,除非計算機包含多個處理器,不然,所謂的同時執行多個操做僅僅是一種模擬出來的效果 --靠計算機在多個線程之間快速切換達到"同時"執行多個操做的效果。通常而言,只有在兩種狀況下多線程才能事實上提升程序運行的速度。第一種狀況是計算 機擁有多個處理器,第二種狀況是程序常常要等待某個外部事件。
對於蜘蛛程序來講,第二種狀況正是它的典型特徵之一,它每發出一個URL請求,老是要等待文件下載完畢,而後再請求下一個URL。若是蜘蛛程序可以同時請求多個URL,顯然可以有效地減小總下載時間。
爲此,咱們用DocumentWorker類封裝全部下載一個URL的操做。每當一個DocumentWorker的實例被建立,它就進入循環,等待下一個要處理的URL。下面是DocumentWorker的主循環:
while(!m_spider.Quit ) { m_uri = m_spider.ObtainWork(); m_spider.SpiderDone.WorkerBegin(); string page = GetPage(); if(page!=null) ProcessPage(page); m_spider.SpiderDone.WorkerEnd(); }
這個循環將一直運行,直至Quit標記被設置成了true(當用戶點擊"Cancel"按鈕時,Quit標記就被設置成true)。在循環以內,我 們調用ObtainWork獲取一個URL。ObtainWork將一直等待,直到有一個URL可用--這要由其餘線程解析文檔並尋找連接才能得到。 Done類利用WorkerBegin和WorkerEnd方法來肯定什麼時候整個下載操做已經完成。
從圖一能夠看出,蜘蛛程序容許用戶本身肯定要使用的線程數量。在實踐中,線程的最佳數量受許多因素影響。若是你的機器性能較高,或者有兩個處理器,能夠設置較多的線程數量;反之,若是網絡帶寬、機器性能有限,設置太多的線程數量其實不必定可以提升性能。
4、任務完成了嗎?
利用多個線程同時下載文件有效地提升了性能,但也帶來了線程管理方面的問題。其中最複雜的一個問題是:蜘蛛程序什麼時候纔算完成了工做?在這裏咱們要藉助一個專用的類Done來判斷。
首先有必要說明一下"完成工做"的具體含義。只有當系統中不存在等待下載的URL,並且全部工做線程都已經結束其處理工做時,蜘蛛程序的工做纔算完成。也就是說,完成工做意味着已經沒有等待下載和正在下載的URL。
Done類提供了一個WaitDone方法,它的功能是一直等待,直到Done對象檢測到蜘蛛程序已完成工做。下面是WaitDone方法的代碼。
public void WaitDone() { Monitor.Enter(this); while ( m_activeThreads>0 ) { Monitor.Wait(this); } Monitor.Exit(this); }
WaitDone方法將一直等待,直到再也不有活動的線程。但必須注意的是,下載開始的最初階段也沒有任何活動的線程,因此很容易形成蜘蛛程序一開始 就當即中止的現象。爲解決這個問題,咱們還須要另外一個方法WaitBegin來等待蜘蛛程序進入"正式的"工做階段。通常的調用次序是:先調用 WaitBegin,再接着調用WaitDone,WaitDone將等待蜘蛛程序完成工做。下面是WaitBegin的代碼:
public void WaitBegin() { Monitor.Enter(this); while ( !m_started ) { Monitor.Wait(this); } Monitor.Exit(this); }
WaitBegin方法將一直等待,直到m_started標記被設置。m_started標記是由WorkerBegin方法設置的。工做線程在 開始處理各個URL之時,會調用WorkerBegin;處理結束時調用WorkerEnd。WorkerBegin和WorkerEnd這兩個方法幫助 Done對象肯定當前的工做狀態。下面是WorkerBegin方法的代碼:
public void WorkerBegin() { Monitor.Enter(this); m_activeThreads++; m_started = true; Monitor.Pulse(this); Monitor.Exit(this); }
WorkerBegin方法首先增長當前活動線程的數量,接着設置m_started標記,最後調用Pulse方法以通知(可能存在的)等待工做線 程啓動的線程。如前所述,可能等待Done對象的方法是WaitBegin方法。每處理完一個URL,WorkerEnd方法會被調用:
public void WorkerEnd() { Monitor.Enter(this); m_activeThreads--; Monitor.Pulse(this); Monitor.Exit(this); }
WorkerEnd方法減少m_activeThreads活動線程計數器,調用Pulse釋放可能在等待Done對象的線程--如前所述,可能在等待Done對象的方法是WaitDone方法。
結束語:本文介紹了開發Internet蜘蛛程序的基礎知識,下面提供的源代碼將幫助你進一步深刻理解本文的主題。這裏提供的代碼很是靈活,你能夠方便地將它用於本身的程序。
源碼下載地址:http://myblog.workgroup.cn/files/folders/csharp/entry1639.aspx
 
View Code

用C#2.0實現網絡蜘蛛(WebSpider)程序員

摘要:本文討論瞭如何使用C#2.0實現抓取網絡資源的網絡蜘蛛。使用這個程序,能夠經過一個入口網址(如 http://www.comprg.com.cn)來掃描整個互聯網的網址,並將這些掃描到的網址所指向的網絡資源下載到本地。而後能夠利用其餘的分析 工具對這些網絡資源作進一步地分析,如提取關鍵詞、分類索引等。也能夠將這些網絡資源做爲數據源來實現象Google同樣的搜索引擎。
關鍵詞:C#2.0,Html,網絡蜘蛛, 鍵樹,正則表達式
1、引言

    在最近幾年,以Google爲首的搜索引擎愈來愈引發人們的關注。因爲在Google出現以前,不少提供搜索服務的公司都是使用人工從網絡上搜集信息,並 將這些信息分類彙總後做爲搜索引擎的數據源。如yahoo公司一開始就是經過數千人不停地從網上搜集供查詢的信息。這樣作雖然信息的分類會很人性化,也比 較準確,可是隨着互聯網信息爆炸式地增加,經過人工的方式來蒐集信息已經不可能知足網民對信息的需求了。然而,這一切隨着Google的出現而獲得了完全 改變。Google一反常規的作法,經過程序7*24地從網上不停地獲取網絡資源,而後經過一些智能算法分析這些被下載到本地的網絡資源,最後將這些分析 後的數據進行索引後就造成了一套完整的基本上不須要人工干預的搜索引擎。使用這種模式的搜索引擎甚至能夠在幾天以內就可獲取Internet中的全部信 息,同時也節省了大量的資金和時間成本。而這種搜索引擎最重要的組成部分之一就是爲搜索引擎提供數據源的網絡蜘蛛。也就是說,實現網絡蜘蛛是實現搜索引擎 的第一步,也是最重要的一步。

2、網絡蜘蛛的基本實現思想和實現步驟

    網絡蜘蛛的主要做用是從Internet上不停地下載網絡資源。它的基本實現思想就是經過一個或多個入口網址來獲取更多的URL,而後經過對這些URL所 指向的網絡資源下載並分析後,再得到這些網絡資源中包含的URL,以此類推,直到再沒有可下的URL爲止。下面是用程序實現網絡蜘蛛的具體步驟。

    1. 指定一個(或多個)入口網址(如http://www.comprg.com.cn),並將這個網址加入到下載隊列中(這時下載隊列中只有一個或多個入口網址)。
    2. 負責下載網絡資源的線程從下載隊列中取得一個或多個URL,並將這些URL所指向的網絡資源下載到本地(在下載以前,通常應該判斷一下這個URL是否已經 被下載過,若是被下載過,則忽略這個URL)。若是下載隊列中沒有URL,而且全部的下載線程都處於休眠狀態,說明已經下載完了由入口網址所引出的全部網 絡資源。這時網絡蜘蛛會提示下載完成,並中止下載。
    3. 分析這些下載到本地的未分析過的網絡資源(通常爲html代碼),並得到其中的URL(如標籤<a>中href屬性的值)。
    4. 將第3步得到的URL加入到下載隊列中。並從新執行第2步。

3、實現數據的輸入輸出

    從實現網絡蜘蛛的步驟中咱們能夠看出,下載隊列的讀、寫URL的操做一直貫穿於整個系統中。雖然這個下載隊列能夠用.Queue類實現,可是各位讀者要清 楚地知道,在互聯網上的URL可不是幾十個、幾百個這麼少。而是以千萬計的。這麼多的URL顯然不能保存在內存中的Queue對象中。所以,咱們須要將它 保存在容量更大的存儲空間中,這就是硬盤。
    本文采用了一個普通的文本文件來保存須要下載和分析的URL(這個文本文件也就是下載隊列)。存儲格式是每一行爲一個URL。既然將URL都保存在了文本文件中,就須要對這個文本文件進行讀寫。所以,在本節實現了一個用於操做這個文本文件的FileIO類。
    在實現FileIO類以前,先來講一下要如何操做這個文本文件。既然要將這個文件做爲隊列使用,那麼就須要對這個文件進行追加行和從文件開始部分讀取數據操做。讓咱們首先來實現向文件中追加行操做。實現代碼以下:

    向文件中追加行的實現代碼
// 這兩個變量爲類全局變量
private FileStream fsw;
private StreamWriter sw;

// 建立用於向文件中追加行的文件流和StreamWriter對象
public void OpenWriteFile(string file)
{
if (!File.Exists(file)) // 若是文件不存在,先建立這個文件
File.Create(file).Close();
// 以追加模式打開這個文件
fsw = new FileStream(file, FileMode.Append ,FileAccess.Write, FileShare.ReadWrite);
// 根據建立的FileStream對象來建立StreamWriter對象
sw = new StreamWriter(fsw);
}
// 關閉寫文件流
public void CloseWriteFile()
{
if (fsr != null)
fsw.Close();
}
// 向文件中追加一行字符串
public void WriteLine(string s)
{
sw.WriteLine(s);
sw.Flush(); // 刷新寫入緩衝區,使這一行對於讀文件流可見
}

    在實現上述的代碼時要注意,在建立FileStream對象時,必須使用FileShare.ReadWrite,不然這個文件沒法被兩個或兩個以上的 Stream打開,也就是說下面要介紹的讀文件流將沒法操做這個被寫文件流打開的文件。從文件中讀取行的實現代碼以下:

    從文件中讀取行的實現代碼
// 這兩個變量爲類全局變量
private FileStream fsr;
private StreamReader sr;

// 建立用於讀取文件行的文件流和StreamWriter對象
public void OpenReadFile(string file)
{
if (!File.Exists(file)) // 若是文件不存在,首先建立這個文件
File.Create(file).Close();
fsr = new FileStream(file, FileMode.OpenOrCreate, FileAccess.Read,
FileShare.ReadWrite);
sr = new StreamReader(fsr);
}
// 關閉讀文件流
public void CloseReadFile()
{
if(fsr != null)
fsr.Close();
}
// 從文件中讀取一行
public string ReadLine()
{
if(sr.EndOfStream) // 若是文件流指針已經指向文件尾部,返回null
return null;
return sr.ReadLine();
}

    除了上述的讀寫文件的代碼外,FileIO還提供了一個IsEof方法用來判斷文件流指針是否位於文件尾部。IsEof方法的實現代碼以下以下:

IsEof方法的實現代碼
// 用於判斷文件流指針是否位於文件尾部
public bool IsEof()
{
return sr.EndOfStream;
}

    FileIO類不只僅用於對下載隊列的讀寫。在後面咱們還會講到,網絡蜘蛛經過多線程下載網絡資源時,每個線程將本身下載的網絡資源保存在屬於本身的一 個目錄中。每一個這樣的目錄都有一個index.txt文件,這個文件保存了當前目錄的網絡資源的URL。向index.txt文件中追加URL也用到了 FileIO(index.txt不須要讀取,只須要不斷地追加行)。


4、線程類的實現

    要想使網絡蜘蛛在有限的硬件環境下儘量地提升下載速度。最廉價和快捷的方法就是使用多線程。在.net framework2.0中提供了豐富的線程功能。其中的核心線程類是Thread。通常可以使用以下的代碼建立並運行一個線程:

    在C#中使用線程的演示代碼
private void fun()
{
// 線程要執行的代碼
}
public void testThread()
{
Thread thread;
thread = new Thread(fun); // 建立一個Thread對象,並將fun設爲線程運行的方法
thread.Start(); // 運行一個線程
}

    雖然上面的代碼比較簡單地建立並運行了一個線程,可是這段代碼看起來仍然不夠透明,也就是客戶端在調用線程時仍然須要顯式地使用Thread類。下面咱們 來實現一個用於建立線程的MyThread類。C#中的任何類只須要繼承這個類,就能夠自動變成一個線程類。MyThread類的代碼以下:

    MyThread類的實現代碼
// 任何C#類繼承MyThread後,就會自動變成一個線程類
class MyThread
{
private Thread thread;
public MyThread()
{
thread = new Thread(run); // 建立Thread對象
}
// 用於運行線程代碼的方法,MyThread的子類必須覆蓋這個方法
public virtual void run()
{
}
public void start()
{
thread.Start(); // 開始運行線程,也就是開始執行run方法
}
// 使當前線程休眠millisecondsTimeout毫秒
public void sleep(int millisecondsTimeout)
{
Thread.Sleep(millisecondsTimeout);
}
}


    咱們可參照以下的代碼使用MyThread類:

    測試的ThreadClass類的代碼
class ThreadClass : MyThread
{
public override void run()
{
// 要執行的線程代碼
}
}

// 測試ThreadClass類
public void testThreadClass()
{
ThreadClass tc = new ThreadClass();
tc.start(); // 開始運行線程,也就是執行run方法
}

    各位讀者能夠看看,上面的代碼是否是要比直接使用Thread類更方便、直觀、易用,還有些面向對象的感受!

5、用多線程下載網絡資源

    通常來講,網絡蜘蛛都是使用多線程來下載網絡資源的。至於如何使用多線程來下載,各個版本的網絡蜘蛛不盡相同。爲了方便和容易理解,本文所討論的網絡蜘蛛 採用了每個線程負責將網絡資源下載到一個屬於本身的目錄中,也就是說,每個線程對應一個目錄。而在當前目錄中下載的網絡資源達到必定的數目後(如 5000),這個線程就會再創建一個新目錄,並從0開始計數繼續下載網絡資源。在本節中將介紹一個用於下載網絡資源的線程類 DownLoadThread。這個類的主要功能就是從下載隊列中得到必定數量的URL,並進行下載和分析。在DownLoadThread類中涉及到很 多其餘重要的類,這些類將在後面的部分介紹。在這裏咱們先看一下DownLoadThread類的實現代碼。

    DownLoadThread類的代碼
class DownLoadThread : MyThread
{
// ParseResource類用於下載和分析網絡資源
private ParseResource pr = new ParseResource();
private int currentCount = 0; // 當前下載目錄中的網頁數
// 用於向每一個線程目錄中的index.txt中寫當前目錄的URL
private FileIO fileIO = new FileIO();
private string path; // 當前的下載目錄(後面帶「\")
private string[] patterns; // 線程不下載符合patterns中的正則表達式的URL
public bool stop = false; // stop爲true,線程退出
public int threadID; // 當前線程的threadID,用於區分其餘的線程

public DownLoadThread(string[] patterns)
{
pr.findUrl += findUrl; // 爲findUrl事件賦一個方法
this.patterns = patterns;
}
// 這是一個事件方法,每得到一個URL時發生
private void findUrl(string url)
{
Common.addUrl(url); // 將得到的URL加到下載隊列中
}
private void openFile() // 打開下載目錄中的index.txt文件
{
fileIO.CloseWriteFile();
fileIO.OpenWriteFile(path + Common.indexFile);
}
public override void run() // 線程運行方法
{
LinkedList<string> urls = new LinkedList<string>();
path = Common.getDir(); // 得到下載目錄
openFile();
while (!stop)
{
// 當下載隊列中沒有URL時,進行循環等待
while (!stop && urls.Count == 0)
{
Common.getUrls(urls, 20); // 從下載隊列中得到20個url
if (urls.Count == 0) // 若是未得到url
{
// 通知系統當前線程已處於等待狀態,
// 若是全部的線程都處於等待狀態,
// 說明全部的網絡資源都被下載完了
Common.threadWait(threadID);
sleep(5000); // 當前線程休眠5秒
}
}
StringBuilder sb = new StringBuilder();
foreach (string url in urls) // 循環對這20個url進行循環下載分析
{
if (stop) break;
// 若是當前下載目錄的資源文件數大於等於最大文件數目時,
// 創建一個新目錄,並繼續下載
if (currentCount >= Common.maxCount)
{
path = Common.getDir();
openFile();
currentCount = 0; // 目錄
}
// 每一個下載資源文件名使用5位的順序號保存(沒有擴展名),
// 如0000一、00002。下面的語句是格式化文件名
string s = string.Format("{0:D5}", currentCount + 1);
sb.Remove(0, sb.Length);
sb.Append(s);
sb.Append(":");
sb.Append(url);
try
{
// 下載和分析當前的url
pr.parse(url, path + s, patterns);
Common.Count++;
// 將當前的url寫入index.txt
fileIO.WriteLine(sb.ToString());
currentCount++;
}
catch (Exception e)
{

}
}
urls.Clear();
}
}
}
}

6、分析網絡資源

    對下載的網絡資源進行分析是網絡蜘蛛中最重要的功能之一。這裏網絡資源主要指的是html代碼中<a>標籤的href屬性值。狀態和狀態之間會根據從html文件中讀入的字符進行切換。下面是狀態之間切換的描述。

狀態0:讀入'<'字符後切換到狀態1,讀入其餘的字符,狀態不變。
狀態1:讀入'a''A',切換到狀態2,讀入其餘的字符,切換到狀態0。
狀態2:讀入空格或製表符(\t),切換到狀態3,讀入其餘的字符,切換到狀態0。
狀 態3:讀入'>',成功得到一個<a>,讀入其餘的字符,狀態不變。爲了更容易說明問題。在本文給出的網絡蜘蛛中只提取了html代碼 中<a>中的href屬性中的url。本文中所採用的分析方法是分步進行提取href。首先將html代碼中的<a>標籤整個提 出來。不包括</a>和前面的字符,如<a href="http://www.comprg.com.cn">comprg</a>中只提取<a href="http://www.comprg.com.cn">,而comprg</a>將被忽略,由於這裏並無url。
本文使用了一個狀態機來的提取<a>,這個狀態機分爲五個狀態(04)。第一個狀態是初始態,最後一個狀態爲終止態,若是到達最後一個狀態,說明已經成功得到了一個<a>

    狀態機如圖1所示。



圖1

    最後一個雙環的狀態是最終態。下面讓咱們來看看得到<a>的實現代碼。

getA方法的實現
// 得到html中的<a>
private void getA()
{
char[] buffer = new char[1024];
int state = 0;
String a = "";

while (!sr.EndOfStream)
{
int n = sr.Read(buffer, 0, buffer.Length);
for (int i = 0; i < n; i++)
{
switch (state)
{
case 0: // 狀態0
if (buffer[i] == '<') // 讀入的是'<'
{
a += buffer[i];
state = 1; // 切換到狀態1
}
break;
case 1: // 狀態1
if (buffer[i] == 'a' || buffer[i] == 'A') // 讀入是'a'或'A'
{
a += buffer[i];
state = 2; // 切換到狀態2
}
else
{
a = "";
state = 0; // 切換到狀態0
}
break;
case 2: // 狀態2
if (buffer[i] == ' ' || buffer[i] == '\t') // 讀入的是空格或'\t'
{
a += buffer[i];
state = 3;
}
else
{
a = "";
state = 0; // 切換到狀態0
}
break;
case 3: // 狀態3
if (buffer[i] == '>') // 讀入的是'>',已經成功得到一個<a>
{
a += buffer[i];
try
{
string url = getUrl(getHref(a)); // 得到<a>中的href屬性的值
if (url != null)
{
if (findUrl != null)
findUrl(url); // 引起發現url的事件

}
}
catch (Exception e)
{
}
state = 0; // 在得到一個<a>後,從新切換到狀態0
}
else
a += buffer[i];
break;
}
}
}
}

    在getA方法中除了切換到狀態0外,其餘的狀態切換都將已經讀入的字符賦給String變量a,若是最後發現變量a中的字符串不多是<a>後,就將a清空,並切換到狀態0後從新讀入字符。
在getA方法中使用了一個重要的方法getHref來從<a>中得到href部分。getHref方法的實現以下:

    getHref方法的實現
// 從<a>中得到Href
private String getHref(string a)
{
try
{
string p = @"href\s*=\s*('[^']*'|""[^""]*""|\S+\s+)"; // 得到Href的正則表達式
MatchCollection matches = Regex.Matches(a, p,
RegexOptions.IgnoreCase |
RegexOptions.ExplicitCapture);

foreach (Match nextMatch in matches)
{
return nextMatch.Value; // 返回href
}
return null;
}
catch (Exception e)
{
throw e;
}
}

    在getHref方法中使用了正則表達式從<a>中得到href。在<a>中正確的href屬性格式有三種狀況,這三種狀況的主要區別是url兩邊的符號,如單引號、雙引號或沒有符號。這三種狀況以下所示:
狀況1: <a href = "http://www.comprg.com.cn" > comprg</a>
狀況2: <a href = 'http://www.comprg.com.cn' > comprg</a>
狀況3: <a href = http://www.comprg.com.cn > comprg</a>
    getHref方法中的p存儲了用於過濾這三種狀況的href,也就是說,使用正則表達式能夠得到上述三種狀況的href以下:

從狀況1得到得的href:href = "http://www.comprg.com.cn"
從狀況2得到得的href:href = 'http://www.comprg.com.cn'
從狀況3得到得的href:href = http://www.comprg.com.cn

    在得到上述的href後,須要將url提出來。這個功能由getUrl完成,這個方法的實現代碼以下:

getUrl方法的實現
// 從href中提取url
private String getUrl(string href)
{
try
{
if (href == null) return href;
int n = href.IndexOf('='); // 查找'='位置
String s = href.Substring(n + 1);
int begin = 0, end = 0;
string sign = "";
if (s.Contains("\"")) // 第一種狀況
sign = "\"";
else if (s.Contains("'")) // 第二種狀況
sign = "'";
else // 第三種狀況
return getFullUrl(s.Trim());
begin = s.IndexOf(sign);
end = s.LastIndexOf(sign);

return getFullUrl(s.Substring(begin + 1, end - begin - 1).Trim());
}
catch (Exception e)
{
throw e;
}
}

    在得到url時有一點應該注意。有的url使用的是相對路徑,也就是沒有「http://host」部分,但將url保存時須要保存它們的完整路徑。這就須要根據相對路徑得到它們的完整路徑。這個功能由getFullUrl方法完成。這個方法的實現代碼以下:

 getFullUrl方法的實現代碼
// 將相對路徑變爲絕對路徑
private String getFullUrl(string url)
{
try
{
if (url == null) return url;
if (processPattern(url)) return null; // 過濾不想下載的url
// 若是url前有http://或https://,爲絕對路徑,按原樣返回
if (url.ToLower().StartsWith("http://") || url.ToLower().StartsWith("https://"))
return url;
Uri parentUri = new Uri(parentUrl);
string port = "";
if (!parentUri.IsDefaultPort)
port = ":" + parentUri.Port.ToString();
if (url.StartsWith("/")) // url以"/"開頭,直接放在host後面
return parentUri.Scheme + "://" + parentUri.Host + port + url;
else // url不以"/"開頭,放在url的路徑後面
{
string s = "";
s = parentUri.LocalPath.Substring(0, parentUri.LocalPath.LastIndexOf("/"));
return parentUri.Scheme + "://" + parentUri.Host + port + s + "/" + url;
}
}
catch (Exception e)
{
throw e;
}
}

    在ParseResource中還提供了一個功能就是經過正則表達式過濾不想下載的url,這個功能將經過processPattern方法完成。實現代碼以下:

    processPattern方法的實現代碼
// 若是返回true,表示url符合pattern,不然,不符合模式
private bool processPattern(string url)
{
foreach (string p in patterns)
{

if (Regex.IsMatch(url, p, RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture)
&& !p.Equals(""))
return true;
}
return false;
}
    ParseResource類在分析html代碼以前,先將html下載到本地的線程目錄中,再經過FileStream打開並讀取待分析的數據。ParseResource類其餘的實現代碼請讀者參閱本文提供的源代碼。

7、鍵樹的實現

    在獲取Url的過程當中,不免重複得到一些Url。這些重複的Url將大大增長網絡蜘蛛的下載時間,以及會致使其餘的分析工具重複分析同一個html。因 此,就須要對過濾出重複的Url,也就是說,要使網絡蜘蛛下載的Url都是惟一的。達到這個目的的最簡單的方法就是將已經下載過的Url保存到一個集合 中,而後在下載新的Url以前,在這個集合中查找這個新的Url是否被下載過,若是下載過,就忽略這個Url。
    這個功能從表面上看很是簡單,但因爲咱們處理的是成千上萬的Url,要是將這些Url簡單地保存在相似List同樣的集合中,不只會佔用大量的內存空間, 並且當Url很是多時,如一百萬。這時每下載一個Url,就要從這一百萬的Url中查找這個待下載的Url是否存在。雖然能夠使用某些查找算法(如折半查 找)來處理,但當數據量很是大時,任何查找算法的效率都會大打折扣。所以,必需要設計一種新的存儲結構來完成這個工做。這個新的數據存儲結構須要具備兩個 特性:

    1. 儘量地減小存儲Url所使用的內存。
    2. 查找Url的速度儘量地快(最好的多是查找速度和Url的數量無關)。

    下面先來完成第一個特性。通常一個Url都比較長,如平均每一個Url有50個字符。若是有不少Url,每一個Url佔50個字符,一百萬個Url就是會佔用 50M的存儲空間。而咱們保存Url的目的只有一個,就是查找某一個Url是否存在。所以,只須要將Url的Hashcode保存起來便可。因爲 Hashcode爲Int類型,所以,Hashcode要比一個Url字符串使用更少的存儲空間。
    對於第二個特性,咱們能夠使用數據結構中的鍵樹來解決。假設有一個數是4532。首先將其轉換爲字符串。而後每一個鍵樹節點有10個(0至9)。這樣4532的存儲結構如圖2所示:



圖2

    從上面的數據結構能夠看出,查找一個整數只和這個整數的位數有關,和整數的數量無關。這個鍵樹的實現代碼以下:

    KeyTree的實現代碼
class KeyTreeNode // 鍵樹節點的結構
{
// 指向包含整數下一個的結點的指針
public KeyTreeNode[] pointers = new KeyTreeNode[10];
// 結束位標誌,若是爲true,表示當前結點爲整數的最後一位
public bool[] endFlag = new bool[10];
}
class KeyTree
{
private KeyTreeNode rootNode = new KeyTreeNode(); // 根結點
// 向鍵樹中添加一個無符號整數
public void add(uint n)
{
string s = n.ToString();
KeyTreeNode tempNode = rootNode;
int index = 0;
for (int i = 0; i < s.Length; i++)
{
index = int.Parse(s[i].ToString()); // 得到整數每一位的值
if (i == s.Length - 1) // 在整數的最後一位時,將結束位設爲true
{
tempNode.endFlag[index] = true;
break;
}
if (tempNode.pointers[index] == null) // 當下一個結點的指針爲空時,新創建一個結點對象
tempNode.pointers[index] = new KeyTreeNode();
tempNode = tempNode.pointers[index];
}
}
// 判斷一個整數是否存在
public bool exists(uint n)
{
string s = n.ToString();
KeyTreeNode tempNode = rootNode;
int index = 0;
for (int i = 0; i < s.Length; i++)
{
if (tempNode != null)
{
index = int.Parse(s[i].ToString());
// 當整數的最後一位的結束標誌爲true時,表示n存在
if((i == s.Length - 1)&& (tempNode.endFlag[index] == true))
return true;
else
tempNode = tempNode.pointers[index];
}
else
return false;
}
return false;
}
}

    上面代碼中的KeyTreeNode之因此要使用結束標誌,而不根據指針是否爲空判斷某個整數的存在,是由於可能存在長度不相等的整數,如4321和 432。若是隻使用指針判斷。保存4321後,432也會被認爲存在。而若是用結束標誌後,在值爲2的節點的結束標誌爲false,所以,代表432並不 存在。下面的UrlFilter使用了上面的鍵樹來處理Url。

    UrlFilter類的實現代碼
// 用於將url從新組合後再加到鍵樹中
// 如http://www.comprg.com.cn和http://www.comprg.com.cn/是同樣的
// 所以,它們的hashcode也要求同樣
class UrlFilter
{
public static KeyTree urlHashCode = new KeyTree();
private static object syncUrlHashCode = new object();
private static string processUrl(string url) // 從新組合Url
{
try
{
Uri uri = new Uri(url);
string s = uri.PathAndQuery;
if(s.Equals("/"))
s = "";
return uri.Host + s;
}
catch(Exception e)
{
throw e;
}
}
private static bool exists(string url) // 判斷url是否存在
{
try
{
lock (syncUrlHashCode)
{
url = processUrl(url);
return urlHashCode.exists((uint)url.GetHashCode());
}
}
catch (Exception e)
{
throw e;
}
}

public static bool isOK(string url)
{
return !exists(url);
}
// 加處理完的Url加到鍵樹中
public static void addUrl(string url)
{
try
{
lock (syncUrlHashCode)
{
url = processUrl(url);
urlHashCode.add((uint)url.GetHashCode());
}
}
catch (Exception e)
{
throw e;
}
}

}

8、其餘部分的實現

    到如今爲止,網絡蜘蛛全部核心代碼都已經完成了。下面讓咱們作一個界面來使下載過程可視化。界面如圖3所示。



圖3

    這個界面主要經過一個定時器每2秒鐘得到個一次網絡蜘蛛的下載狀態。包括得到的URL數和已經下載的網絡資源數。其中這些狀態信息都保存在一個Common類的靜態變量中。Common類和主界面的代碼請讀者參閱本文提供的源代碼。

9、結束語

    至此,網絡蜘蛛程序已經所有完成了。但在實際應用中,光靠一臺機器下載整個的網絡資源是遠遠不夠的。這就須要經過多臺機器聯合下載。然而這就會給咱們帶來 一個難題。就是這些機器須要對已經下載的Url進行同步。讀者能夠根據本文提供的例子,將其改爲分佈式的可多機同時下載的網絡蜘蛛。這樣網絡蜘蛛的下載速 度將會有一個質的飛躍。
分類: Data Mining
 
View Code

本身用C#寫一個採集器、蜘蛛web

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Web;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;
 
 
 
 
 
namespace chinaz
 
{
    class Program
    {
        static void Main(string[] args)
        {
 
 
            string cookie = null;
 
            using (StreamReader sr = new StreamReader("cookie.txt"))
            {
                cookie = sr.ReadToEnd();
                sr.Close();
            }
           
            int a = int.Parse(Console.ReadLine());
            int b = int.Parse(Console.ReadLine());
            string url = Console.ReadLine();
 
 
            Hashtable hash = new Hashtable();
 
            Encoding encoding = Encoding.GetEncoding(Console.ReadLine());
 
 
            for (int i = a; i <= b; i++)
 
            {
                string html =
    SRWebClient.GetPage(string.Format(url, i), encoding, cookie);
                //Console.WriteLine(html);
                if (html != null && html.Length > 1000)
                {
                    Match m =
                        Regex.Match(html,
                        @"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",
                        RegexOptions.Compiled | RegexOptions.IgnoreCase);
                    while (m != null && m.Value != null &&
                        m.Value.Trim() != string.Empty)
                    {
                        if (!hash.Contains(m.Value))
                        {
                            Console.WriteLine(m.Value);
                            using (StreamWriter sw =
                            new StreamWriter("mail.txt", true))
                            {
                                sw.WriteLine(m.Value);
                                sw.Close();
                            }
                            hash.Add(m.Value, string.Empty);
                        }
                        m = m.NextMatch();
                    }
 
 
                }
 
            }
 
 
 
 
 
 
 
 
            Console.Write("完成");
 
            Console.ReadLine();
        }
    }
 
 
 
 
 
    public class SRWebClient
 
    {
        public CookieCollection cookie;
        public SRWebClient()
        {
            cookie = null;
        }
 
 
        #region 從包含多個 Cookie 的字符串讀取到 CookieCollection 集合中
 
        private static void AddCookieWithCookieHead(ref CookieCollection cookieCol,
            string cookieHead, string defaultDomain)
        {
            if (cookieCol == null) cookieCol = new CookieCollection();
            if (cookieHead == null) return;
            string[] ary = cookieHead.Split(';');
            for (int i = 0; i < ary.Length; i++)
            {
                Cookie ck = GetCookieFromString(ary[i].Trim(), defaultDomain);
                if (ck != null)
                {
                    cookieCol.Add(ck);
                }
            }
        }
        #endregion
 
 
        #region 讀取某一個 Cookie 字符串到 Cookie 變量中
 
        private static Cookie GetCookieFromString(string cookieString,
            string defaultDomain)
        {
            string[] ary = cookieString.Split(',');
            Hashtable hs = new Hashtable();
            for (int i = 0; i < ary.Length; i++)
            {
                string s = ary[i].Trim();
                int index = s.IndexOf("=");
                if (index > 0)
                {
                    hs.Add(s.Substring(0, index), s.Substring(index + 1));
                }
            }
            Cookie ck = new Cookie();
            foreach (object Key in hs.Keys)
            {
                if (Key.ToString() == "path") ck.Path = hs[Key].ToString();
 
 
                else if (Key.ToString() == "expires")
 
                {
                    //ck.Expires=DateTime.Parse(hs[Key].ToString();
                }
                else if (Key.ToString() == "domain")
                    ck.Domain = hs[Key].ToString();
                else
                {
                    ck.Name = Key.ToString();
                    ck.Value = hs[Key].ToString();
                }
            }
            if (ck.Name == "") return null;
            if (ck.Domain == "") ck.Domain = defaultDomain;
            return ck;
        }
        #endregion
 
 
 
 
 
 
 
 
        /**/
 
        /// <TgData>
        ///     <Alias>下載Web源代碼</Alias>
        /// </TgData>
        public string DownloadHtml(string URL, bool CreateCookie)
        {
            try
            {
 HttpWebRequest request =HttpWebRequest.Create(URL) as HttpWebRequest;
                if (cookie != null)
                {
                    request.CookieContainer = new CookieContainer();
                    request.CookieContainer.Add(cookie);
                }
                request.AllowAutoRedirect = false;
                //request.MaximumAutomaticRedirections = 3;
                request.Timeout = 20000;
 
 
                HttpWebResponse res = (HttpWebResponse)request.GetResponse();
 
                string r = "";
 
 
                System.IO.StreamReader S1 =
 
                    new System.IO.StreamReader(res.GetResponseStream(),
                        System.Text.Encoding.Default);
                try
                {
                    r = S1.ReadToEnd();
                    if (CreateCookie)
                        cookie = res.Cookies;
                }
                catch (Exception er)
                {
                    //Log l = new Log();
                    //l.writelog("下載Web錯誤", er.ToString());
                }
                finally
                {
                    res.Close();
                    S1.Close();
                }
 
 
                return r;
 
            }
 
 
            catch
 
            {
 
 
            }
 
 
 
            return string.Empty;
 
        }
 
 
        /**/
 
        /// <TgData>
        ///     <Alias>下載文件</Alias>
        /// </TgData>
        public long DownloadFile(string FileURL,
            string FileSavePath, bool CreateCookie)
        {
            long Filelength = 0;
            HttpWebRequest req =
                HttpWebRequest.Create(FileURL) as HttpWebRequest;
 
 
            if (cookie != null)
 
            {
                req.CookieContainer = new CookieContainer();
                req.CookieContainer.Add(cookie);
            }
            req.AllowAutoRedirect = true;
 
 
            HttpWebResponse res =
 
                req.GetResponse() as HttpWebResponse;
            if (CreateCookie)
                cookie = res.Cookies;
            System.IO.Stream stream = res.GetResponseStream();
            try
            {
                Filelength = res.ContentLength;
 
 
                byte[] b = new byte[512];
 
 
 
                int nReadSize = 0;
 
                nReadSize = stream.Read(b, 0, 512);
 
 
                System.IO.FileStream fs =
 
                    System.IO.File.Create(FileSavePath);
                try
                {
                    while (nReadSize > 0)
                    {
                        fs.Write(b, 0, nReadSize);
                        nReadSize = stream.Read(b, 0, 512);
                    }
                }
                finally
                {
                    fs.Close();
                }
            }
            catch (Exception er)
            {
                //Log l = new Log();
                //l.writelog("下載文件錯誤", er.ToString());
            }
            finally
            {
                res.Close();
                stream.Close();
            }
 
 
            return Filelength;
 
        }
 
 
        /**/
 
        /// <TgData>
        ///     <Alias>提交數據</Alias>
        /// </TgData>
        public string Request(string RequestPageURL,
            RequestData Data, bool CreateCookie)
        {
            StreamReader reader = null;
            HttpWebResponse response = null;
            HttpWebRequest request = null;
            try
            {
                string StrUrl = RequestPageURL;
                request = HttpWebRequest.Create(StrUrl) as HttpWebRequest;
 
 
                string postdata = Data.GetData();
 
                request.Referer = RequestPageURL;
                request.AllowAutoRedirect = false;
                request.UserAgent =
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2;"+
                    "SV1; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
                request.Timeout = 20000;
 
 
                if (cookie != null)
 
                {
                    request.CookieContainer = new CookieContainer();
                    request.CookieContainer.Add(cookie);
                }
 
 
                Uri u = new Uri(StrUrl);
 
 
 
                if (postdata.Length > 0) //包含要提交的數據 就使用Post方式
 
                {
                    //做爲表單請求
                    request.ContentType =
                        "application/x-www-form-urlencoded";
                    request.Method = "POST";        //方式就是Post
 
 
                    //把提交的數據換成字節數組
 
                    Byte[] B = System.Text.Encoding.UTF8.GetBytes(postdata);
                    request.ContentLength = B.Length;
 
 
                    //開始提交數據
 
                    System.IO.Stream SW = request.GetRequestStream();
                    SW.Write(B, 0, B.Length);
                    SW.Close();
                }
 
 
                response = request.GetResponse() as HttpWebResponse;
 
                if (CreateCookie)
                    //cookie = response.Cookies;
                    AddCookieWithCookieHead(ref cookie,
                        response.Headers["Set-Cookie"],
                        request.RequestUri.Host);
                reader = new StreamReader(response.GetResponseStream(),
                    Encoding.Default);
 
 
                return reader.ReadToEnd();
 
            }
            catch (Exception ex)
            {
                string x = ex.StackTrace;
            }
            finally
            {
                if (response != null)
                    response.Close();
            }
 
 
            return string.Empty;
 
        }
 
 
 
 
 
        public bool PostDownload(RequestData Data, out string file)
 
        {
            file = null;
            StreamReader reader = null;
            HttpWebResponse response = null;
            HttpWebRequest request = null;
            try
            {
                string StrUrl =
                     "http://www.imobile.com.cn/wapdiyringdownload.php";
                request = HttpWebRequest.Create(StrUrl) as HttpWebRequest;
 
 
                string postdata = Data.GetData();
 
                request.Referer = StrUrl;
                request.AllowAutoRedirect = false;
                request.UserAgent =
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2;"+
                    "SV1; Maxthon; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
                request.Timeout = 20000;
 
 
                if (cookie != null)
 
                {
                    request.CookieContainer = new CookieContainer();
                    request.CookieContainer.Add(cookie);
                }
 
 
                Uri u = new Uri(StrUrl);
 
 
 
                if (postdata.Length > 0) //包含要提交的數據 就使用Post方式
 
                {
                    request.ContentType =
                        "application/x-www-form-urlencoded"; //做爲表單請求
                    request.Method = "POST";        //方式就是Post
 
 
                    //把提交的數據換成字節數組
 
                    Byte[] B = System.Text.Encoding.UTF8.GetBytes(postdata);
                    request.ContentLength = B.Length;
 
 
                    System.IO.Stream SW =
 
                        request.GetRequestStream(); //開始提交數據
                    SW.Write(B, 0, B.Length);
                    SW.Close();
                }
 
 
                response = request.GetResponse() as HttpWebResponse;
 
                string des =
                    response.Headers["Content-Disposition"].Trim();
                file = des.Substring(des.IndexOf("filename=") + 9);
                file = new Random().Next(100).ToString() + "/" + file;
 
 
                System.IO.Stream stream = response.GetResponseStream();
 
                try
                {
                    int Filelength = (int)response.ContentLength;
 
 
                    byte[] b = new byte[512];
 
 
 
                    int nReadSize = 0;
 
                    nReadSize = stream.Read(b, 0, 512);
 
 
                    System.IO.FileStream fs =
 
                        System.IO.File.Create("f:/mobileMusic/" + file);
                    try
                    {
                        while (nReadSize > 0)
                        {
                            fs.Write(b, 0, nReadSize);
                            nReadSize = stream.Read(b, 0, 512);
                        }
                    }
                    finally
                    {
                        fs.Close();
                    }
                }
                catch (Exception er)
                {
                    //Log l = new Log();
                    //l.writelog("下載文件錯誤", er.ToString());
                }
                finally
                {
                    response.Close();
                    stream.Close();
                }
            }
            catch (Exception ex)
            {
                string x = ex.StackTrace;
            }
            finally
            {
                if (response != null)
                    response.Close();
            }
            return true;
        }
        #region GetPage
        /// <summary>
        /// 獲取源代碼
        /// </summary>
        /// <param name="url"></param>
        /// <param name="coding"></param>
        /// <param name="TryCount"></param>
        /// <returns></returns>
        public static string GetPage(string url,
            Encoding encoding, int TryCount)
        {
            for (int i = 0; i < TryCount; i++)
            {
                string result = GetPage(url, encoding, null);
                if (result != null && result != string.Empty)
                    return result;
            }
 
 
            return string.Empty;
 
        }
 
 
        /// <summary>
 
        /// 獲取源代碼
        /// </summary>
        /// <param name="url"></param>
        /// <param name="coding"></param>
        /// <returns></returns>
        public static string GetPage(string url, Encoding encoding,
            string cookie)
        {
            HttpWebRequest request = null;
            HttpWebResponse response = null;
            StreamReader reader = null;
            try
            {
                request = (HttpWebRequest)WebRequest.Create(url);
                request.UserAgent =
                    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2;)";
                request.Timeout = 20000;
                request.AllowAutoRedirect = false;
                if (cookie != null)
                    request.Headers["Cookie"] = cookie;
 
 
                response = (HttpWebResponse)request.GetResponse();
 
                if (response.StatusCode == HttpStatusCode.OK &&
                    response.ContentLength < 1024 * 1024)
                {
                    reader =
                        new StreamReader(response.GetResponseStream(), encoding);
                    string html = reader.ReadToEnd();
 
 
                    return html;
 
                }
            }
            catch
            {
            }
            finally
            {
 
 
                if (response != null)
 
                {
                    response.Close();
                    response = null;
                }
                if (reader != null)
                    reader.Close();
 
 
                if (request != null)
 
                    request = null;
 
 
            }
 
 
 
            return string.Empty;
 
        }
        #endregion
    }
 
 
    public class RequestData
 
    {
        Hashtable hash = new Hashtable();
 
 
        public RequestData()
 
        {
 
 
        }
 
 
 
        public string GetData()
 
        {
            string r = "";
 
 
            foreach (string key in hash.Keys)
 
            {
                if (r.Length > 0) r += "&";
                r += key + "=" + hash[key];
            }
 
 
            return r;
 
        }
 
 
        public void AddField(string Field, string Value)
 
        {
            hash[Field] = Value;
        }
 
 
 
 
 
    }
 
}
View Code

C# 過濾HTML標籤的幾種方法 精華整理哦正則表達式

/**/ ///   <summary>
///   去除HTML標記
///   </summary>
///   <param   name="NoHTML">包括HTML的源碼   </param>
///   <returns>已經去除後的文字</returns>
public static string NoHTML(string Htmlstring)
{
  //刪除腳本
  Htmlstring = Regex.Replace(Htmlstring, @"<script[^>]*?>.*?</script>", "",
    RegexOptions.IgnoreCase);
  //刪除HTML
  Htmlstring = Regex.Replace(Htmlstring, @"<(.[^>]*)>", "",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"([\r\n])[\s]+", "",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"-->", "", RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"<!--.*", "", RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&(quot|#34);", "\"",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&(amp|#38);", "&",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&(lt|#60);", "<",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&(gt|#62);", ">",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&(nbsp|#160);", "   ",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&(iexcl|#161);", "\xa1",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&(cent|#162);", "\xa2",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&(pound|#163);", "\xa3",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&(copy|#169);", "\xa9",
    RegexOptions.IgnoreCase);
  Htmlstring = Regex.Replace(Htmlstring, @"&#(\d+);", "",
    RegexOptions.IgnoreCase);
 
  Htmlstring.Replace("<", "");
  Htmlstring.Replace(">", "");
  Htmlstring.Replace("\r\n", "");
  Htmlstring = HttpContext.Current.Server.HtmlEncode(Htmlstring).Trim();
  return Htmlstring;
}
/**/ ///提取HTML代碼中文字的C#函數
///   <summary>
///   去除HTML標記
///   </summary>
///   <param   name="strHtml">包括HTML的源碼   </param>
///   <returns>已經去除後的文字</returns>
using System;
using System.Text.RegularExpressions;
public class StripHTMLTest
{
  public static void Main()
  {
    string s = StripHTML(
      "<HTML><HEAD><TITLE>中國石龍信息平臺</TITLE>< /HEAD><BODY>faddfs龍信息平臺</BODY></HTML>");
    Console.WriteLine(s);
  }
  public static string StripHTML(string strHtml)
  {
    string[]aryReg =
    {
      @"<script[^>]*?>.*?</script>",
      @"<(\/\s*)?!?((\w+:)?\w+)(\w+(\s*=?\s*(([""'])(\\["
        "'tbnr]|[^\7])*?\7|\w+)|.{0})|\s)*?(\/\s*)?>", @"([\r\n])[\s]+", @
        "&(quot|#34);", @"&(amp|#38);", @"&(lt|#60);", @"&(gt|#62);", @
        "&(nbsp|#160);", @"&(iexcl|#161);", @"&(cent|#162);", @"&(pound|#163);",
        @"&(copy|#169);", @"&#(\d+);", @"-->", @"<!--.*\n"
    };
    string[]aryRep =
    {
      "", "", "", "\"", "&", "<", ">", "   ", "\xa1",  //chr(161),
      "\xa2",  //chr(162),
      "\xa3",  //chr(163),
      "\xa9",  //chr(169),
      "", "\r\n", ""
    };
    string newReg = aryReg[0];
    string strOutput = strHtml;
    for (int i = 0; i < aryReg.Length; i++)
    {
      Regex regex = new Regex(aryReg[i], RegexOptions.IgnoreCase);
      strOutput = regex.Replace(strOutput, aryRep[i]);
    }
    strOutput.Replace("<", "");
    strOutput.Replace(">", "");
    strOutput.Replace("\r\n", "");
    return strOutput;
  }
}
寫一個靜態方法移除HTML標籤
#region
///移除HTML標籤
/**/ ///   <summary>
///   移除HTML標籤
///   </summary>
///   <param   name="HTMLStr">HTMLStr</param>
public static string ParseTags(string HTMLStr)
{
  return System.Text.RegularExpressions.Regex.Replace(HTMLStr, "<[^>]*>", "");
}
#endregion
   
///   取出文本中的圖片地址
#region
///   取出文本中的圖片地址
/**/ ///   <summary>
///   取出文本中的圖片地址
///   </summary>
///   <param   name="HTMLStr">HTMLStr</param>
public static string GetImgUrl(string HTMLStr)
{
  string str = string.Empty;
  string sPattern = @"^<img\s+[^>]*>";
  Regex r = new Regex(@"<img\s+[^>]*\s*src\s*=\s*([']?)(?<url>\S+)'?[^>]*>",
    RegexOptions.Compiled);
  Match m = r.Match(HTMLStr.ToLower());
  if (m.Success)
    str = m.Result("${url}");
  return str;
}
#endregion
 
View Code

C# 獲取IIS站點及虛擬目錄信息算法

參考信息:http://msdn.microsoft.com/en-us/library/ms524578.aspx
using System;
using System.DirectoryServices;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            DirectoryEntry rootEntry = new DirectoryEntry("IIS://localhost/w3svc");
            int siteID = 1;
            
            foreach (DirectoryEntry entry in rootEntry.Children)
            {
                if (entry.SchemaClassName.Equals("IIsWebServer", StringComparison.OrdinalIgnoreCase))
                {
                    Console.WriteLine("Name: {0}", entry.Name);
                    Console.WriteLine("Path: {0}", IISWorker.GetWebsitePhysicalPath(entry));
                    Console.WriteLine("ServerBindings: {0}", entry.Properties["ServerBindings"].Value);
                    Console.WriteLine();
                    DirectoryEntry virEntry = new DirectoryEntry(entry.Path + "/ROOT");
                    foreach (DirectoryEntry entryVirtual in virEntry.Children)
                    {
                        if (entryVirtual.SchemaClassName.Equals("IIsWebVirtualDir", StringComparison.OrdinalIgnoreCase))
                        {
                            Console.WriteLine("SchemaClassName: {0}", entryVirtual.SchemaClassName);
                            Console.WriteLine("Name: {0}", entryVirtual.Name);
                            Console.WriteLine("Path: {0}", entryVirtual.Properties["Path"].Value);
                            Console.WriteLine();
                        }
                    }
                    int ID = Convert.ToInt32(entry.Name);
                    if (ID >= siteID)
                    {
                        siteID = ID + 1;
                    }
                }
            }
        }
    }
    public class IISWorker
    {
        /// <summary>
        /// 獲得網站的物理路徑
        /// </summary>
        /// <param name="rootEntry">網站節點</param>
        /// <returns></returns>
        public static string GetWebsitePhysicalPath(DirectoryEntry rootEntry)
        {
            string physicalPath = "";
            foreach (DirectoryEntry childEntry in rootEntry.Children)
            {
                if ((childEntry.SchemaClassName == "IIsWebVirtualDir") && (childEntry.Name.ToLower() == "root"))
                {
                    if (childEntry.Properties["Path"].Value != null)
                    {
                        physicalPath = childEntry.Properties["Path"].Value.ToString();
                    }
                    else
                    {
                        physicalPath = "";
                    }
                }
            }
            return physicalPath;
        }
    }
}
 
View Code

C# 獲取網頁中匹配代碼的正則 (得到字符串中開始和結束字符串中間得值)數據庫

<div>1div</div>
<a>1a</a>
<p>1p</p>
<p>2p</p>
<div>2div</div>
<a>2a</a>
<p>3p</p>
<p>4p</p>
<a>3a</a>
<p>5p</p>
<div>3div</div>
<a>4a</a>
<p>6p</p>
<span>1span</span>

如今的問題是:有N多DIV,N多p,N多A標籤以及最多1個span,想只獲取全部p裏的內容以及最後一個span裏的內容(其中獲取P的內容有一個條件,那就是隻有前面有一個A標籤的P的內容纔會被獲取),span或許有或許沒有,若是有就獲取,若是沒有就不獲取求:
C#的正則表達式
using System.Text.RegularExpressions;
 
 

代碼
 string restult = "";
            foreach(Match m in Regex.Matches(str ,@"(?ins)(?<=(</a>\s*<(?<mark>p[^>]*>)|<(?<mark>span)[^>]*>))[\s\S]+?(?=</\k<mark>)"))
            {
                restult +=m.Value;//就是你要的結果

                MessageBox.Show(m.Value);
            }
 
或是用
foreach(Match m in Regex.Matches(yourHtml,@"(?is)(</a>\s*<(?<mark>p[^>]*>)|<(?<mark>span)[^>]*>)(?<data>[\s\S]+?)</\k<mark>"))
{
    m.Groups["data"].Value;//
}
 
或是>>>>>>得到字符串中開始和結束字符串中間得值

代碼
  #region 得到字符串中開始和結束字符串中間得值
        /// <summary>
        /// 得到字符串中開始和結束字符串中間得值
        /// </summary>
        /// <param name="begin">開始匹配標記</param>
        /// <param name="end">結束匹配標記</param>
        /// <param name="html">Html字符串</param>
        /// <returns>返回中間字符串</returns>
        public static MatchCollection GetMidValue(string begin, string end, string html)
        {
            Regex reg = new Regex("(?<=(" + begin + "))[.\\s\\S]*?(?=(" + end + "))", RegexOptions.Multiline | RegexOptions.Singleline);
            return reg.Matches(html);
        }
        #endregion
 
 

代碼
 /// <summary> 
        /// 得到字符串中開始和結束字符串中間得值 
        /// </summary> 
        /// <param name="str"></param> 
        /// <param name="s">開始</param> 
        /// <param name="e">結束</param> 
        /// <returns></returns> 
        private string getvalue(string str, string start, string end) 
        {
            Regex rg = new Regex("(?<=(" + start + "))[.\\s\\S]*?(?=(" + end + "))", RegexOptions.Multiline | RegexOptions.Singleline); 
     
            return rg.Match(str).Value;            
        }
 
 
 
//正則抽取單個Table , 可根據table內的某個標識字符, good !
 若是僅僅是以「會員資料」這樣的作爲參考標識,用我上面寫的稍稍改造就能夠了,問題的複雜在於,若是以「00」或者「444」作爲參考標識,就要考慮到<table>標籤嵌套的問題,既要保證取包含參考標識的最內層<table>,又要保證<table>和</table>配對匹配
 

代碼
 Match mm = Regex.Match(html, @"<table[^>]*>(((<table[^>]*>(?<o>)|</table>(?<-o>)|(?!</?table)[\s\S])*)(?(o)(?!)))\b" + "會員資料" + @"\b(?:(?!<table[^>]*>)[\s\S])*?(((<table[^>]*>(?<o>)|</table>(?<-o>)|(?!</?table)[\s\S])*)(?(o)(?!)))</table>", RegexOptions.IgnoreCase);
 
輸入的參考標識中若是有正則中有特殊意義的字符,須要對其進行預處理,另外須要在程序中進行異常處理,這個本身處理下吧
若是源字符串中同時多處出現輸入的參考標識,這裏取第一個出現的參考標識所在的<table>
 
 
//正則抽取單個Table中 , 解析tb中的內容.........

代碼
 Match mm = Regex.Match(html, @"<table[^>]*>(((<table[^>]*>(?<o>)|</table>(?<-o>)|(?!</?table)[\s\S])*)(?(o)(?!)))\b" + "會員輸贏資料" + @"\b(?:(?!<table[^>]*>)[\s\S])*?(((<table[^>]*>(?<o>)|</table>(?<-o>)|(?!</?table)[\s\S])*)(?(o)(?!)))</table>", RegexOptions.IgnoreCase);
            if (mm.Success)
            {
                //MessageBox.Show(mm.Value);

                //MatchCollection mdd = GetMidValue("<td", "</td>", mm.Value);
                //foreach (Match m in mdd)
                //{
                //    for (int i = 1; i < m.Groups.Count; i++)
                //    {                       
                //        restult += m.Groups[i].Value;//就是你要的結果
                //    }                    
                //}

                MatchCollection mc = Regex.Matches(mm.Value, @"<td[^>]*>\s*(?<content>[\s\S]*?)\s*</td>", RegexOptions.IgnoreCase);
                foreach(Match m in mc)
                {
                    for (int i = 1; i < m.Groups.Count; i++)
                    {
                        restult += m.Groups[i].Value + "\n";
                    }
                }
                MessageBox.Show(restult);
            }
 
View Code

C# 生成Google Sitemapexpress

Google Sitemaps是Google的一個和網站管理員相關的工具,有點像BLOG的RSS功能,是一個方便本身的服務,若是你們(互聯網上全部的信息源)都採用了這種方式提交本身的更新的話,Google就不再用派出那麼多爬蟲辛辛苦苦的處處亂竄了,任何一個站點,只要有更新,便會自動「通知」Google,方便Google進行索引。
看看Google 本身的介紹。
通常來講,有兩種類型的 sitemap。 第一種類型的 sitemap 是一般按部分列出您網站網頁的 HTML 網頁,用於幫助用戶查找所需的信息。
XML Sitemap - 一般稱爲 Sitemap(使用大寫 S),是您向 Google 提供有關您網站信息的一種方法。 這正是咱們要在本文中討論的 Sitemap 類型。
用最簡單的話來講,Sitemap 就是您網站上網頁的列表。 建立並提交 Sitemap 有助於確保 Google 知道您網站上的全部網頁,包括 Google 的正常抓取過程可能沒法找到的網址。
若是網站屬於下列狀況,那麼 Sitemap 會特別實用:

       網站含動態內容。

       網站有不容易被 Googlebot 在抓取過程當中發現的頁面,若有大量富 AJAX 或 Flash 內容的頁面。

       網站爲新網站且指向網站的連接很少。 (Googlebot 會跟隨連接從一個網頁到另外一個網頁抓取網絡,所以,若是您的網站沒有很好地連接,咱們可能很難發現它。)

       網站有大量內容頁存檔,這些內容頁相互沒有很好地連接,或根本就沒有連接。
您還能夠使用 Sitemap 向 Google 提供有關您網頁的其餘信息,包括:

       您網站上網頁的更改頻率。 例如:您可能每日都更新產品頁,但每幾個月才更新"個人簡介"頁一次。

       各網頁上次修改的日期。

       您網站上各網頁的相對重要性。 例如:主頁的相對重要性爲 1.0,類別頁的相對重要性爲 0.8,而我的博客條目或產品頁的相對重要性則爲 0.5。這個優先級只是說明特定網址相對於您網站上其餘網址的重要性,並不會影響您的網頁在搜索結果中的排名。
Sitemap 會向 Google 提供有關您網站的其餘信息,從而使咱們抓取網絡的常規方法獲得補充。 咱們但願 Sitemap 可幫助咱們更及時地抓取您網站的更多內容,但咱們不能保證您 Sitemap 中的網址會添加到 Google 索引中。 網站不會因提交 Sitemap 而受處處罰。
當你的Sitemap 放在一個文件太大時(1000個連接 以上或者文件超過10M),就須要把它分紅多個Sitemap 文件,並創建 SitemapIndex 文件來提交。
Sitemap 索引文件
Sitemap 索引文件的 XML 格式與 Sitemap 文件的 XML 格式很是類似。 Sitemap 索引文件使用如下 XML 標記:

       <sitemapindex> - 文件頭尾的父標記。

       <sitemap> - 文件中列出的每一個 Sitemap 的父標記(<sitemapindex> 的子標記)

       <loc> - Sitemap 的位置(<sitemap> 的子標記)

       <lastmod> - Sitemap 的上次修改日期(可選)
 我提供了2個靜態函數CreateSitemap 和 CreateSitemapIndex 來生成 Sitemap 文件和SitemapIndex 文件,雖然很簡單,當想用的時候能夠不用本身寫了J。你能夠修改一下,寫一個適合生成本身網站Sitemap的小工具,用起來就方便了。
 看看分別生成的Sitemap 文件和SitemapIndex 文件的截圖:
  


 
聲明:
本文版權歸做者和CS 程序員之窗全部,歡迎轉載,轉載必須保留如下版權信息,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。
做者:Starts_2000
出處:http://www.csharpwin.com CS 程序員之窗。
你能夠無償使用或修改提供的源代碼,但請保留源代碼中的版權信息,詳情請查看:
CS程序員之窗開源協議(http://www.csharpwin.com/csol.html)。
 
View Code

C# 蜘蛛

    "蜘蛛"(Spider)是Internet上一種頗有用的程序,搜索引擎利用蜘蛛程序將Web頁面收集到數據庫,企業利用蜘蛛程序監視競爭對手的網站並跟蹤變更,我的用戶用蜘蛛程序下載Web頁面以便脫機使用,開發者利用蜘蛛程序掃描本身的Web檢查無效的連接……對於不一樣的用戶,蜘蛛程序有不一樣的用途。那麼,蜘蛛程序究竟是怎樣工做的呢? 
   
    蜘蛛是一種半自動的程序,就象現實當中的蜘蛛在它的Web(蜘蛛網)上旅行同樣,蜘蛛程序也按照相似的方式在Web連接織成的網上旅行。蜘蛛程序之因此是半自動的,是由於它老是須要一個初始連接(出發點),但此後的運行狀況就要由它本身決定了,蜘蛛程序會掃描起始頁面包含的連接,而後訪問這些連接指向的頁面,再分析和追蹤那些頁面包含的連接。從理論上看,最終蜘蛛程序會訪問到Internet上的每個頁面,由於Internet上幾乎每個頁面老是被其餘或多或少的頁面引用。 
   
    本文介紹如何用C#語言構造一個蜘蛛程序,它可以把整個網站的內容下載到某個指定的目錄,程序的運行界面如圖一。你能夠方便地利用本文提供的幾個核心類構造出本身的蜘蛛程序。 
  

 
  圖1 
   
   
    C#特別適合於構造蜘蛛程序,這是由於它已經內置了HTTP訪問和多線程的能力,而這兩種能力對於蜘蛛程序來講都是很是關鍵的。下面是構造一個蜘蛛程序要解決的關鍵問題: 
   
    ⑴ HTML分析:須要某種HTML解析器來分析蜘蛛程序遇到的每個頁面。 
   
    ⑵ 頁面處理:須要處理每個下載獲得的頁面。下載獲得的內容可能要保存到磁盤,或者進一步分析處理。 
   
    ⑶ 多線程:只有擁有多線程能力,蜘蛛程序才能真正作到高效。 
   
    ⑷ 肯定什麼時候完成:不要小看這個問題,肯定任務是否已經完成並不簡單,尤爲是在多線程環境下。 
   
    1、HTML解析 
   
    C#語言自己不包含解析HTML的能力,但支持XML解析;不過,XML有着嚴格的語法,爲XML設計的解析器對HTML來講根本沒用,由於HTML的語法要寬鬆得多。爲此,咱們須要本身設計一個HTML解析器。本文提供的解析器是高度獨立的,你能夠方便地將它用於其它用C#處理HTML的場合。 
   
    本文提供的HTML解析器由ParseHTML類實現,使用很是方便:首先建立該類的一個實例,而後將它的Source屬性設置爲要解析的HTML文檔: 
   
  ParseHTML parse = new ParseHTML(); 
  parse.Source = "<p>Hello World</p>"; 
     接下來就能夠利用循環來檢查HTML文檔包含的全部文本和標記。一般,檢查過程能夠從一個測試Eof方法的while循環開始: 
   
  while(!parse.Eof()) 
  { 
  char ch = parse.Parse(); 
   
   
   
    Parse方法將返回HTML文檔包含的字符--它返回的內容只包含那些非HTML標記的字符,若是遇到了HTML標記,Parse方法將返回0值,表示如今遇到了一個HTML標記。遇到一個標記以後,咱們能夠用GetTag()方法來處理它。 
   
  if(ch==0) 
  { 
  HTMLTag tag = parse.GetTag(); 
  } 
   
   
   
    通常地,蜘蛛程序最重要的任務之一就是找出各個HREF屬性,這能夠藉助C#的索引功能完成。例如,下面的代碼將提取出HREF屬性的值(若是存在的話)。 
   
  Attribute href = tag["HREF"]; 
  string link = href.Value; 
   
   
   
    得到Attribute對象以後,經過Attribute.Value能夠獲得該屬性的值。 
   
  2、處理HTML頁面 
   
    下面來看看如何處理HTML頁面。首先要作的固然是下載HTML頁面,這能夠經過C#提供的HttpWebRequest類實現: 
   
  HttpWebRequest request = (HttpWebRequest)WebRequest.Create(m_uri); 
  response = request.GetResponse(); 
  stream = response.GetResponseStream(); 
   
   
   
    接下來咱們就從request建立一個stream流。在執行其餘處理以前,咱們要先肯定該文件是二進制文件仍是文本文件,不一樣的文件類型處理方式也不一樣。下面的代碼肯定該文件是否爲二進制文件。 
   
  if( !response.ContentType.ToLower().StartsWith("text/") ) 
  { 
  SaveBinaryFile(response); 
  return null; 
  } 
  string buffer = "",line; 
   
   
   
    若是該文件不是文本文件,咱們將它做爲二進制文件讀入。若是是文本文件,首先從stream建立一個StreamReader,而後將文本文件的內容一行一行加入緩衝區。 
   
  reader = new StreamReader(stream); 
  while( (line = reader.ReadLine())!=null ) 
  { 
  buffer+=line+"\r\n"; 
  } 
   
   
   
    裝入整個文件以後,接着就要把它保存爲文本文件。 
   
  SaveTextFile(buffer); 
   
   
   
    下面來看看這兩類不一樣文件的存儲方式。 
   
    二進制文件的內容類型聲明不以"text/"開頭,蜘蛛程序直接把二進制文件保存到磁盤,沒必要進行額外的處理,這是由於二進制文件不包含HTML,所以也不會再有須要蜘蛛程序處理的HTML連接。下面是寫入二進制文件的步驟。 
   
    首先準備一個緩衝區臨時地保存二進制文件的內容。 byte []buffer = new byte[1024]; 
   
   
   
    接下來要肯定文件保存到本地的路徑和名稱。若是要把一個myhost.com網站的內容下載到本地的c:\test文件夾,二進制文件的網上路徑和名稱是http://myhost.com/images/logo.gif,則本地路徑和名稱應當是c:\test\images\logo.gif。與此同時,咱們還要確保c:\test目錄下已經建立了images子目錄。這部分任務由convertFilename方法完成。 
   
  string filename = convertFilename( response.ResponseUri ); 
   
   
   
    convertFilename方法分離HTTP地址,建立相應的目錄結構。肯定了輸出文件的名字和路徑以後就能夠打開讀取Web頁面的輸入流、寫入本地文件的輸出流。 
   
  Stream outStream = File.Create( filename ); 
  Stream inStream = response.GetResponseStream(); 
   
   
   
    接下來就能夠讀取Web文件的內容並寫入到本地文件,這能夠經過一個循環方便地完成。 
   
  int l; 
  do 
  { 
  l = inStream.Read(buffer,0, 
  buffer.Length); 
  if(l>0) 
  outStream.Write(buffer,0,l); 
  } while(l>0); 
   
   
   
    寫入整個文件以後,關閉輸入流、輸出流。 
   
  outStream.Close(); 
  inStream.Close(); 
   
   
   
    比較而言,下載文本文件更容易一些。文本文件的內容類型老是以"text/"開頭。假設文件已被下載並保存到了一個字符串,這個字符串能夠用來分析網頁包含的連接,固然也能夠保存爲磁盤上的文件。下面代碼的任務就是保存文本文件。 
   
  string filename = convertFilename( m_uri ); 
  StreamWriter outStream = new StreamWriter( filename ); 
  outStream.Write(buffer); 
  outStream.Close(); 
   
   
   
    在這裏,咱們首先打開一個文件輸出流,而後將緩衝區的內容寫入流,最後關閉文件。 
     3、多線程 
   
    多線程使得計算機看起來就象可以同時執行一個以上的操做,不過,除非計算機包含多個處理器,不然,所謂的同時執行多個操做僅僅是一種模擬出來的效果--靠計算機在多個線程之間快速切換達到"同時"執行多個操做的效果。通常而言,只有在兩種狀況下多線程才能事實上提升程序運行的速度。第一種狀況是計算機擁有多個處理器,第二種狀況是程序常常要等待某個外部事件。 
   
    對於蜘蛛程序來講,第二種狀況正是它的典型特徵之一,它每發出一個URL請求,老是要等待文件下載完畢,而後再請求下一個URL。若是蜘蛛程序可以同時請求多個URL,顯然可以有效地減小總下載時間。 
   
    爲此,咱們用DocumentWorker類封裝全部下載一個URL的操做。每當一個DocumentWorker的實例被建立,它就進入循環,等待下一個要處理的URL。下面是DocumentWorker的主循環: 
   
  while(!m_spider.Quit ) 
  { 
  m_uri = m_spider.ObtainWork(); 
   
  m_spider.SpiderDone.WorkerBegin(); 
  string page = GetPage(); 
  if(page!=null) 
  ProcessPage(page); 
  m_spider.SpiderDone.WorkerEnd(); 
  } 
   
   
   
    這個循環將一直運行,直至Quit標記被設置成了true(當用戶點擊"Cancel"按鈕時,Quit標記就被設置成true)。在循環以內,咱們調用ObtainWork獲取一個URL。ObtainWork將一直等待,直到有一個URL可用--這要由其餘線程解析文檔並尋找連接才能得到。Done類利用WorkerBegin和WorkerEnd方法來肯定什麼時候整個下載操做已經完成。 
   
    從圖一能夠看出,蜘蛛程序容許用戶本身肯定要使用的線程數量。在實踐中,線程的最佳數量受許多因素影響。若是你的機器性能較高,或者有兩個處理器,能夠設置較多的線程數量;反之,若是網絡帶寬、機器性能有限,設置太多的線程數量其實不必定可以提升性能。 
   
    4、任務完成了嗎? 
   
    利用多個線程同時下載文件有效地提升了性能,但也帶來了線程管理方面的問題。其中最複雜的一個問題是:蜘蛛程序什麼時候纔算完成了工做?在這裏咱們要藉助一個專用的類Done來判斷。 
   
    首先有必要說明一下"完成工做"的具體含義。只有當系統中不存在等待下載的URL,並且全部工做線程都已經結束其處理工做時,蜘蛛程序的工做纔算完成。也就是說,完成工做意味着已經沒有等待下載和正在下載的URL。 
   
    Done類提供了一個WaitDone方法,它的功能是一直等待,直到Done對象檢測到蜘蛛程序已完成工做。下面是WaitDone方法的代碼。 
   
  public void WaitDone() 
  { 
  Monitor.Enter(this); 
  while ( m_activeThreads>0 ) 
  { 
  Monitor.Wait(this); 
  } 
  Monitor.Exit(this); 
  } 
   
   
   
    WaitDone方法將一直等待,直到再也不有活動的線程。但必須注意的是,下載開始的最初階段也沒有任何活動的線程,因此很容易形成蜘蛛程序一開始就當即中止的現象。爲解決這個問題,咱們還須要另外一個方法WaitBegin來等待蜘蛛程序進入"正式的"工做階段。通常的調用次序是:先調用WaitBegin,再接着調用WaitDone,WaitDone將等待蜘蛛程序完成工做。下面是WaitBegin的代碼: 
   
  public void WaitBegin() 
  { 
  Monitor.Enter(this); 
  while ( !m_started ) 
  { 
  Monitor.Wait(this); 
  } 
  Monitor.Exit(this); 
  } 
   
   
   
    WaitBegin方法將一直等待,直到m_started標記被設置。m_started標記是由WorkerBegin方法設置的。工做線程在開始處理各個URL之時,會調用WorkerBegin;處理結束時調用WorkerEnd。WorkerBegin和WorkerEnd這兩個方法幫助Done對象肯定當前的工做狀態。下面是WorkerBegin方法的代碼: 
   
  public void WorkerBegin() 
  { 
  Monitor.Enter(this); 
  m_activeThreads++; 
  m_started = true; 
  Monitor.Pulse(this); 
  Monitor.Exit(this); 
  } 
   
   
   
    WorkerBegin方法首先增長當前活動線程的數量,接着設置m_started標記,最後調用Pulse方法以通知(可能存在的)等待工做線程啓動的線程。如前所述,可能等待Done對象的方法是WaitBegin方法。每處理完一個URL,WorkerEnd方法會被調用: 
   
  public void WorkerEnd() 
  { 
  Monitor.Enter(this); 
  m_activeThreads--; 
  Monitor.Pulse(this); 
  Monitor.Exit(this); 
  } 
   
   
   
    WorkerEnd方法減少m_activeThreads活動線程計數器,調用Pulse釋放可能在等待Done對象的線程--如前所述,可能在等待Done對象的方法是WaitDone方法。 
   
    結束語:本文介紹了開發Internet蜘蛛程序的基礎知識,下面提供的源代碼將幫助你進一步深刻理解本文的主題。這裏提供的代碼很是靈活,你能夠方便地將它用於本身的程序。
 
View Code

C# 抓取網頁裏面的全部連接!

這幾天偶爾看見了,C#抓取網頁的連接。的代碼。感受當時作的很簡單。呵呵。也沒多考慮什麼過程。先把簡單的給你們拿出來看看。若是你們有什麼意見或者有好的方法能夠共同交流。謝謝!一下僅供參考:
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using System.Xml;
using System.Net;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;

namespace text
{
    public partial class Form1 : Form
    {
        string strCode;
        ArrayList alLinks;
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text == "")
            {
                MessageBox.Show("請輸入網址");
                return;
            }
            string strURL = textBox1.Text.ToString().Trim();
            if (strURL.Substring(0, 7) != @"http://")
            {
                strURL = @"http://" + strURL;
            }
            MessageBox.Show("正在獲取頁面代碼,請稍後...");
            strCode = GetPageSource(strURL);
            MessageBox.Show("正在提取超連接,請稍侯...");
            alLinks = GetHyperLinks(strCode);
            MessageBox.Show("正在寫入文件,請稍侯...");
            WriteToXml(strURL, alLinks);
        }
        // 獲取指定網頁的HTML代碼 
        public static string GetPageSource(string URL)
        {
            Uri uri = new Uri(URL);
            HttpWebRequest hwReq = (HttpWebRequest)WebRequest.Create(uri);
            HttpWebResponse hwRes = (HttpWebResponse)hwReq.GetResponse();
            hwReq.Method = "Get";
            hwReq.KeepAlive = false;
            StreamReader reader = new StreamReader(hwRes.GetResponseStream(), System.Text.Encoding.GetEncoding("GB2312"));
            return reader.ReadToEnd();
        }
        // 提取HTML代碼中的網址 
        public static ArrayList GetHyperLinks(string htmlCode)
        {
            ArrayList al = new ArrayList();
            string strRegex = @"http://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";
            Regex r = new Regex(strRegex, RegexOptions.IgnoreCase);
            MatchCollection m = r.Matches(htmlCode);
            for (int i = 0; i <= m.Count - 1; i++)
            {
                bool rep = false;
                string strNew = m[i].ToString();
                // 過濾重複的URL 
                foreach (string str in al)
                {
                    if (strNew == str)
                    {
                        rep = true;
                        break;
                    }
                }
                if (!rep) al.Add(strNew);
            }
            al.Sort();
            return al;
        }
        // 把網址寫入xml文件 
        static void WriteToXml(string strURL, ArrayList alHyperLinks)
        {
            XmlTextWriter writer = new XmlTextWriter("HyperLinks.xml", Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            writer.WriteStartDocument(false);
            writer.WriteDocType("HyperLinks", null, "urls.dtd", null);
            writer.WriteComment("提取自" + strURL + "的超連接");
            writer.WriteStartElement("HyperLinks");
            writer.WriteStartElement("HyperLinks", null);
            writer.WriteAttributeString("DateTime", DateTime.Now.ToString());

            foreach (string str in alHyperLinks)
            {
                string title = GetDomain(str);
                string body = str;
                writer.WriteElementString(title, null, body);
            }
            writer.WriteEndElement();
            writer.WriteEndElement();
            writer.Flush();
            writer.Close();
        }
        // 獲取網址的域名後綴 
        static string GetDomain(string strURL)
        {
            string retVal;
            string strRegex = @"(\.com/|\.net/|\.cn/|\.org/|\.gov/)";
            Regex r = new Regex(strRegex, RegexOptions.IgnoreCase);
            Match m = r.Match(strURL);
            retVal = m.ToString();
            strRegex = @"\.|/$";
            retVal = Regex.Replace(retVal, strRegex, "").ToString();
            if (retVal == "")
                retVal = "other";
            return retVal;
        }
    }
}
 
View Code

C# 抓取網頁上的文字,保存到數據庫

<
string content = string.Empty;
string str = string.Format(http://www.qingxi360/info/168.htm);
 WebRequest wrq = WebRequest.Create(str); WebResponse wrs = wrq.GetResponse();
 using (StreamReader dr = new StreamReader(wrs.GetResponseStream(), Encoding.GetEncoding("gb2312")))
{
 content = dr.ReadToEnd();//這就是所有內容 int start = content.IndexOf("相關搜索");
 int end = content.IndexOf("");
string StrOldHtml = content.Substring(start, end - start);
StrOldHtml = StrOldHtml.Replace("相關搜索", "");
StrOldHtml = StrOldHtml.Replace(" ", "");
content.add(content);
OK,處理完畢,只是在線交流,無其餘用途
在這裏只是簡單的演示下,有事能夠給我留言。謝謝
 
View Code

C#根據網址獲取域名,目錄名,文件名函數

#region 獲取網址中域名,目錄,文件名的函數
public string GetUrlDomainName(string strHtmlPagePath)
{
string p = @"http://[^/.]*/.(?<domain>[^/]*)"; 
Regex reg = new Regex(p,RegexOptions.IgnoreCase); 
Match m = reg.Match(strHtmlPagePath); 
return m.Groups["domain"].Value;
}
public string[] GetUrlFolerName(string strHtmlPagePath)
{
//抓取網址字符串中的文件目錄

int at = 0;
int start = 0; 
int notei=0;
int endi=0;
int[] myIntArray =new int[10];
string[] ArrayFolderName=null;
string NewFolderName;
while((start < strHtmlPagePath.Length) && (at > -1))
{
at = strHtmlPagePath.IndexOf('/', start);
if (at == -1) break; 
myIntArray[notei]=at;
start = at+1;
notei = notei+1;
endi=at;
}
ArrayFolderName=new string[notei-1];
for(int i=0;i<notei;i++)
{
if(myIntArray[i]>0)
{
if (myIntArray[i+1]>0)
{
NewFolderName=strHtmlPagePath.Substring(myIntArray[i]+1,myIntArray[i+1]-myIntArray[i]-1);
ArrayFolderName.SetValue(NewFolderName,i);
}
}
}
return ArrayFolderName; 
}
public string GetUrlFileName(string strHtmlPagePath) 
{
//抓取網址字符串中的文件名稱
int at = 0;
int start = 0; 
int notei=0;
int endi=0;
int[] myIntArray = new int[10]; 
string NewFileName="";
while((start < strHtmlPagePath.Length) && (at > -1))
{
at = strHtmlPagePath.IndexOf('/', start);
if (at == -1) break; 
myIntArray[notei]=at;
start = at+1;
notei = notei+1;
endi=at;
}
for(int i=0;i<notei;i++)
{
if(myIntArray[i]>0)
{
if (myIntArray[i+1]==0)
{
NewFileName=strHtmlPagePath.Substring(myIntArray[i]+1,strHtmlPagePath.Length-myIntArray[i]-1);

}
}
}
return NewFileName.ToLower(); 

}
#endregion
 
View Code

C#構造蜘蛛程序介紹-HTML解析

「蜘蛛」(Spider)是一種半自動的程序,就象現實當中的蜘蛛在它的Web(蜘蛛網)上旅行同樣,蜘蛛程序也按照相似的方式在Web連接織成的網上旅行。蜘蛛程序之因此是半自動的,是由於它老是須要一個初始連接(出發點),但此後的運行狀況就要由它本身決定了,蜘蛛程序會掃描起始頁面包含的連接,而後訪問這些連接指向的頁面,再分析和追蹤那些頁面包含的連接。從理論上看,最終蜘蛛程序會訪問到Internet上的每個頁面,由於Internet上幾乎每個頁面老是被其餘或多或少的頁面引用。
本文介紹如何用C#語言構造一個蜘蛛程序,它可以把整個網站的內容下載到某個指定的目錄,程序的運行界面如圖一。你能夠方便地利用本文提供的幾個核心類構造出本身的蜘蛛程序。

 
圖1
C#特別適合於構造蜘蛛程序,這是由於它已經內置了HTTP訪問和多線程的能力,而這兩種能力對於蜘蛛程序來講都是很是關鍵的。下面是構造一個蜘蛛程序要解決的關鍵問題:
⑴ HTML分析:須要某種HTML解析器來分析蜘蛛程序遇到的每個頁面;
⑵ 頁面處理:須要處理每個下載獲得的頁面。下載獲得的內容可能要保存到磁盤,或者進一步分析處理;
⑶ 多線程:只有擁有多線程能力,蜘蛛程序才能真正作到高效;
⑷ 肯定什麼時候完成:不要小看這個問題,肯定任務是否已經完成並不簡單,尤爲是在多線程環境下。
1、HTML解析
C#語言自己不包含解析HTML的能力,但支持XML解析;不過,XML有着嚴格的語法,爲XML設計的解析器對HTML來講根本沒用,由於HTML的語法要寬鬆得多。爲此,咱們須要本身設計一個HTML解析器。本文提供的解析器是高度獨立的,你能夠方便地將它用於其它用C#處理HTML的場合。
本文提供的HTML解析器由ParseHTML類實現,使用很是方便:首先建立該類的一個實例,而後將它的Source屬性設置爲要解析的HTML文檔:
ParseHTML parse = new ParseHTML();parse.Source = "Hello World";
接下來就能夠利用循環來檢查HTML文檔包含的全部文本和標記。一般,檢查過程能夠從一個測試Eof方法的while循環開始:
while(!parse.Eof()){char ch = parse.Parse();
Parse方法將返回HTML文檔包含的字符--它返回的內容只包含那些非HTML標記的字符,若是遇到了HTML標記,Parse方法將返回0值,表示如今遇到了一個HTML標記。遇到一個標記以後,咱們能夠用GetTag()方法來處理它。
if(ch==0){HTMLTag tag = parse.GetTag();}
通常地,蜘蛛程序最重要的任務之一就是找出各個HREF屬性,這能夠藉助C#的索引功能完成。例如,下面的代碼將提取出HREF屬性的值(若是存在的話)。
Attribute href = tag["HREF"];string link = href.Value;
得到Attribute對象以後,經過Attribute.Value能夠獲得該屬性的值。
2、處理HTML頁面
下面來看看如何處理HTML頁面。首先要作的固然是下載HTML頁面,這能夠經過C#提供的HttpWebRequest類實現:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(m_uri);response = request.GetResponse();stream = response.GetResponseStream();
接下來咱們就從request建立一個stream流。在執行其餘處理以前,咱們要先肯定該文件是二進制文件仍是文本文件,不一樣的文件類型處理方式也不一樣。下面的代碼肯定該文件是否爲二進制文件。
if( !response.ContentType.ToLower().StartsWith("text/") ){SaveBinaryFile(response);return null;}string buffer = "",line;
若是該文件不是文本文件,咱們將它做爲二進制文件讀入。若是是文本文件,首先從stream建立一個StreamReader,而後將文本文件的內容一行一行加入緩衝區。
reader = new StreamReader(stream);while( (line = reader.ReadLine())!=null ){buffer+=line+"\r\n";}
裝入整個文件以後,接着就要把它保存爲文本文件。
SaveTextFile(buffer);
下面來看看這兩類不一樣文件的存儲方式。
二進制文件的內容類型聲明不以"text/"開頭,蜘蛛程序直接把二進制文件保存到磁盤,沒必要進行額外的處理,這是由於二進制文件不包含HTML,所以也不會再有須要蜘蛛程序處理的HTML連接。下面是寫入二進制文件的步驟。
首先準備一個緩衝區臨時地保存二進制文件的內容。 byte []buffer = new byte[1024];
接下來要肯定文件保存到本地的路徑和名稱。若是要把一個myhost.com網站的內容下載到本地的c:\test文件夾,二進制文件的網上路徑和名稱是http://myhost.com/images/logo.gif,則本地路徑和名稱應當是c:\test\images\logo.gif。與此同時,咱們還要確保c:\test目錄下已經建立了images子目錄。這部分任務由convertFilename方法完成。
string filename = convertFilename( response.ResponseUri );
convertFilename方法分離HTTP地址,建立相應的目錄結構。肯定了輸出文件的名字和路徑以後就能夠打開讀取Web頁面的輸入流、寫入本地文件的輸出流。
Stream outStream = File.Create( filename );Stream inStream = response.GetResponseStream();
接下來就能夠讀取Web文件的內容並寫入到本地文件,這能夠經過一個循環方便地完成。
int l;do{l = inStream.Read(buffer,0,buffer.Length);if(l>0)outStream.Write(buffer,0,l);} while(l>0);
寫入整個文件以後,關閉輸入流、輸出流。
outStream.Close();inStream.Close();
比較而言,下載文本文件更容易一些。文本文件的內容類型老是以"text/"開頭。假設文件已被下載並保存到了一個字符串,這個字符串能夠用來分析網頁包含的連接,固然也能夠保存爲磁盤上的文件。下面代碼的任務就是保存文本文件。
string filename = convertFilename( m_uri );StreamWriter outStream = new StreamWriter( filename );outStream.Write(buffer);outStream.Close();
在這裏,咱們首先打開一個文件輸出流,而後將緩衝區的內容寫入流,最後關閉文件。
 
View Code

C#過濾html標籤的方法

//過濾內容裏的html標籤
    private string checkStr(string html)
    {
        System.Text.RegularExpressions.Regex regex1 = new System.Text.RegularExpressions.Regex(@"<script[\s\S]+</script *>", RegexOptions.IgnoreCase);
        Regex regex2 = new Regex(@" href *= *[\s\S]*script *:", RegexOptions.IgnoreCase);
        Regex regex3 = new Regex(@" no[\s\S]*=", RegexOptions.IgnoreCase);
        Regex regex4 = new Regex(@"<iframe[\s\S]+</iframe *>", RegexOptions.IgnoreCase);
        Regex regex5 = new Regex(@"<frameset[\s\S]+</frameset *>", RegexOptions.IgnoreCase);
        Regex regex6 = new Regex(@"\<img[^\>]+\>", RegexOptions.IgnoreCase);

        Regex regex7 = new Regex(@"</p>", RegexOptions.IgnoreCase);
        Regex regex8 = new Regex(@"<p>", RegexOptions.IgnoreCase);
        Regex regex9 = new Regex(@"<[^>]*>", RegexOptions.IgnoreCase);
        html = regex1.Replace(html, ""); //過濾<script></script>標記 
        html = regex2.Replace(html, ""); //過濾href=javascript: (<A>) 屬性 網管網bitsCN.com 
        html = regex3.Replace(html, " _disibledevent="); //過濾其它控件的on...事件 
        html = regex4.Replace(html, ""); //過濾iframe 
        html = regex5.Replace(html, ""); //過濾frameset 
        html = regex6.Replace(html, ""); //過濾frameset 
        html = regex7.Replace(html, ""); //過濾frameset 
        html = regex8.Replace(html, ""); //過濾frameset 
        html = regex9.Replace(html, "");
        html = html.Replace(" ", "");

        html = html.Replace("</strong>", "");
        html = html.Replace("<strong>", "");
        return html;
    }
 
View Code

C#抓取和分析網頁的類

主要功能有:
1、提取網頁的純文本,去全部html標籤和javascript代碼
2、提取網頁的連接,包括href和frame及iframe
3、提取網頁的title等(其它的標籤可依此類推,正則是同樣的)
4、能夠實現簡單的表單提交及cookie保存
/*
* Author:Sunjoy at CCNU
* 若是您改進了這個類請發一份代碼給我(ccnusjy 在gmail.com)
*/
using System;
using System.Data;
using System.Configuration;
using System.Net;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
/// <summary>
/// 網頁類
/// </summary>
public class WebPage
{
 #region 私有成員
 private Uri m_uri; //網址
 private List<Link> m_links; //此網頁上的連接
 private string m_title; //此網頁的標題
 private string m_html; //此網頁的HTML代碼
 private string m_outstr; //此網頁可輸出的純文本
 private bool m_good; //此網頁是否可用
 private int m_pagesize; //此網頁的大小
 private static Dictionary<string, CookieContainer> webcookies = new Dictionary<string, CookieContainer>();//存放全部網頁的Cookie
 private string m_post; //此網頁的登錄頁須要的POST數據
 private string m_loginurl; //此網頁的登錄頁
 #endregion
 #region 私有方法
 /// <summary>
 /// 這私有方法從網頁的HTML代碼中分析出連接信息
 /// </summary>
 /// <returns>List<Link></returns>
 private List<Link> getLinks()
 {
 if (m_links.Count == 0)
 {
 Regex[] regex = new Regex[2];
 regex[0] = new Regex("(?m)<a[^><]+href=(/"|')?(?<url>([^>/"'//s)])+)(/"|')?[^>]*>(?<text>(//w|//W)*?)</", RegexOptions.Multiline | RegexOptions.IgnoreCase);
 regex[1] = new Regex("<[i]*frame[^><]+src=(/"|')?(?<url>([^>/"'//s)])+)(/"|')?[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase);
 for (int i = 0; i < 2; i++)
 {
 Match match = regex[i].Match(m_html);
 while (match.Success)
 {
 try
 {
 string url = new Uri(m_uri, match.Groups["url"].Value).AbsoluteUri;
 string text = "";
 if (i == 0) text = new Regex("(<[^>]+>)|(//s)|( )|&|/"", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(match.Groups["text"].Value, "");
 Link link = new Link(url, text);
 m_links.Add(link);
 }
 catch(Exception ex){Console.WriteLine(ex.Message); };
 match = match.NextMatch();
 }
 }
 }
 return m_links;
 }
 
 /// <summary>
 /// 此私有方法從一段HTML文本中提取出必定字數的純文本
 /// </summary>
 /// <param name="instr">HTML代碼</param>
 /// <param name="firstN">提取從頭數多少個字</param>
 /// <param name="withLink">是否要連接裏面的字</param>
 /// <returns>純文本</returns>
 private string getFirstNchar(string instr, int firstN, bool withLink)
 {
 if (m_outstr == "")
 {
 m_outstr = instr.Clone() as string;
 m_outstr = new Regex(@"(?m)<script[^>]*>(/w|/W)*?</script[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase ).Replace(m_outstr, "");
 m_outstr = new Regex(@"(?m)<style[^>]*>(/w|/W)*?</style[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase ).Replace(m_outstr, "");
 m_outstr = new Regex(@"(?m)<select[^>]*>(/w|/W)*?</select[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase ).Replace(m_outstr, "");
 if (!withLink) m_outstr = new Regex(@"(?m)<a[^>]*>(/w|/W)*?</a[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
 Regex objReg = new System.Text.RegularExpressions.Regex("(<[^>]+?>)| ", RegexOptions.Multiline | RegexOptions.IgnoreCase);
 m_outstr = objReg.Replace(m_outstr, "");
 Regex objReg2 = new System.Text.RegularExpressions.Regex("(//s)+", RegexOptions.Multiline | RegexOptions.IgnoreCase);
 m_outstr = objReg2.Replace(m_outstr, " ");
 }
 return m_outstr.Length > firstN ? m_outstr.Substring(0, firstN) : m_outstr;
 }
 /// <summary>
 /// 此私有方法返回一個IP地址對應的無符號整數
 /// </summary>
 /// <param name="x">IP地址</param>
 /// <returns></returns>
 private uint getuintFromIP(IPAddress x)
 {
 Byte[] bt = x.GetAddressBytes();
 uint i = (uint)(bt[0] * 256 * 256 * 256);
 i += (uint)(bt[1] * 256 * 256);
 i += (uint)(bt[2] * 256);
 i += (uint)(bt[3]);
 return i;
 }
 #endregion
 #region 公有文法
 /// <summary>
 /// 此公有方法提取網頁中必定字數的純文本,包括連接文字
 /// </summary>
 /// <param name="firstN">字數</param>
 /// <returns></returns>
 public string getContext(int firstN)
 {
 return getFirstNchar(m_html, firstN, true);
 }
 /// <summary>
 /// 此公有方法提取網頁中必定字數的純文本,不包括連接文字
 /// </summary>
 /// <param name="firstN"></param>
 /// <returns></returns>
 public string getContextWithOutLink(int firstN)
 {
 return getFirstNchar(m_html, firstN, false);
 }
 /// <summary>
 /// 此公有方法從本網頁的連接中提取必定數量的連接,該連接的URL知足某正則式
 /// </summary>
 /// <param name="pattern">正則式</param>
 /// <param name="count">返回的連接的個數</param>
 /// <returns>List<Link></returns>
 public List<Link> getSpecialLinksByUrl(string pattern,int count)
 {
 if(m_links.Count==0)getLinks();
 List<Link> SpecialLinks = new List<Link>();
 List<Link>.Enumerator i;
 i = m_links.GetEnumerator();
 int cnt = 0;
 while (i.MoveNext() && cnt<count)
 {
 if (new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase ).Match(i.Current.url).Success)
 {
 SpecialLinks.Add(i.Current);
 cnt++;
 }
 } 
 return SpecialLinks;
 }
 /// <summary>
 /// 此公有方法從本網頁的連接中提取必定數量的連接,該連接的文字知足某正則式
 /// </summary>
 /// <param name="pattern">正則式</param>
 /// <param name="count">返回的連接的個數</param>
 /// <returns>List<Link></returns>
 public List<Link> getSpecialLinksByText(string pattern,int count)
 {
 if (m_links.Count == 0) getLinks();
 List<Link> SpecialLinks = new List<Link>();
 List<Link>.Enumerator i;
 i = m_links.GetEnumerator();
 int cnt = 0;
 while (i.MoveNext() && cnt < count)
 {
 if (new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase ).Match(i.Current.text).Success)
 {
 SpecialLinks.Add(i.Current);
 cnt++;
 }
 }
 return SpecialLinks;
 }
 /// <summary>
 /// 此公有方法得到全部連接中在必定IP範圍的連接
 /// </summary>
 /// <param name="_ip_start">起始IP</param>
 /// <param name="_ip_end">終止IP</param>
 /// <returns></returns>
 public List<Link> getSpecialLinksByIP(string _ip_start, string _ip_end)
 {
 IPAddress ip_start = IPAddress.Parse(_ip_start);
 IPAddress ip_end = IPAddress.Parse(_ip_end);
 if (m_links.Count == 0) getLinks();
 List<Link> SpecialLinks = new List<Link>();
 List<Link>.Enumerator i;
 i = m_links.GetEnumerator();
 while (i.MoveNext())
 {
 IPAddress ip;
 try
 {
 ip = Dns.GetHostEntry(new Uri(i.Current.url).Host).AddressList[0];
 }
 catch { continue; }
 if(getuintFromIP(ip)>=getuintFromIP(ip_start) && getuintFromIP(ip)<=getuintFromIP(ip_end))
 {
 SpecialLinks.Add(i.Current);
 }
 }
 return SpecialLinks;
 }
 /// <summary>
 /// 這公有方法提取本網頁的純文本中知足某正則式的文字
 /// </summary>
 /// <param name="pattern">正則式</param>
 /// <returns>返回文字</returns>
 public string getSpecialWords(string pattern)
 {
 if (m_outstr == "") getContext(Int16.MaxValue);
 Regex regex = new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase );
 Match mc=regex.Match(m_outstr);
 if (mc.Success)
 return mc.Groups[1].Value;
 return string.Empty;
 }
 #endregion
 #region 構造函數
 
 private void Init(string _url)
 {
 
 try
 {
 m_uri = new Uri(_url);
 m_links = new List<Link>();
 m_html = "";
 m_outstr = "";
 m_title = "";
 m_good = true;
 if (_url.EndsWith(".rar") || _url.EndsWith(".dat") || _url.EndsWith(".msi"))
 {
 m_good = false;
 return;
 }
 HttpWebRequest rqst = (HttpWebRequest)WebRequest.Create(m_uri);
 rqst.AllowAutoRedirect = true;
 rqst.MaximumAutomaticRedirections = 3;
 rqst.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
 rqst.KeepAlive = true;
 rqst.Timeout = 30000;
 lock (WebPage.webcookies)
 {
 if (WebPage.webcookies.ContainsKey(m_uri.Host))
 rqst.CookieContainer = WebPage.webcookies[m_uri.Host];
 else
 {
 CookieContainer cc = new CookieContainer();
 WebPage.webcookies[m_uri.Host] = cc;
 rqst.CookieContainer = cc;
 }
 }
 HttpWebResponse rsps = (HttpWebResponse)rqst.GetResponse();
 Stream sm = rsps.GetResponseStream();
 if (!rsps.ContentType.ToLower().StartsWith("text/") || rsps.ContentLength > 1 << 22)
 {
 rsps.Close();
 m_good = false;
 return;
 }
 Encoding cding = System.Text.Encoding.Default;
 string contenttype=rsps.ContentType.ToLower();
 int ix = contenttype.IndexOf("charset=");
 if (ix != -1)
 {
 try
 {
 cding = System.Text.Encoding.GetEncoding(rsps.ContentType.Substring(ix + "charset".Length + 1));
 }
 catch
 {
 cding = Encoding.Default;
 }
 m_html = new StreamReader(sm, cding).ReadToEnd();
 }
 else
 {
 m_html = new StreamReader(sm, cding).ReadToEnd();
 Regex regex = new Regex("charset=(?<cding>[^=]+)?/"",RegexOptions.IgnoreCase);
 string strcding = regex.Match(m_html).Groups["cding"].Value;
 try
 {
 cding = Encoding.GetEncoding(strcding);
 }
 catch{
 cding = Encoding.Default;
 }
 byte[] bytes=Encoding.Default.GetBytes(m_html.ToCharArray());
 m_html = cding.GetString(bytes);
 if (m_html.Split('?').Length > 100)
 {
 m_html=Encoding.Default.GetString(bytes);
 }
 }
 
 m_pagesize = m_html.Length;
 m_uri = rsps.ResponseUri;
 rsps.Close();
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message+m_uri.ToString());
 m_good = false;
 
 }
 }
 public WebPage(string _url)
 {
 string uurl = "";
 try
 {
 uurl = Uri.UnescapeDataString(_url);
 _url = uurl;
 }
 catch { };
 Regex re = new Regex("(?<h>[^/x00-/xff]+)");
 Match mc = re.Match(_url);
 if (mc.Success)
 {
 string han = mc.Groups["h"].Value;
 _url = _url.Replace(han, System.Web.HttpUtility.UrlEncode(han, Encoding.GetEncoding("GB2312")));
 }
 Init(_url);
 }
 public WebPage(string _url, string _loginurl, string _post)
 {
 string uurl = "";
 try
 {
 uurl = Uri.UnescapeDataString(_url);
 _url = uurl;
 }
 catch { };
 Regex re = new Regex("(?<h>[^/x00-/xff]+)");
 Match mc = re.Match(_url);
 if (mc.Success)
 {
 string han = mc.Groups["h"].Value;
 _url = _url.Replace(han, System.Web.HttpUtility.UrlEncode(han, Encoding.GetEncoding("GB2312")));
 }
 if (_loginurl.Trim() == "" || _post.Trim() == "" || WebPage.webcookies.ContainsKey(new Uri(_url).Host))
 {
 Init(_url);
 }
 else
 {
 #region 登錄
 string indata = _post;
 m_post = _post;
 m_loginurl = _loginurl;
 byte[] bytes = Encoding.Default.GetBytes(_post);
 CookieContainer myCookieContainer = new CookieContainer();
 try
 {
 //新建一個CookieContainer來存放Cookie集合 
 HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(_loginurl);
 //新建一個HttpWebRequest 
 myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
 myHttpWebRequest.AllowAutoRedirect = false;
 myHttpWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
 myHttpWebRequest.Timeout = 60000;
 myHttpWebRequest.KeepAlive = true;
 myHttpWebRequest.ContentLength = bytes.Length;
 myHttpWebRequest.Method = "POST";
 myHttpWebRequest.CookieContainer = myCookieContainer;
 //設置HttpWebRequest的CookieContainer爲剛纔創建的那個myCookieContainer 
 Stream myRequestStream = myHttpWebRequest.GetRequestStream();
 myRequestStream.Write(bytes, 0, bytes.Length);
 myRequestStream.Close();
 HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
 foreach (Cookie ck in myHttpWebResponse.Cookies)
 {
 myCookieContainer.Add(ck);
 }
 myHttpWebResponse.Close();
 }
 catch
 {
 Init(_url);
 return;
 }
 #endregion
 #region 登錄後再訪問頁面
 try
 {
 m_uri = new Uri(_url);
 m_links = new List<Link>();
 m_html = "";
 m_outstr = "";
 m_title = "";
 m_good = true;
 if (_url.EndsWith(".rar") || _url.EndsWith(".dat") || _url.EndsWith(".msi"))
 {
 m_good = false;
 return;
 }
 HttpWebRequest rqst = (HttpWebRequest)WebRequest.Create(m_uri);
 rqst.AllowAutoRedirect = true;
 rqst.MaximumAutomaticRedirections = 3;
 rqst.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
 rqst.KeepAlive = true;
 rqst.Timeout = 30000;
 rqst.CookieContainer = myCookieContainer;
 lock (WebPage.webcookies)
 {
 WebPage.webcookies[m_uri.Host] = myCookieContainer;
 }
 HttpWebResponse rsps = (HttpWebResponse)rqst.GetResponse();
 Stream sm = rsps.GetResponseStream();
 if (!rsps.ContentType.ToLower().StartsWith("text/") || rsps.ContentLength > 1 << 22)
 {
 rsps.Close();
 m_good = false;
 return;
 }
 Encoding cding = System.Text.Encoding.Default;
 int ix = rsps.ContentType.ToLower().IndexOf("charset=");
 if (ix != -1)
 {
 try
 {
 cding = System.Text.Encoding.GetEncoding(rsps.ContentType.Substring(ix + "charset".Length + 1));
 }
 catch
 {
 cding = Encoding.Default;
 }
 }
 m_html = new StreamReader(sm, cding).ReadToEnd();
 m_pagesize = m_html.Length;
 m_uri = rsps.ResponseUri;
 rsps.Close();
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message+m_uri.ToString());
 m_good = false;
 
 }
 #endregion
 }
 }
 #endregion
 #region 屬性
 /// <summary>
 /// 經過此屬性可得到本網頁的網址,只讀
 /// </summary>
 public string URL
 {
 get
 {
 return m_uri.AbsoluteUri;
 }
 }
 /// <summary>
 /// 經過此屬性可得到本網頁的標題,只讀
 /// </summary>
 public string Title
 {
 get
 {
 if (m_title == "")
 {
 Regex reg = new Regex(@"(?m)<title[^>]*>(?<title>(?:/w|/W)*?)</title[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase );
 Match mc = reg.Match(m_html);
 if (mc.Success)
 m_title= mc.Groups["title"].Value.Trim();
 }
 return m_title;
 }
 }
 
 /// <summary>
 /// 此屬性得到本網頁的全部連接信息,只讀
 /// </summary>
 public List<Link> Links
 {
 get
 {
 if (m_links.Count == 0) getLinks();
 return m_links;
 }
 }
 /// <summary>
 /// 此屬性返回本網頁的所有純文本信息,只讀
 /// </summary>
 public string Context
 {
 get
 {
 if (m_outstr == "") getContext(Int16.MaxValue);
 return m_outstr;
 }
 }
 /// <summary>
 /// 此屬性得到本網頁的大小
 /// </summary>
 public int PageSize
 {
 get
 {
 return m_pagesize;
 }
 }
 /// <summary>
 /// 此屬性得到本網頁的全部站內連接
 /// </summary>
 public List<Link> InsiteLinks
 {
 get
 {
 return getSpecialLinksByUrl("^http://"+m_uri.Host,Int16.MaxValue);
 }
 }
 /// <summary>
 /// 此屬性表示本網頁是否可用
 /// </summary>
 public bool IsGood
 {
 get
 {
 return m_good;
 }
 }
 /// <summary>
 /// 此屬性表示網頁的所在的網站
 /// </summary>
 public string Host
 {
 get
 {
 return m_uri.Host;
 }
 }
 
 /// <summary>
 /// 此網頁的登錄頁所需的POST數據
 /// </summary>
 public string PostStr
 {
 get
 {
 return m_post;
 }
 }
 /// <summary>
 /// 此網頁的登錄頁
 /// </summary>
 public string LoginURL
 {
 get
 {
 return m_loginurl;
 }
 }
 #endregion
}
/// <summary>
/// 連接類
/// </summary>
public class Link
{
 public string url; //連接網址
 public string text; //連接文字
 public Link(string _url, string _text)
 {
 url = _url;
 text = _text;
 }
}
View Code

C#抓取和分析網頁的類(提取、正文、內容、連接)

抓取和分析網頁的類。
主要功能有:
1、提取網頁的純文本,去全部html標籤和javascript代碼
2、提取網頁的連接,包括href和frame及iframe
3、提取網頁的title等(其它的標籤可依此類推,正則是同樣的)
4、能夠實現簡單的表單提交及cookie保存
/*
* Author:Sunjoy at CCNU
* 若是您改進了這個類請發一份代碼給我(ccnusjy 在gmail.com)
*/

using System;
using System.Data;
using System.Configuration;
using System.Net;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
/// <summary>
/// 網頁類
/// </summary>
public class WebPage
{

#region 私有成員
private Uri m_uri; //網址
private List<Link> m_links; //此網頁上的連接
private string m_title; //此網頁的標題
private string m_html; //此網頁的HTML代碼
private string m_outstr; //此網頁可輸出的純文本
private bool m_good; //此網頁是否可用
private int m_pagesize; //此網頁的大小
private static Dictionary<string, CookieContainer> webcookies = new Dictionary<string, CookieContainer>();//存放全部網頁的Cookie
private string m_post; //此網頁的登錄頁須要的POST數據
private string m_loginurl; //此網頁的登錄頁
#endregion


#region 私有方法
/// <summary>
/// 這私有方法從網頁的HTML代碼中分析出連接信息
/// </summary>
/// <returns>List<Link></returns>
private List<Link> getLinks()
{
if (m_links.Count == 0)
{
Regex[] regex = new Regex[2];
regex[0] = new Regex("(?m)<a[^><]+href=(\"|')?(?<url>([^>\"'\\s)])+)(\"|')?[^>]*>(?<text>(\\w|\\W)*?)</", RegexOptions.Multiline | RegexOptions.IgnoreCase);
regex[1] = new Regex("<[i]*frame[^><]+src=(\"|')?(?<url>([^>\"'\\s)])+)(\"|')?[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase);
for (int i = 0; i < 2; i++)
{
Match match = regex[i].Match(m_html);
while (match.Success)
{
try
{
string url = new Uri(m_uri, match.Groups["url"].Value).AbsoluteUri;
string text = "";
if (i == 0) text = new Regex("(<[^>]+>)|(\\s)|( )|&|\"", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(match.Groups["text"].Value, "");
Link link = new Link(url, text);
m_links.Add(link);
}
catch(Exception ex){Console.WriteLine(ex.Message); };
match = match.NextMatch();
}
}
}
return m_links;
}

/// <summary>
/// 此私有方法從一段HTML文本中提取出必定字數的純文本
/// </summary>
/// <param name="instr">HTML代碼</param>
/// <param name="firstN">提取從頭數多少個字</param>
/// <param name="withLink">是否要連接裏面的字</param>
/// <returns>純文本</returns>
private string getFirstNchar(string instr, int firstN, bool withLink)
{
if (m_outstr == "")
{
m_outstr = instr.Clone() as string;
m_outstr = new Regex(@"(?m)<script[^>]*>(\w|\W)*?</script[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase ).Replace(m_outstr, "");
m_outstr = new Regex(@"(?m)<style[^>]*>(\w|\W)*?</style[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase ).Replace(m_outstr, "");
m_outstr = new Regex(@"(?m)<select[^>]*>(\w|\W)*?</select[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase ).Replace(m_outstr, "");
if (!withLink) m_outstr = new Regex(@"(?m)<a[^>]*>(\w|\W)*?</a[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
Regex objReg = new System.Text.RegularExpressions.Regex("(<[^>]+?>)| ", RegexOptions.Multiline | RegexOptions.IgnoreCase);
m_outstr = objReg.Replace(m_outstr, "");
Regex objReg2 = new System.Text.RegularExpressions.Regex("(\\s)+", RegexOptions.Multiline | RegexOptions.IgnoreCase);
m_outstr = objReg2.Replace(m_outstr, " ");
}
return m_outstr.Length > firstN ? m_outstr.Substring(0, firstN) : m_outstr;
}

/// <summary>
/// 此私有方法返回一個IP地址對應的無符號整數
/// </summary>
/// <param name="x">IP地址</param>
/// <returns></returns>
private uint getuintFromIP(IPAddress x)
{
Byte[] bt = x.GetAddressBytes();
uint i = (uint)(bt[0] * 256 * 256 * 256);
i += (uint)(bt[1] * 256 * 256);
i += (uint)(bt[2] * 256);
i += (uint)(bt[3]);
return i;
}

#endregion


#region 公有文法
/// <summary>
/// 此公有方法提取網頁中必定字數的純文本,包括連接文字
/// </summary>
/// <param name="firstN">字數</param>
/// <returns></returns>
public string getContext(int firstN)
{
return getFirstNchar(m_html, firstN, true);
}

/// <summary>
/// 此公有方法提取網頁中必定字數的純文本,不包括連接文字
/// </summary>
/// <param name="firstN"></param>
/// <returns></returns>
public string getContextWithOutLink(int firstN)
{
return getFirstNchar(m_html, firstN, false);
}

/// <summary>
/// 此公有方法從本網頁的連接中提取必定數量的連接,該連接的URL知足某正則式
/// </summary>
/// <param name="pattern">正則式</param>
/// <param name="count">返回的連接的個數</param>
/// <returns>List<Link></returns>
public List<Link> getSpecialLinksByUrl(string pattern,int count)
{
if(m_links.Count==0)getLinks();
List<Link> SpecialLinks = new List<Link>();
List<Link>.Enumerator i;
i = m_links.GetEnumerator();
int cnt = 0;
while (i.MoveNext() && cnt<count)
{
if (new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase ).Match(i.Current.url).Success)
{
SpecialLinks.Add(i.Current);
cnt++;
}
} 
return SpecialLinks;
}



/// <summary>
/// 此公有方法從本網頁的連接中提取必定數量的連接,該連接的文字知足某正則式
/// </summary>
/// <param name="pattern">正則式</param>
/// <param name="count">返回的連接的個數</param>
/// <returns>List<Link></returns>
public List<Link> getSpecialLinksByText(string pattern,int count)
{
if (m_links.Count == 0) getLinks();
List<Link> SpecialLinks = new List<Link>();
List<Link>.Enumerator i;
i = m_links.GetEnumerator();
int cnt = 0;
while (i.MoveNext() && cnt < count)
{
if (new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase ).Match(i.Current.text).Success)
{
SpecialLinks.Add(i.Current);
cnt++;
}
}
return SpecialLinks;
}
/// <summary>
/// 此公有方法得到全部連接中在必定IP範圍的連接
/// </summary>
/// <param name="_ip_start">起始IP</param>
/// <param name="_ip_end">終止IP</param>
/// <returns></returns>
public List<Link> getSpecialLinksByIP(string _ip_start, string _ip_end)
{
IPAddress ip_start = IPAddress.Parse(_ip_start);
IPAddress ip_end = IPAddress.Parse(_ip_end);
if (m_links.Count == 0) getLinks();
List<Link> SpecialLinks = new List<Link>();
List<Link>.Enumerator i;
i = m_links.GetEnumerator();
while (i.MoveNext())
{
IPAddress ip;
try
{
ip = Dns.GetHostEntry(new Uri(i.Current.url).Host).AddressList[0];
}
catch { continue; }
if(getuintFromIP(ip)>=getuintFromIP(ip_start) && getuintFromIP(ip)<=getuintFromIP(ip_end))
{
SpecialLinks.Add(i.Current);
}
}
return SpecialLinks;
}

/// <summary>
/// 這公有方法提取本網頁的純文本中知足某正則式的文字
/// </summary>
/// <param name="pattern">正則式</param>
/// <returns>返回文字</returns>
public string getSpecialWords(string pattern)
{
if (m_outstr == "") getContext(Int16.MaxValue);
Regex regex = new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase );
Match mc=regex.Match(m_outstr);
if (mc.Success)
return mc.Groups[1].Value;
return string.Empty;
}
#endregion


#region 構造函數

private void Init(string _url)
{

try
{
m_uri = new Uri(_url);
m_links = new List<Link>();
m_html = "";
m_outstr = "";
m_title = "";
m_good = true;
if (_url.EndsWith(".rar") || _url.EndsWith(".dat") || _url.EndsWith(".msi"))
{
m_good = false;
return;
}
HttpWebRequest rqst = (HttpWebRequest)WebRequest.Create(m_uri);
rqst.AllowAutoRedirect = true;
rqst.MaximumAutomaticRedirections = 3;
rqst.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
rqst.KeepAlive = true;
rqst.Timeout = 30000;
lock (WebPage.webcookies)
{
if (WebPage.webcookies.ContainsKey(m_uri.Host))
rqst.CookieContainer = WebPage.webcookies[m_uri.Host];
else
{
CookieContainer cc = new CookieContainer();
WebPage.webcookies[m_uri.Host] = cc;
rqst.CookieContainer = cc;
}
}

HttpWebResponse rsps = (HttpWebResponse)rqst.GetResponse();

Stream sm = rsps.GetResponseStream();
if (!rsps.ContentType.ToLower().StartsWith("text/") || rsps.ContentLength > 1 << 22)
{
rsps.Close();
m_good = false;
return;
}
Encoding cding = System.Text.Encoding.Default;
string contenttype=rsps.ContentType.ToLower();
int ix = contenttype.IndexOf("charset=");
if (ix != -1)
{

try
{
cding = System.Text.Encoding.GetEncoding(rsps.ContentType.Substring(ix + "charset".Length + 1));
}
catch
{
cding = Encoding.Default;
}
m_html = new StreamReader(sm, cding).ReadToEnd();
}
else
{
m_html = new StreamReader(sm, cding).ReadToEnd();
Regex regex = new Regex("charset=(?<cding>[^=]+)?\"",RegexOptions.IgnoreCase);
string strcding = regex.Match(m_html).Groups["cding"].Value;
try
{
cding = Encoding.GetEncoding(strcding);
}
catch{
cding = Encoding.Default;
}
byte[] bytes=Encoding.Default.GetBytes(m_html.ToCharArray());
m_html = cding.GetString(bytes);
if (m_html.Split('?').Length > 100)
{
m_html=Encoding.Default.GetString(bytes);
}
}


m_pagesize = m_html.Length;
m_uri = rsps.ResponseUri;
rsps.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message+m_uri.ToString());
m_good = false;

}
}

public WebPage(string _url)
{
string uurl = "";
try
{
uurl = Uri.UnescapeDataString(_url);
_url = uurl;
}
catch { };
Regex re = new Regex("(?<h>[^\x00-\xff]+)");
Match mc = re.Match(_url);
if (mc.Success)
{
string han = mc.Groups["h"].Value;
_url = _url.Replace(han, System.Web.HttpUtility.UrlEncode(han, Encoding.GetEncoding("GB2312")));
}

Init(_url);
}

public WebPage(string _url, string _loginurl, string _post)
{
string uurl = "";
try
{
uurl = Uri.UnescapeDataString(_url);
_url = uurl;
}
catch { };
Regex re = new Regex("(?<h>[^\x00-\xff]+)");
Match mc = re.Match(_url);
if (mc.Success)
{
string han = mc.Groups["h"].Value;
_url = _url.Replace(han, System.Web.HttpUtility.UrlEncode(han, Encoding.GetEncoding("GB2312")));
}
if (_loginurl.Trim() == "" || _post.Trim() == "" || WebPage.webcookies.ContainsKey(new Uri(_url).Host))
{
Init(_url);
}
else
{
#region 登錄
string indata = _post;
m_post = _post;
m_loginurl = _loginurl;
byte[] bytes = Encoding.Default.GetBytes(_post);
CookieContainer myCookieContainer = new CookieContainer();
try
{

//新建一個CookieContainer來存放Cookie集合 

HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(_loginurl);
//新建一個HttpWebRequest 
myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
myHttpWebRequest.AllowAutoRedirect = false;
myHttpWebRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
myHttpWebRequest.Timeout = 60000;
myHttpWebRequest.KeepAlive = true;
myHttpWebRequest.ContentLength = bytes.Length;
myHttpWebRequest.Method = "POST";
myHttpWebRequest.CookieContainer = myCookieContainer;
//設置HttpWebRequest的CookieContainer爲剛纔創建的那個myCookieContainer 
Stream myRequestStream = myHttpWebRequest.GetRequestStream();
myRequestStream.Write(bytes, 0, bytes.Length);
myRequestStream.Close();
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();

foreach (Cookie ck in myHttpWebResponse.Cookies)
{
myCookieContainer.Add(ck);
}
myHttpWebResponse.Close();
}
catch
{
Init(_url);
return;
}

#endregion

#region 登錄後再訪問頁面
try
{
m_uri = new Uri(_url);
m_links = new List<Link>();
m_html = "";
m_outstr = "";
m_title = "";
m_good = true;
if (_url.EndsWith(".rar") || _url.EndsWith(".dat") || _url.EndsWith(".msi"))
{
m_good = false;
return;
}
HttpWebRequest rqst = (HttpWebRequest)WebRequest.Create(m_uri);
rqst.AllowAutoRedirect = true;
rqst.MaximumAutomaticRedirections = 3;
rqst.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
rqst.KeepAlive = true;
rqst.Timeout = 30000;
rqst.CookieContainer = myCookieContainer;
lock (WebPage.webcookies)
{
WebPage.webcookies[m_uri.Host] = myCookieContainer;
}
HttpWebResponse rsps = (HttpWebResponse)rqst.GetResponse();

Stream sm = rsps.GetResponseStream();
if (!rsps.ContentType.ToLower().StartsWith("text/") || rsps.ContentLength > 1 << 22)
{
rsps.Close();
m_good = false;
return;
}
Encoding cding = System.Text.Encoding.Default;
int ix = rsps.ContentType.ToLower().IndexOf("charset=");
if (ix != -1)
{
try
{
cding = System.Text.Encoding.GetEncoding(rsps.ContentType.Substring(ix + "charset".Length + 1));
}
catch
{
cding = Encoding.Default;
}
}

m_html = new StreamReader(sm, cding).ReadToEnd();

m_pagesize = m_html.Length;
m_uri = rsps.ResponseUri;
rsps.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message+m_uri.ToString());
m_good = false;

}
#endregion
}

}

#endregion


#region 屬性

/// <summary>
/// 經過此屬性可得到本網頁的網址,只讀
/// </summary>
public string URL
{
get
{
return m_uri.AbsoluteUri;
}
}

/// <summary>
/// 經過此屬性可得到本網頁的標題,只讀
/// </summary>
public string Title
{
get
{
if (m_title == "")
{
Regex reg = new Regex(@"(?m)<title[^>]*>(?<title>(?:\w|\W)*?)</title[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase );
Match mc = reg.Match(m_html);
if (mc.Success)
m_title= mc.Groups["title"].Value.Trim();
}
return m_title;
}
}


/// <summary>
/// 此屬性得到本網頁的全部連接信息,只讀
/// </summary>
public List<Link> Links
{
get
{
if (m_links.Count == 0) getLinks();
return m_links;
}
}

/// <summary>
/// 此屬性返回本網頁的所有純文本信息,只讀
/// </summary>
public string Context
{
get
{
if (m_outstr == "") getContext(Int16.MaxValue);
return m_outstr;
}
}

/// <summary>
/// 此屬性得到本網頁的大小
/// </summary>
public int PageSize
{
get
{
return m_pagesize;
}
}
/// <summary>
/// 此屬性得到本網頁的全部站內連接
/// </summary>
public List<Link> InsiteLinks
{
get
{
return getSpecialLinksByUrl("^http://"+m_uri.Host,Int16.MaxValue);
}
}

/// <summary>
/// 此屬性表示本網頁是否可用
/// </summary>
public bool IsGood
{
get
{
return m_good;
}
}
/// <summary>
/// 此屬性表示網頁的所在的網站
/// </summary>
public string Host
{
get
{
return m_uri.Host;
}
}


/// <summary>
/// 此網頁的登錄頁所需的POST數據
/// </summary>
public string PostStr
{
get
{
return m_post;
}
}
/// <summary>
/// 此網頁的登錄頁
/// </summary>
public string LoginURL
{
get
{
return m_loginurl;
}
}
#endregion
}

/// <summary>
/// 連接類
/// </summary>
public class Link
{
public string url; //連接網址
public string text; //連接文字
public Link(string _url, string _text)
{
url = _url;
text = _text;
}
}
View Code

C#抓取網頁上的全部鏈接

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
 
using System.Xml;
using System.Net;
using System.IO;
using System.Collections;
using System.Text.RegularExpressions;
 
 
namespace text
{
    public partial class Form1 : Form
    {
 
        string strCode;
        ArrayList alLinks;
 
        public Form1()
        {
            InitializeComponent();
        }
 
 
        private void button1_Click(object sender, EventArgs e)
        {
            if (textBox1.Text == "")
            {
                MessageBox.Show("請輸入網址");
                return;
            }
            string strURL = textBox1.Text.ToString().Trim();
            if (strURL.Substring(0, 7) != @"http://")
            {
                strURL = @"http://" + strURL;
            }
            MessageBox.Show("正在獲取頁面代碼,請稍後...");
            strCode = GetPageSource(strURL);
            MessageBox.Show("正在提取超連接,請稍侯...");
            alLinks = GetHyperLinks(strCode);
            MessageBox.Show("正在寫入文件,請稍侯...");
            WriteToXml(strURL, alLinks);
        }
 
        // 獲取指定網頁的HTML代碼
        public static string GetPageSource(string URL)
        {
            Uri uri = new Uri(URL);
 
            HttpWebRequest hwReq = (HttpWebRequest)WebRequest.Create(uri);
            HttpWebResponse hwRes = (HttpWebResponse)hwReq.GetResponse();
 
            hwReq.Method = "Get";
 
            hwReq.KeepAlive = false;
 
            StreamReader reader = new StreamReader(hwRes.GetResponseStream(), System.Text.Encoding.GetEncoding("GB2312"));
 
            return reader.ReadToEnd();
        }
        // 提取HTML代碼中的網址
        public static ArrayList GetHyperLinks(string htmlCode)
        {
            ArrayList al = new ArrayList();
 
            string strRegex = @"http://([/w-]+/.)+[/w-]+(/[/w- ./?%&=]*)?";
 
            Regex r = new Regex(strRegex, RegexOptions.IgnoreCase);
            MatchCollection m = r.Matches(htmlCode);
 
            for (int i = 0; i <= m.Count - 1; i++)
            {
                bool rep = false;
                string strNew = m[i].ToString();
 
                // 過濾重複的URL
                foreach (string str in al)
                {
                    if (strNew == str)
                    {
                        rep = true;
                        break;
                    }
                }
 
                if (!rep) al.Add(strNew);
            }
 
            al.Sort();
 
            return al;
        }
        // 把網址寫入xml文件
        static void WriteToXml(string strURL, ArrayList alHyperLinks)
        {
            XmlTextWriter writer = new XmlTextWriter("HyperLinks.xml", Encoding.UTF8);
 
            writer.Formatting = Formatting.Indented;
            writer.WriteStartDocument(false);
            writer.WriteDocType("HyperLinks", null, "urls.dtd", null);
            writer.WriteComment("提取自" + strURL + "的超連接");
            writer.WriteStartElement("HyperLinks");
            writer.WriteStartElement("HyperLinks", null);
            writer.WriteAttributeString("DateTime", DateTime.Now.ToString());
 
 
            foreach (string str in alHyperLinks)
            {
                string title = GetDomain(str);
                string body = str;
                writer.WriteElementString(title, null, body);
            }
 
            writer.WriteEndElement();
            writer.WriteEndElement();
 
            writer.Flush();
            writer.Close();
        }
 
        // 獲取網址的域名後綴
        static string GetDomain(string strURL)
        {
            string retVal;
 
            string strRegex = @"(/.com/|/.net/|/.cn/|/.org/|/.gov/)";
 
            Regex r = new Regex(strRegex, RegexOptions.IgnoreCase);
            Match m = r.Match(strURL);
            retVal = m.ToString();
 
            strRegex = @"/.|/$";
            retVal = Regex.Replace(retVal, strRegex, "").ToString();
 
            if (retVal == "")
                retVal = "other";
 
            return retVal;
        }
    }
}
View Code

C#抓取網站下的連接下的網頁數據怎麼作

1讀取此網站的頁面源代碼
2利用正則取得全部超鏈接的內容
3把取得的超鏈接內容循環,再次操做1,2的步驟,此次2中寫邏輯你想要的 數據
 
---讀取網頁源代碼---
protected void Page_Load(object sender, EventArgs e)
{
string strtemp;
strtemp = GetURLContent("http://go.microsoft.com/fwlink/?LinkId=25817", "utf-8");
//Response.ContentType = "application/x-www-form-urlencoded";
Response.Write(strtemp);
}
string GetURLContent(string url,string EncodingType)
{
string PetiResp = "";
Stream mystream;
//"http://go.microsoft.com/fwlink/?LinkId=25817"
//"utf-8"
System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(url);
req.AllowAutoRedirect = true;
System.Net.HttpWebResponse resp = (System.Net.HttpWebResponse)req.GetResponse();
if (resp.StatusCode == System.Net.HttpStatusCode.OK)
{
mystream = resp.GetResponseStream();
System.Text.Encoding encode = System.Text.Encoding.GetEncoding(EncodingType);
StreamReader readStream = new StreamReader(mystream, encode);
char[] cCont = new char[500];
int count = readStream.Read(cCont, 0, 256);
while (count > 0)
{
// Dumps the 256 characters on a string and displays the string to the console.
String str = new String(cCont, 0, count);
PetiResp += str;
count = readStream.Read(cCont, 0, 256);
}
resp.Close();
return PetiResp;
}
resp.Close();
return null;
}
 
View Code

System.Web.UI抓取網頁連接

using System;
using System.Data;
using System.Configuration;
using System.Net;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Web.UI.MobileControls;
    /// <summary>
    /// 網頁類
    /// </summary>
    public class WebPage
    {
        #region 私有成員
        private Uri m_uri;   //url
        private List<Link> m_links;    //此網頁上的連接
        private string m_title;        //標題
        private string m_html;         //HTML代碼
        private string m_outstr;       //網頁可輸出的純文本
        private bool m_good;           //網頁是否可用
        private int m_pagesize;       //網頁的大小
        private static Dictionary<string, CookieContainer> webcookies = new Dictionary<string, CookieContainer>();//存放全部網頁的Cookie
       
        #endregion
 
        #region 屬性
 
        /// <summary>
        /// 經過此屬性可得到本網頁的網址,只讀
        /// </summary>
        public string URL
        {
            get
            {
                return m_uri.AbsoluteUri;
            }
        }
 
        /// <summary>
        /// 經過此屬性可得到本網頁的標題,只讀
        /// </summary>
        public string Title
        {
            get
            {
                if (m_title == "")
                {
                    Regex reg = new Regex(@"(?m)<title[^>]*>(?<title>(?:\w|\W)*?)</title[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase);
                    Match mc = reg.Match(m_html);
                    if (mc.Success)
                        m_title = mc.Groups["title"].Value.Trim();
                }
                return m_title;
            }
        }
        public string M_html
        {
            get
            {
                if (m_html == null)
                {
                    m_html = "";
                }
                return m_html;
            }
        }
        /// <summary>
        /// 此屬性得到本網頁的全部連接信息,只讀
        /// </summary>
        public List<Link> Links
        {
            get
            {
                if (m_links.Count == 0) getLinks();
                return m_links;
            }
        }
 
 
        /// <summary>
        /// 此屬性返回本網頁的所有純文本信息,只讀
        /// </summary>
        public string Context
        {
            get
            {
                if (m_outstr == "") getContext(Int16.MaxValue);
                return m_outstr;
            }
        }
 
        /// <summary>
        /// 此屬性得到本網頁的大小
        /// </summary>
        public int PageSize
        {
            get
            {
                return m_pagesize;
            }
        }
        /// <summary>
        /// 此屬性得到本網頁的全部站內連接
        /// </summary>
        public List<Link> InsiteLinks
        {
            get
            {
                return getSpecialLinksByUrl("^http://" + m_uri.Host, Int16.MaxValue);
            }
        }
 
        /// <summary>
        /// 此屬性表示本網頁是否可用
        /// </summary>
        public bool IsGood
        {
            get
            {
                return m_good;
            }
        }
        /// <summary>
        /// 此屬性表示網頁的所在的網站
        /// </summary>
        public string Host
        {
            get
            {
                return m_uri.Host;
            }
        }
        #endregion
 
 
        /// <summary>
        /// 從HTML代碼中分析出連接信息
        /// </summary>
        /// <returns>List<Link></returns>
        private List<Link> getLinks()
        {
            if (m_links.Count == 0)
            {
                Regex[] regex = new Regex[2];
                regex[0] = new Regex(@"<a\shref\s*=""(?<URL>[^""]*).*?>(?<title>[^<]*)</a>", RegexOptions.IgnoreCase | RegexOptions.Singleline);
                regex[1] = new Regex("<[i]*frame[^><]+src=(\"|')?(?<url>([^>\"'\\s)])+)(\"|')?[^>]*>", RegexOptions.IgnoreCase);
 
                for (int i = 0; i < 2; i++)
                {
                    Match match = regex[i].Match(m_html);
                    while (match.Success)
                    {
                        try
                        {
                            string url = HttpUtility.UrlDecode(new Uri(m_uri, match.Groups["URL"].Value).AbsoluteUri);
 
                            string text = "";
                            if (i == 0) text = new Regex("(<[^>]+>)|(\\s)|( )|&|\"", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(match.Groups["text"].Value, "");
 
                            Link link = new Link();
                            link.Text = text;
                            link.NavigateUrl = url;
 
                            m_links.Add(link);
                        }
                        catch (Exception ex) { Console.WriteLine(ex.Message); };
                        match = match.NextMatch();
                    }
                }
            }
            return m_links;
        }
        /// <summary>
        /// 此私有方法從一段HTML文本中提取出必定字數的純文本
        /// </summary>
        /// <param name="instr">HTML代碼</param>
        /// <param name="firstN">提取從頭數多少個字</param>
        /// <param name="withLink">是否要連接裏面的字</param>
        /// <returns>純文本</returns>
        private string getFirstNchar(string instr, int firstN, bool withLink)
        {
            if (m_outstr == "")
            {
                m_outstr = instr.Clone() as string;
                m_outstr = new Regex(@"(?m)<script[^>]*>(\w|\W)*?</script[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
                m_outstr = new Regex(@"(?m)<style[^>]*>(\w|\W)*?</style[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
                m_outstr = new Regex(@"(?m)<select[^>]*>(\w|\W)*?</select[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
                if (!withLink) m_outstr = new Regex(@"(?m)<a[^>]*>(\w|\W)*?</a[^>]*>", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(m_outstr, "");
                Regex objReg = new System.Text.RegularExpressions.Regex("(<[^>]+?>)| ", RegexOptions.Multiline | RegexOptions.IgnoreCase);
                m_outstr = objReg.Replace(m_outstr, "");
                Regex objReg2 = new System.Text.RegularExpressions.Regex("(\\s)+", RegexOptions.Multiline | RegexOptions.IgnoreCase);
                m_outstr = objReg2.Replace(m_outstr, " ");
 
            }
            return m_outstr.Length > firstN ? m_outstr.Substring(0, firstN) : m_outstr;
        }
 
 
        #region 公有文法
        /// <summary>
        /// 此公有方法提取網頁中必定字數的純文本,包括連接文字
        /// </summary>
        /// <param name="firstN">字數</param>
        /// <returns></returns>
        public string getContext(int firstN)
        {
            return getFirstNchar(m_html, firstN, true);
        }
 
        /// <summary>
        /// 此公有方法從本網頁的連接中提取必定數量的連接,該連接的URL知足某正則式
        /// </summary>
        /// <param name="pattern">正則式</param>
        /// <param name="count">返回的連接的個數</param>
        /// <returns>List<Link></returns>
        public List<Link> getSpecialLinksByUrl(string pattern, int count)
        {
            if (m_links.Count == 0) getLinks();
            List<Link> SpecialLinks = new List<Link>();
            List<Link>.Enumerator i;
            i = m_links.GetEnumerator();
            int cnt = 0;
            while (i.MoveNext() && cnt < count)
            {
                if (new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase).Match(i.Current.NavigateUrl).Success)
                {
                    SpecialLinks.Add(i.Current);
                    cnt++;
                }
            }
            return SpecialLinks;
        }
 
        /// <summary>
        /// 此公有方法從本網頁的連接中提取必定數量的連接,該連接的文字知足某正則式
        /// </summary>
        /// <param name="pattern">正則式</param>
        /// <param name="count">返回的連接的個數</param>
        /// <returns>List<Link></returns>
        public List<Link> getSpecialLinksByText(string pattern, int count)
        {
            if (m_links.Count == 0) getLinks();
            List<Link> SpecialLinks = new List<Link>();
            List<Link>.Enumerator i;
            i = m_links.GetEnumerator();
            int cnt = 0;
            while (i.MoveNext() && cnt < count)
            {
                if (new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase).Match(i.Current.Text).Success)
                {
                    SpecialLinks.Add(i.Current);
                    cnt++;
                }
            }
            return SpecialLinks;
        }
 
        /// <summary>
        /// 這公有方法提取本網頁的純文本中知足某正則式的文字
        /// </summary>
        /// <param name="pattern">正則式</param>
        /// <returns>返回文字</returns>
        public string getSpecialWords(string pattern)
        {
            if (m_outstr == "") getContext(Int16.MaxValue);
            Regex regex = new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase);
            Match mc = regex.Match(m_outstr);
            if (mc.Success)
                return mc.Groups[1].Value;
            return string.Empty;
        }
        #endregion
 
        #region 構造函數
 
        private void Init(string _url)
        {
            try
            {
                m_uri = new Uri(_url);
                m_links = new List<Link>();
                m_html = "";
                m_outstr = "";
                m_title = "";
                m_good = true;
                if (_url.EndsWith(".rar") || _url.EndsWith(".dat") || _url.EndsWith(".msi"))
                {
                    m_good = false;
                    return;
                }
                HttpWebRequest rqst = (HttpWebRequest)WebRequest.Create(m_uri);
                rqst.AllowAutoRedirect = true;
                rqst.MaximumAutomaticRedirections = 3;
                rqst.UserAgent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";
                rqst.KeepAlive = true;
                rqst.Timeout = 10000;
                lock (WebPage.webcookies)
                {
                    if (WebPage.webcookies.ContainsKey(m_uri.Host))
                        rqst.CookieContainer = WebPage.webcookies[m_uri.Host];
                    else
                    {
                        CookieContainer cc = new CookieContainer();
                        WebPage.webcookies[m_uri.Host] = cc;
                        rqst.CookieContainer = cc;
                    }
                }
                HttpWebResponse rsps = (HttpWebResponse)rqst.GetResponse();
                Stream sm = rsps.GetResponseStream();
                if (!rsps.ContentType.ToLower().StartsWith("text/") || rsps.ContentLength > 1 << 22)
                {
                    rsps.Close();
                    m_good = false;
                    return;
                }
                Encoding cding = System.Text.Encoding.Default;
                string contenttype = rsps.ContentType.ToLower();
                int ix = contenttype.IndexOf("charset=");
                if (ix != -1)
                {
                    try
                    {
                        cding = System.Text.Encoding.GetEncoding(rsps.ContentType.Substring(ix + "charset".Length + 1));
                    }
                    catch
                    {
                        cding = Encoding.Default;
                    }
                   
                    //該處視狀況而定 有的須要解碼
                    //m_html = HttpUtility.HtmlDecode(new StreamReader(sm, cding).ReadToEnd());
                    m_html = new StreamReader(sm, cding).ReadToEnd();
                    
                }
                else
                {
                  //該處視狀況而定 有的須要解碼
                   //m_html = HttpUtility.HtmlDecode(new StreamReader(sm, cding).ReadToEnd());
                    
                    m_html = new StreamReader(sm, cding).ReadToEnd();
                    Regex regex = new Regex("charset=(?<cding>[^=]+)?\"", RegexOptions.IgnoreCase);
                    string strcding = regex.Match(m_html).Groups["cding"].Value;
                    try
                    {
                        cding = Encoding.GetEncoding(strcding);
                    }
                    catch
                    {
                        cding = Encoding.Default;
                    }
                    byte[] bytes = Encoding.Default.GetBytes(m_html.ToCharArray());
                    m_html = cding.GetString(bytes);
                    if (m_html.Split('?').Length > 100)
                    {
                        m_html = Encoding.Default.GetString(bytes);
                    }
                }
                m_pagesize = m_html.Length;
                m_uri = rsps.ResponseUri;
                rsps.Close();
            }
            catch (Exception ex)
            {
               
            }
        }
        public WebPage(string _url)
        {
            string uurl = "";
            try
            {
                uurl = Uri.UnescapeDataString(_url);
                _url = uurl;
            }
            catch { };
            Init(_url);
        }
        #endregion
    }
WebPage webInfo = new WebPage("網址");
 
webInfo.Context;//不包含html標籤的全部內容
 
webInfo.M_html;//包含html標籤的內容
 
...參考屬性
View Code

提取網頁圖片連接地址代碼

原計劃中使用過的LZW圖片壓縮算法:
LZW壓縮算法是一種新穎的壓縮方法,由Lemple-Ziv-Welch 三人共同創造,用他們的名字命名。
它採用了一種先進的串表壓縮不,將每一個第一次出現的串放在一個串表中,用一個數字來表示串,壓
縮文件只存貯數字,則不存貯串,從而使圖象文件的壓縮效率獲得較大的提升。奇妙的是,無論是在
壓縮仍是在解壓縮的過程當中都能正確的創建這個串表,壓縮或解壓縮完成後,這個串表又被丟棄。
1.基本原理
    首先創建一個字符串表,把每個第一次出現的字符串放入串表中,並用一個數字來表示,這個
數字與此字符串在串表中的位置有關,並將這個數字存入壓縮文件中,若是這個字符串再次出現時,
便可用表示它的數字來代替,並將這個數字存入文件中。壓縮完成後將串表丟棄。如"print" 字符串
,若是在壓縮時用266表示,只要再次出現,均用266表示,並將"print"字符串存入串表中,在圖象解
碼時遇到數字266,便可從串表中查出266所表明的字符串"print",在解壓縮時,串表能夠根據壓縮數
據從新生成。
2.實現方法
  A.初始化串表
    在壓縮圖象信息時,首先要創建一個字符串表,用以記錄每一個第一次出現的字符串。一個字符串
表最少由兩個字符數組構成,一個稱爲當前數組,一個稱爲前綴數組,由於在GIF文件中每一個基本字符
串的長度一般爲2(但它表示的實際字符串長度可達幾百甚至上千),一個基本字符串由當前字符和它
前面的字符(也稱前綴)構成。前綴數組中存入字符串中的首字符,當前數組存放字符串中的尾字符
,其存入位置相同,所以只要肯定一個下標,就可肯定它所存貯的基本字符串,因此在數據壓縮時,
用下標代替基本字符串。通常串表大小爲4096個字節(即2 的12次方),這意味着一個串表中最多能
存貯4096個基本字符串,在初始化時根據圖象中色彩數目多少,將串表中起始位置的字節均賦以數字
,一般當前數組中的內容爲該元素的序號(即下標),如第一個元素爲0,第二個元素爲1,第15個元
素爲14 ,直到下標爲色彩數目加2的元素爲止。若是色彩數爲256,則要初始化到第258個字節,該字
節中的數值爲257。其中數字256表示清除碼,數字257 爲圖象結束碼。後面的字節存放文件中每個
第一次出現的串。一樣也要音樂會 前綴數組初始化,其中各元素的值爲任意數,但通常均將其各位置
1,即將開始位置的各元素初始化爲0XFF,初始化的元素數目與當前數組相同,其後的元素則要存入每
一個第一次出現的字符串了。若是加大串表的長度可進一步提升壓縮效率,但會下降解碼速度。
  B.壓縮方法
    瞭解壓縮方法時,先要了解幾個名詞,一是字符流,二是代碼流,三是當前碼,四是當前前綴。
字符流是源圖象文件中未經壓縮的圖象數據;代碼流是壓縮後寫入GIF 文件的壓縮圖象數據;當前碼
是從字符流中剛剛讀入的字符;當前前綴是剛讀入字符前面的字符。
GIF 文件在壓縮時,不論圖象色彩位數是多少,均要將顏色值按字節的單位放入代碼流中,每一個字節
均表示一種顏色。雖然在源圖象文件中用一個字節表示16色、4色、2色時會出現4位或更多位的浪費(
由於用一個字節中的4位就能夠表示16色),但用LZW 壓縮法時可回收字節中的空閒位。在壓縮時,先
從字符流中讀取第一個字符做爲當前前綴,再取第二個字符做爲當前碼,當前前綴與當前碼構成第一
個基本字符串(如當前前綴爲A,當前碼爲B則此字符串即爲AB),查串表,此時確定不會找到一樣字
符串,則將此字符串寫入串表,當前前綴寫入前綴數組,當前碼寫入當前數組,並將當前前綴送入代
碼流,當前碼放入當前前綴,接着讀取下一個字符,該字符即爲當前碼了,此時又造成了一個新的基
本字符串 (若當前碼爲C,則此基本字符串爲BC),查串表,如有此串,則丟棄當前前綴中的值,用
該串在串表中的位置代碼(即下標)做爲當前前綴,再讀取下一個字符做爲當前碼,造成新的基本字
符串,直到整幅圖象壓縮完成。由此可看出,在壓縮時,前綴數組中的值就是代碼流中的字符,大於
色彩數目的代碼確定表示一個字符串,而小於或等於色彩數目的代碼即爲色彩自己。
  C.清除碼
    事實上壓縮一幅圖象時,經常要對串表進行屢次初始化,每每一幅圖象中出現的第一次出現的基
本字符串個數會超過4096個,在壓縮過程當中只要字符串的長度超過了4096,就要將當前前綴和當前碼
輸入代碼流,並向代碼流中加入一個清除碼,初始化串表,繼續按上述方法進行壓縮。
  D.結束碼
    當全部壓縮完成後,就向代碼流中輸出一個圖象結束碼,其值爲色彩數加1,在256色文件中,結
束碼爲257。
  E.字節空間回收
    在GIF文件輸出的代碼流中的數據,除了以數據包的形式存放以外,全部的代碼均按單位存貯,樣
就有效的節省了存貯空間。這如同4位彩色(16色)的圖象,按字節存放時,只能利用其中的4位,另
外的4位就浪費了,可按位存貯時,每一個字節就能夠存放兩個顏色代碼了。事實上在GIF 文件中,使用
了一種可變數的存貯方法,由壓縮過程可看出,串表前綴數組中各元素的值頒是有規律的,以256色的
GIF文件中,第258-511元素中值的範圍是0-510 ,正好可用9位的二進制數表示,第512-1023元素中值
的範圍是0-1022,正好可用10位的二進制數表示,第1024-2047 元素中值的範圍是0-2046,正好用11
位的二進制數表示,第2048-4095元素中值的範圍是0-4094,正好用12位的二進制數表示。用可變位數
存貯代碼時,基礎位數爲圖象色彩位數加1,隨着代碼數的增長,位數也在加大,直到位數超過爲12(
此時字符串表中的字符串個數正好爲2 的12次方,即4096個)。 其基本方法是:每向代碼流加入一個
字符,就要判別此字符所在串在串表中的位置(即下標)是否超過2的當前位數次方,一旦超過,位數
加1。如在4位圖象中,對於剛開始的代碼按5位存貯,第一個字節的低5位放第一個代碼,高三位爲第
二個代碼的低3位,第二個字節的低2位放第二個代碼的高兩位,依次類推。對於8位(256色)的圖象
,其基礎位數就爲9,一個代碼最小要放在兩個字節。
  F.壓縮範圍
    如下爲256色GIF文件編碼實例,若是留心您會發現這是一種奇妙的編碼方法,同時爲何在壓縮
完成後再也不須要串表,並且還在解碼時根據代碼流信息能從新建立串表。
字 符 串: 1,2,1,1,1,1,2,3,4,1,2,3,4,5,9,…
當 前 碼: 2,1,1,1,1,2,3,4,1,2,3,4,5,9,…
當前前綴: 1,2,1,1,260,1,258,3,4,1,258,262,4,5,…
當前數組: 2,1,1, 1, 3,4,1, 4,5,9,…
數組下標: 258,259,260,261,262,263,264,265,266,267,…
代 碼 流: 1,2,1,260,258,3,4,262,4,5,…
    GIF文件做爲一種重要的圖形圖象文件格式,儘管其編碼規則極複雜,但其壓縮效率是極高的,特
別是對某些平滑過渡的圖象的圖形,壓縮效果更好。同時因爲其在壓縮過程當中的對圖象信息可以完整
的保存,在目前流行的電子圖片及電子圖書中獲得了普遍的應用。
 
 
 
 
 
通常的html編輯器也是這樣實現相似的功能,要改寫html中圖片的代碼,想辦法從html的內容中找到img的連接地址,而後在服務器端把他下載下來保存到服務器端。而後把地址給改成服務上保存圖片的絕對地址,以此爲參數調用圖片。
 
 
一:實現對HTML中網頁連接地址的提取
 
// AnalizeIMG.java
 
 // 主程序
 
 import java.io.BufferedReader;
import java.io.File;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 
 
 public class AnalizeIMG {
 
 public void p(String s)
 {
 System.out.println(s);
 }
 
 public void analizeFile(String infile,String outfile) throws Exception
 {
 File file = new File(infile);
 if (file == null || ! file.exists()) {
 p( "File" + infile + "not exits !" );
 }
 
 if ( ! file.canRead()) {
 p( "File" + infile +" can't read !" );
 
 }
 
 String strLine = null ;
 FileReader frd = new FileReader(infile);
BufferedReader bufferedReader = new BufferedReader(frd);
try {
 AnalizeWebParse parse = new AnalizeWebParse();
 String s = parse.parse(bufferedReader);
 
 createFile(outfile,s);
 
 } catch (Exception ex) {
 throw ex;
} finally {
 frd.close();
 bufferedReader.close();
 }
 }
 
 private void createFile(String filename, String content) {
 FileWriter f = null ;
 try {
 f = new FileWriter(filename);
 if (f == null || content == null ) {
 return ;
 }
 
 f.write(content);
 f.flush();
 f.close();
 
 } catch (Exception e) {
 
 } finally {
if (f!= null ) {
 try {
 f.close();
 } catch (Exception e) {
 
 }
}
 }
 }
public static void main(String arg[])
 {
 AnalizeIMG ana = new AnalizeIMG();
 try {
 ana.analizeFile("E:\\1.txt" , "E:\\out.lst");
 } catch (Exception ex) {
 ex.printStackTrace();
 }
 }
 }
 
二:提取與下載
 
// AnalizeWebParse.java
 
 // 網頁分析代碼,
 import java.io.BufferedReader;
 import java.io.StringReader;
import java.util.regex.Pattern;
 
 import javax.swing.text.MutableAttributeSet;
 import javax.swing.text.html.HTML;
 import javax.swing.text.html.HTMLEditorKit.ParserCallback;
 import javax.swing.text.html.parser.ParserDelegator;
 public class AnalizeWebParse extends ParserCallback {
 
 StringBuffer sb = new StringBuffer();
 
 boolean start =false ;
 boolean finished =false ;
 
 public void p(String s)
 {
 System.out.println(s);
 }
 
 public void handleStartTag(HTML.Tag tag, MutableAttributeSet attribs,
 int pos) {
 
 if (finished == true )
 {
 return ;
 }
 
 if (start == false ) {
 if (tag == HTML.Tag.DIV) {
 String cla = (String) attribs
 .getAttribute(HTML.Attribute.CLASS);
 if (cla == null ) {
 return ;
 }
 
 if (cla.indexOf("body")!= - 1 ) {
 // Start
 start = true ;
 }
 }
 }
 }
 
 public void handleEndTag(HTML.Tag tag, int pos) {
 if (tag == HTML.Tag.DIV && start == true && finished == false ) {
 finished = true ;
 }  }
 
 public void handleText( char [] text, int pos) {
 
 }
 
 public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
 if (t == HTML.Tag.IMG) {
 // get a src
 String src = (String) a.getAttribute(HTML.Attribute.SRC);
 if (src == null ) {
 return ;
 }
 
 if (Pattern.matches("^(http://.+)" , src)) {
 sb.append(src).append("\n");
 }
 }
 }
 
 public String parse(BufferedReader file) throws Exception {
 if (file == null )
 {
 return null ;
 }
 
 ParserDelegator pd = new ParserDelegator();
 try {
 pd.parse(file, this , true );
 } catch(Exception e) {
 throw e;
 }
 
 return sb.toString();
 }
 }
 
 
 
 
 
對於部分須要,能夠提取Html內容中的全部圖片信息
源碼以下
 
protected ArrayList  GetAList(string HtmlContent)
  {
   try
   {
    ArrayList arr = new ArrayList();
    HtmlContent = content.Replace("\r\n","");
    HtmlContent = content.Trim();
string partern = @"\<img(.*?)\>";//@"<a (.*)>.*</a> ";//"<a.*(?=Headline)(.|\n)*?</a>";//@"/<a (.*)>.*<\/\a>/ ";  
 
 
System.Text.RegularExpressions.Regex.Regex regex = new System.Text.RegularExpressions.rege
x(partern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
System.Text.RegularExpressions.MatchCollection mc = regex.Matches(HtmlContent);   
    if(mc.Count <= 0)
     return arr;        
    System.Text.RegularExpressions.Regex.regex2=new System.Text.RegularExpressions.Regex(@"('|""|/)?[\w_()]*(.jpg|.bmp|.gif|.png|.jpeg)",System.Text.RegularExpressions.RegexOptions.IgnoreCase);
    
    foreach(Match m in mc)
    {
     System.Text.RegularExpressions.MatchCollection m2 = regex2.Matches(m.ToString());
     if( m2.Count > 0 )
     {      
      arr.Add( m2[0].ToString().Substring(1) );      
     }
    }
    return arr;    
     
   }
   catch(Exception ex)
   {
    throw ex;
   }
 
  }
三:Java字符串替換函數replace實現圖片連接地址,即絕對地址向相對地址的轉換。而後發送在服務器上通過壓縮後的圖片的相對地址,實現了WAP的圖片瀏覽。
Public static Stringreplace (String strSource ,String strFrom,String srtTo){
//若是要替換的字串爲空,則直接返回。
If (srtForm==null||strFrom.equals(''))return srtSource;
String srtDesr='';//提取的圖片連接地址
Int intFromLen=srtFrom.length();
Int intPos;
While((intPos=strSource.indexof(srtFrom))!=-1{
srtDest=strDext+strSource.substring(0,inrPos);
strDext=srtDext+strSource;
Return strDest;
}
 
 
View Code

用C#和正則表達式截取html代碼

用C#和正則表達式截【IT168技術文檔】如何使用C#和正則表達式截取html代碼呢,如何處理html代碼中的\r\n這樣的字符呢,下面咱們來一塊兒研究一下,先從截取目標開始。

 1、代碼說明

 1.如下html表示收到的3個組的信息,若是含有"unread.gif"表示未讀消息,不然表示已讀信息。

 2.截取未讀消息和已讀消息的條數和theUrl

 3.要將未讀信息和已讀信息分開放入兩個組裏。

 <div class="dxx_of" id="message1" onmouseover="msgOnmouseover(1)" onmouseout="msgOnmouseout(1)" />

 <div class="dxx1" style="padding:15px 10px;"><img src="http://www.microsoft.com/i2/unread.gif" width="14" height="10" title="" /></div>

 <div class="dxx2">

 <table class="aa" border="0" cellpadding="0" cellspacing="0" >

 <colgroup>

 <col width="463" />

 </colgroup>

 <tbody>

 <tr basestyle="oRowLine2">

 <td valign="top" onclick="javascript:document.location='thUrl';" >

 wa

 <div><span class='c9'>共6條會話</span><a href="thUrl" class="sl">+展開</a></span></div>

 <span class="c9"></span>

 </td>

 </tr>

 </tbody>

 </table>

 </div>

 <div class="c"></div>

 </div>

 <div class="dxx_of" id="message2" onmouseover="msgOnmouseover(2)" onmouseout="msgOnmouseout(2)" />

 <div class="dxx1" style="padding:15px 10px;"></div>

 <div class="dxx2">

 <table class="aa" border="0" cellpadding="0" cellspacing="0" >

 <colgroup>

 <col width="463" />

 </colgroup>

 <tbody>

 <tr basestyle="oRowLine2">

 <td valign="top" onclick="javascript:document.location='thUrl';" >

 wa

 <div><span class='c9'>共3條會話</span><a href="thUrl1" class="sl">+展開</a></span></div>

 <span class="c9"></span>

 </td>

 </tr>

 </tbody>

 </table>

 </div>

 <div class="c"></div>

 </div>

 <div class="dxx_of" id="message3" onmouseover="msgOnmouseover(3)" onmouseout="msgOnmouseout(3)" />

 <div class="dxx1" style="padding:15px 10px;"></div>

 <div class="dxx2">

 同上不少html內容

 </div>

 <div class="c"></div>

 </div>

 
  2、官方樣例

 用C#和正則表達式如何對上例的代碼進行截取呢,咱們來看看微軟官方發佈的樣例。

 示例

 System.Text.RegularExpressions.RegexOptions 。

 C#

 class TestRegularExpressions

 {

 static void Main()

 {

 string[] sentences =

 {

 "cow over the moon",

 "Betsy the Cow",

 "cowering in the corner",

 "no match here"

 };

 string sPattern = "cow";

 foreach (string s in sentences)

 {

 System.Console.Write("{0,24}", s);

 if (System.Text.RegularExpressions.Regex.IsMatch(s, sPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase))

 {

 System.Console.WriteLine("  (match for '{0}' found)", sPattern);

 }

 else

 {

 System.Console.WriteLine();

 }

 }

 // Keep the console window open in debug mode.

 System.Console.WriteLine("Press any key to exit.");

 System.Console.ReadKey();

 }

 }

 /* Output:

 cow over the moon  (match for 'cow' found)

 Betsy the Cow  (match for 'cow' found)

 cowering in the corner  (match for 'cow' found)

 no match here

 */

 以上代碼是一個控制檯應用程序,用於對數組中的字符串執行簡單的不區分大小寫的搜索。給定要搜索的字符串和包含搜索模式的字符串後,靜態方法 Regex.IsMatch 將執行搜索。使用第三個參數指示忽略大小寫。

 實際能夠使用如下代碼來匹配。

Regex regex = new Regex("<div class=\"dxx_of\" id=\".+/>.+(?<htmlCode>.+).+<div class=\"c\"></div>");
 MatchCollection matchs = regex.Matches(resultHtml);

 if(maths.Count>0)

 strig html = matchs[0].Groups["htmlCode"].Value;

  可是正則的"."只能匹配不含\n的任何字符,但是HTML代碼中有不少\r\n。

 3、如何處理特殊字符

 若是不重要能夠用string Replace方法將 \r\n替換掉,下面這個方法能夠有效的將其分爲3個組。

 C#

 class TestRegularExpressionValidation

 {

 static void Main()

 {

 string[] numbers =

 {

 "123-456-7890",

 "444-234-22450",

 "690-203-6578",

 "146-893-232",

 "146-839-2322",

 "4007-295-1111",

 "407-295-1111",

 "407-2-5555",

 };

 string sPattern = "^\d{3}-\d{3}-\d{4}$";

 foreach (string s in numbers)

 {

 System.Console.Write("{0,14}", s);

 if (System.Text.RegularExpressions.Regex.IsMatch(s, sPattern))

 {

 System.Console.WriteLine(" - valid");

 }

 else

 {

 System.Console.WriteLine(" - invalid");

 }

 }

 // Keep the console window open in debug mode.

 System.Console.WriteLine("Press any key to exit.");

 System.Console.ReadKey();

 }

 }

 /* Output:

 123-456-7890 - valid

 444-234-22450 - invalid

 690-203-6578 - valid

 146-893-232 - invalid

 146-839-2322 - valid

 4007-295-1111 - invalid

 407-295-1111 - valid

 407-2-5555 - invalid

 */

 以上代碼是一個控制檯應用程序,此程序使用正則表達式驗證數組中每一個字符串的格式。驗證要求每一個字符串具備電話號碼的形式,即用短劃線將數字分紅三組,前兩組各包含三個數字,第三組包含四個數字。這是使用正則表達式 ^\d{3}-\d{3}-\d{4}$ 完成的。取html代碼
View Code

在《爬蟲蜘蛛程序的製做(C#語言)》一文中,已經介紹了爬蟲程序實現的基本方法,能夠說,已經實現了爬蟲的功能。只是它存在一個效率問題,下載速度可能很慢。這是兩方面

在《爬蟲/蜘蛛程序的製做(C#語言)》一文中,已經介紹了爬蟲程序實現的基本方法,能夠說,已經實現了爬蟲的功能。只是它存在一個效率問題,下載速度可能很慢。這是兩方面的緣由形成的:
  1.分析和下載不能同步進行。在《爬蟲/蜘蛛程序的製做(C#語言)》中已經介紹了爬蟲程序的兩個步驟:分析和下載。在單線程的程序中,二者是沒法同時進行的。也就是說,分析時會形成網絡空閒,分析的時間越長,下載的效率越低。反之也是同樣,下載時沒法同時進行分析,只有停下下載後才能進行下一步的分析。問題浮出水面,我想你們都會想到:把分析和下載用不一樣的線程進行,問題不就解決了嗎?
  2.只是單線程下載。相信你們都有用過網際快車等下載資源的經歷,它裏面是能夠設置線程數的(近年版本默認是10,曾經默認是5)。它會將文件分紅與線程數相同的部分,而後每一個線程下載本身的那一部分,這樣下載效率就有可能提升。相信你們都有加多線程數,提高下載效率的經歷。但細心的用戶會發現,在帶寬必定的狀況下,並非線程越多,速度越快,而是在某一點達到峯值。爬蟲做爲特殊的下載工具,不具有多線程的能力何以有效率可談?爬蟲在信息時代的目的,難道不是快速獲取信息嗎?因此,爬蟲須要有多線程(可控數量)同時下載網頁。
  好了,認識、分析完問題,就是解決問題了:
  多線程在C#中並不難實現。它有一個命名空間:System.Threading,提供了多線程的支持。
  要開啓一個新線程,須要如下的初始化:
ThreadStart startDownload = new ThreadStart( DownLoad );
//線程起始設置:即每一個線程都執行DownLoad(),注意:DownLoad()必須爲不帶有參數的方法
Thread downloadThread = new Thread( startDownload ); //實例化要開啓的新類
downloadThread.Start();//開啓線程
  因爲線程起始時啓動的方法不能帶有參數,這就爲多線程共享資源添加了麻煩。不過咱們能夠用類級變量(固然也能夠使用其它方法,筆者認爲此方法最簡單易用)來解決這個問題。知道開啓多線程下載的方法後,你們可能會產生幾個疑問:
1.如何控制線程的數量?
  2.如何防止多線程下載同一網頁?
  3.如何判斷線程結束?
  4.如何控制線程結束?
  下面就這幾個問題提出解決方法:
  1.線程數量咱們能夠經過for循環來實現,就如同當年初學編程的打點程序同樣。
  好比已知用戶指定了n(它是一個int型變量)個線程吧,能夠用以下方法開啓五個線程。
Thread[] downloadThread;
//聲名下載線程,這是C#的優點,即數組初始化時,不須要指定其長度,能夠在使用時才指定。
這個聲名應爲類級,這樣也就爲其它方法控件它們提供了可能
ThreadStart startDownload = new ThreadStart( DownLoad );
//線程起始設置:即每一個線程都執行DownLoad()
downloadThread = new Thread[ n ];//爲線程申請資源,肯定線程總數
for( int i = 0; i < n; i++ )//開啓指定數量的線程數
{
downloadThread[i] = new Thread( startDownload );//指定線程起始設置
downloadThread[i].Start();//逐個開啓線程
}
  好了,實現控制開啓線程數是否是很簡單啊?
  2.下面出現的一個問題:全部的線程都調用DonwLoad()方法,這樣如何避免它們同時下載同一個網頁呢?
  這個問題也好解決,只要創建一下Url地址表,表中的每一個地址只容許被一個線程申請便可。具體實現:
  能夠利用數據庫,創建一個表,表中有四列,其中一列專門用於存儲Url地址,另外兩列分別存放地址對應的線程以及該地址被申請的次數,最後一列存放下載的內容。(固然,對應線程一列不是必要的)。當有線程申請後,將對應線程一列設定爲當前線程編號,並將是否申請過一列設置爲申請一次,這樣,別的線程就沒法申請該頁。若是下載成功,則將內容存入內容列。若是不成功,內容列仍爲空,做爲是否再次下載的依據之一,若是反覆不成功,則進程將於達到重試次數(對應該地址被申請的次數,用戶可設)後,申請下一個Url地址。主要的代碼以下(以VFP爲例):
<創建表>
CREATE TABLE (ctablename) ( curl M , ctext M , ldowned I , threadNum I )
&&創建一個表ctablename.dbf,含有地址、文本內容、已經嘗試下載次數、
線程標誌(初值爲-1,線程標誌是從0開始的整數)四個字段
<提取Url地址>
cfullname = (ctablename) + '.dbf'&&爲表添加擴展名
USE (cfullname) 
GO TOP
LOCATE FOR (EMPTY( ALLTRIM( ctext ) ) AND ldowned < 2 AND
( threadNum = thisNum OR threadNum = - 1) ) 
&&查找還沒有下載成功且應下載的屬於本線程權限的Url地址,thisNum是當前線程的編號,
能夠經過參數傳遞獲得
gotUrl = curl
recNum = RECNO()
IF recNum <= RECCOUNT() THEN &&若是在列表中找到這樣的Url地址
UPDATE (cfullname) SET ldowned = ( ldowned + 1 ) , threadNum =
thisNum WHERE RECNO() = recNum &&更新表,將此記錄更新爲已申請,即下載次數加1,
線程標誌列設爲本線程的編號。
<下載內容>
cfulltablename = (ctablename) + '.dbf'
USE (cfulltablename)
SET EXACT ON
LOCATE FOR curl = (csiteurl) && csiteurl是參數,爲下載到的內容所對應的Url地址
recNumNow = RECNO()&&獲得含有此地址的記錄號
UPDATE (cfulltablename) SET ctext = (ccontent) WHERE RECNO() =
recNumNow &&插入對應地址的對應內容
<插入新地址>
ctablename = (ctablename) + '.dbf'
USE (ctablename)
GO TOP
SET EXACT ON
LOCATE FOR curl = (cnewurl) &&查找有無此地址
IF RECNO() > RECCOUNT() THEN &&若是尚無此地址
SET CARRY OFF
INSERT INTO (ctablename) ( curl , ctext , ldowned , threadNum )
VALUES ( (cnewurl) , "" , 0 , -1 ) &&將主頁地址添加到列表
  好了,這樣就解決了多線程中,線程衝突。固然,去重問題也能夠在C#語言內解決,只根創建一個臨時文件(文本就能夠),保存全部的Url地址,差對它們設置相應的屬性便可,但查找效率可能不及數據庫快。
  3.線程結束是很難判斷的,由於它老是在查找新的連接。用者認爲能夠假設:線程重複N次之後仍是沒有能申請到新的Url地址,那麼能夠認爲它已經下載完了全部連接。主要代碼以下:
string url = "";
int times = 0;
while ( url == "" )//若是沒有找到符合條件的記錄,則不斷地尋找符合條件的記錄
{
url = getUrl.GetAUrl( …… );//調用GetAUrl方法,試圖獲得一個url值
if ( url == "" )//若是沒有找到
{
times ++;//嘗試次數自增
continue; //進行下一次嘗試
}
if ( times > N ) //若是已經嘗試夠了次數,則退出進程
{
downloadThread[i].Abort; //退出進程
}
else//若是沒有嘗試夠次數
{
Times = 0; //嘗試次數歸零處理
}
//進行下一步針對獲得的Url的處理
}
  4.這個問題相對簡單,由於在問題一中已經建議,將線程聲名爲類級數組,這樣就很易於控制。只要用一個for循環便可結束。代碼以下:
for( int i = 0; i < n; i++ )//關閉指定數量n的線程數
{
downloadThread[i].Abort();//逐個關閉線程
}
  好了,一個蜘蛛程序就這樣完成了,在C#面前,它的實現原來如此簡單。
  這裏筆者還想提醒讀者:筆者只是提供了一個思路及一個能夠實現的解決方案,但它並非最佳的,即便這個方案自己,也有好多能夠改進的地方,留給讀者思考。
  最後說明一下我所使用的環境:
  winXP sp2 Pro
  VFP 9.0
  Visual Studio 2003 .net中文企業版
 
View Code

正則表達式過濾html標籤對

public string DealHtml(string str)
{
//str = Regex.Replace(str, @"\<(img)[^>]*>|<\/(img)>", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, @"\<(table|tbody|tr|td|th)[^>]*>|<\/(table|tbody|tr|td|th)>", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, @"\<(div|blockquote|fieldset|legend)[^>]*>|<\/(div|blockquote|fieldset|legend)>", "", RegexOptions.IgnoreCase);
//str = Regex.Replace(str, @"\<(font|i|u|h[1-9]|s)[^>]*>|<\/(font|i|u|h[1-9]|s)>", "", RegexOptions.IgnoreCase);
//str = Regex.Replace(str, @"\<(style|strong)[^>]*>|<\/(style|strong)>", "", RegexOptions.IgnoreCase);
//str = Regex.Replace(str, @"\<a[^>]*>|<\/a>", "", RegexOptions.IgnoreCase);
//str = Regex.Replace(str, @"\<(meta|iframe|frame|span|tbody|layer)[^>]*>|<\/(iframe|frame|meta|span|tbody|layer)>", "", RegexOptions.IgnoreCase);
str = Regex.Replace(str, @"\<br[^>]*", "", RegexOptions.IgnoreCase);
str = str.Replace("<br>", "");
return str;
}
 
View Code

正則表達式過濾(.net)

Regex re = new Regex("<a[^>]+href=[^>]+>[^<]*</a>");//這個能夠過濾掉全部的超連接的內容
Regex re = new Regex("<a.*?>|</a>");//過濾超連接中的<a ....>xxx</a>標籤,標籤中xxx內容保留
 
public string checkStr(string html)
       {
           System.Text.RegularExpressions.Regex regex1 = new System.Text.RegularExpressions.Regex(@"<script[/s/S]+</script *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
           System.Text.RegularExpressions.Regex regex2 = new System.Text.RegularExpressions.Regex(@" href *= *[/s/S]*script *:", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
           System.Text.RegularExpressions.Regex regex3 = new System.Text.RegularExpressions.Regex(@" no[/s/S]*=", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
           System.Text.RegularExpressions.Regex regex4 = new System.Text.RegularExpressions.Regex(@"<iframe[/s/S]+</iframe *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
           System.Text.RegularExpressions.Regex regex5 = new System.Text.RegularExpressions.Regex(@"<frameset[/s/S]+</frameset *>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
           System.Text.RegularExpressions.Regex regex6 = new System.Text.RegularExpressions.Regex(@"/<img[^/>]+/>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
           System.Text.RegularExpressions.Regex regex7 = new System.Text.RegularExpressions.Regex(@"</p>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
           System.Text.RegularExpressions.Regex regex8 = new System.Text.RegularExpressions.Regex(@"<p>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
           System.Text.RegularExpressions.Regex regex9 = new System.Text.RegularExpressions.Regex(@"<[^>]*>", System.Text.RegularExpressions.RegexOptions.IgnoreCase);
           html = regex1.Replace(html, ""); //過濾<script></script>標記
           html = regex2.Replace(html, ""); //過濾href=Javascript: (<A>) 屬性
           html = regex3.Replace(html, " _disibledevent="); //過濾其它控件的on...事件
           html = regex4.Replace(html, ""); //過濾iframe
           html = regex5.Replace(html, ""); //過濾frameset
           html = regex6.Replace(html, ""); //過濾frameset
           html = regex7.Replace(html, ""); //過濾frameset
           html = regex8.Replace(html, ""); //過濾frameset
           html = regex9.Replace(html, "");
           html = html.Replace(" ", "");
           html = html.Replace("</strong>", "");
           html = html.Replace("<strong>", "");
           return html;
}
TempContent 表示包含有html的字符串; 
TempContent = System.Text.RegularExpressions.Regex.Replace(TempContent,"<[^>]+>","");至少一個 
TempContent = System.Text.RegularExpressions.Regex.Replace(TempContent,"<[^>]*>","");任意個 
 
View Code

C#獲取網頁源碼,自動判斷網頁字符集編碼

方法一:
2008-9-22 20:16:49
C#獲取網頁源碼,自動判斷網頁字符集編碼
最近開始打算從新學習C#,而且嘗試作點C#練習。而最讓我感興趣的仍是和網站相關的東西。那就作個獲取網站源碼,採集文章的功能吧。
根據網上的資料,使用WebClient來獲取源碼,很容易就能獲得網頁源碼。可是,發現,不一樣網站的網頁字符編碼就不同的,如何自動分別不一樣網站的字符編碼,而正確解釋網頁中的漢字呢。在C#裏,提供了豐富的工具類庫,能夠輕鬆的轉碼。可是,卻發現不能自動獲取網站上的字符編碼而自動正確的解釋源碼,而致使漢字顯示亂碼。之前我也用JAVA作過這樣的功能,獲取網站源碼,一樣,在JAVA的各類獲取網站源碼的類庫裏,也不能自動根據網頁字符編碼自動正確解釋編碼,只能咱們本身手動來作了。
個人解決辦法是先採用系統默認的編碼從stream裏獲得源碼,再使用正則表達式獲取源碼中的[獲取網頁字符編碼描述信息],這個信息,通常來講,網頁裏都會有的,在網頁源碼的<head>裏,相似這樣的代碼:<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />(其實不同徹底這樣,有些不規範的,沒有雙引號,或者最後面沒有/閉合,因此,正則表達式得考慮周全些),從這個代碼裏來獲取編碼信息,再判斷系統當前的默認編碼是否和這個同樣,若是不一樣,再使用網頁中取到的編碼來從新從stream裏解釋取得網頁源碼。
源碼以下:(下面這段代碼是一個完整的獲取網頁源碼,且自動正確解釋漢字)
[CODE=csharp] using System.Net; using System.IO; using System.Text.RegularExpressions; private string getHtml(string url, string charSet)//url是要訪問的網站地址,charSet是目標網頁的編碼,若是傳入的是null或者"",那就自動分析網頁的編碼 { WebClient myWebClient = new WebClient(); //建立WebClient實例myWebClient // 須要注意的: //有的網頁可能下不下來,有種種緣由好比須要cookie,編碼問題等等 //這是就要具體問題具體分析好比在頭部加入cookie // webclient.Headers.Add("Cookie", cookie); //這樣可能須要一些重載方法。根據須要寫就能夠了 //獲取或設置用於對向 Internet 資源的請求進行身份驗證的網絡憑據。 myWebClient.Credentials = CredentialCache.DefaultCredentials; //若是服務器要驗證用戶名,密碼 //NetworkCredential mycred = new NetworkCredential(struser, strpassword); //myWebClient.Credentials = mycred; //從資源下載數據並返回字節數組。(加@是由於網址中間有"/"符號) byte[] myDataBuffer = myWebClient.DownloadData(url); string strWebData = Encoding.Default.GetString(myDataBuffer); //獲取網頁字符編碼描述信息 Match charSetMatch = Regex.Match(strWebData, "
這樣就能夠了,不信你試試,對了,若是你有什麼更方便的方法請告訴我哦~~~~
這段代碼裏有不少註釋,若是你也想作個網頁採集功能,能夠學一下,嘿嘿。
方法二:
用asp.net c# HttpWebRequest獲取網頁源代碼
該方法須要傳遞目標網頁的編碼方式,好比System.Text.Encoding.Default或者System.Text.Encoding.UTF8
若是哪位高手知道如何自動判斷目標頁面的編碼格式,請在評論中告知。謝謝!
 
/// <summary>
 /// 獲取源代碼
 /// </summary>
 /// <param name="url"></param>
 /// <param name="encoding"></param>
 /// <returns></returns>
 public static string GetPage(string url, Encoding encoding)
 {
 HttpWebRequest request = null;
 HttpWebResponse response = null;
 StreamReader reader = null;
 try
 {
 request = (HttpWebRequest)WebRequest.Create(url);
 request.UserAgent = "www.svnhost.cn";
 request.Timeout = 20000;
 request.AllowAutoRedirect = false;
 response = (HttpWebResponse)request.GetResponse();
 if (response.StatusCode == HttpStatusCode.OK && response.ContentLength < 1024 * 1024)
 {
 reader = new StreamReader(response.GetResponseStream(), encoding);
 string html = reader.ReadToEnd();
 return html;
 }
 }
 catch
 {
 }
 finally
 {
 if (response != null)
 {
 response.Close();
 response = null;
 }
 if (reader != null)
 reader.Close();
 if (request != null)
 request = null;
 }
 return string.Empty;
 }
View Code

C# code

C# code
string str = "<div class=\"cl1\">sdfsdfsdf</div>";
Regex re = new Regex(@"(?is)(?<=>[^>]).*?(?=<[^<])");

foreach (Match ma in re.Matches(str))
{
Respo……

C# code
string str = "<div class=\"cl1\">sdfsdfsdf</div>";
        Regex re = new Regex(@"(?is)(?<=>[^>]).*?(?=<[^<])");

        foreach (Match ma in re.Matches(str))
        {
           Response.Write(ma.Value+ "<br/>");
        }

對我有用[0]丟個板磚[0]引用舉報管理TOP
精華推薦:【散分】公佈一些經常使用的WebServices,但願對你們的應用有幫助~

soonfei
(soonfei)
等 級:
#3樓 得分:10回覆於:2011-10-08 18:41:25
若是是特定的id或者calss
C# code
Regex re = new Regex(@"(?is)<div\s(id|class)="".*?"">(.*?)</div>");

對我有用[0]丟個板磚[0]引用舉報管理TOP
精華推薦:Share Some Methods about Linq to Entry

dalmeeme
(無機戰士)
等 級:
#4樓 得分:10回覆於:2011-10-08 21:09:45
C# code
        string s = @"<div class=""cl1"">sdfsdfsdf</div>";
        MatchCollection matches = Regex.Matches(s, @"(?is)<div[^>]*?>(.*?)</div>");
        foreach (Match match in matches)
            Response.Write(match.Groups[1].Value + "<br/>");
View Code
 Regex regex = new Regex("<div class=\"dxx_of\" id=\".+/>.+(?<htmlCode>.+).+<div class=\"c\"></div>");

 MatchCollection matchs = regex.Matches(resultHtml);



 if(maths.Count>0)

    strig html = matchs[0].Groups["htmlCode"].Value;
View Code

匹配divdiv的正則表達式

<div id="all">(.+?)</div>
匹配<div></div>的正則表達式

<input type="button" value="GetDiv" onclick="getDivContent();">
<script>
function getDivContent()
{
var div_str = 'dsadasd<div id="idname">csdfaer2342rwqer2?$@#$@#Dswweef</div>231231';
var re = /<div id="idname">[\s|\S]*?<\/div>/;
alert(div_str.match(re));
}
</script>
var re = /<div id="idname">[\s|\S]*?<\/div>/;
創建正則表達式
構造正則表達式的方法和建立數學表達式的方法同樣。也就是用多種元字符與操做符將小的表達式結合在一塊兒來建立更大的表達式。 
能夠經過在一對分隔符之間放入表達式模式的各類組件來構造一個正則表達式。對 JScript 而言,分隔符爲一對正斜槓 (/) 字符。例如:
/expression/
對 VBScript 而言,則採用一對引號 ("") 來肯定正則表達式的邊界。例如:
"expression"
在上面所示的兩個示例中,正則表達式模式 (expression) 均存儲在RegExp 對象的Pattern 屬性中。
正則表達式的組件能夠是單個的字符、字符集合、字符範圍、字符間的選擇或者全部這些組件的任意組合。
 
特殊字符
有很多元字符在試圖對其進行匹配時須要進行特殊的處理。要匹配這些特殊字符,必須首先將這些字符轉義,也就是在前面使用一個反斜槓 ()。下表給出了這些特殊字符及其含義:
特殊字符 說明 
$ 匹配輸入字符串的結尾位置。若是設置了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 ' '' '。要匹配 $ 字符自己,請使用 $。 
( ) 標記一個子表達式的開始和結束位置。子表達式能夠獲取供之後使用。要匹配這些字符,請使用 ( 和 )。 
* 匹配前面的子表達式零次或屢次。要匹配 * 字符,請使用 *+ 匹配前面的子表達式一次或屢次。要匹配 + 字符,請使用 +。 
. 匹配除換行符 以外的任何單字符。要匹配 .,請使用 。 
[ 標記一箇中括號表達式的開始。要匹配 [,請使用 [。 
? 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字符,請使用 ?。 
 將下一個字符標記爲或特殊字符、或原義字符、或後向引用、或八進制轉義符。例如, 'n' 匹配字符 'n'' ' 匹配換行符。序列 '\' 匹配 "",而 '(' 則匹配 "("。 
^ 匹配輸入字符串的開始位置,除非在方括號表達式中使用,此時它表示不接受該字符集合。要匹配 ^ 字符自己,請使用 ^。 
{ 標記限定符表達式的開始。要匹配 {,請使用 {。 
| 指明兩項之間的一個選擇。要匹配 |,請使用 |。 
 
下表給出了各類限定符及其含義的說明:
字符 描述 
* 匹配前面的子表達式零次或屢次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等價於{0,}。 
+ 匹配前面的子表達式一次或屢次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價於 {1,}。 
? 匹配前面的子表達式零次或一次。例如,"do(es)?" 能夠匹配 "do""does" 中的"do" 。? 等價於 {0,1}。 
{n} n 是一個非負整數。匹配肯定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',可是能匹配 "food" 中的兩個 o。 
{n,} n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的全部 o。'o{1,}' 等價於 'o+''o{0,}' 則等價於 'o*'。 
{n,m} m 和 n 均爲非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。劉, "o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價於 'o?'。請注意在逗號和兩個數之間不能有空格。 
 
match 方法
使用正則表達式模式對字符串執行查找,並將包含查找的結果做爲數組返回。
stringObj.match(rgExp) 
參數
stringObj
必選項。對其進行查找的 String 對象或字符串文字。
rgExp
必選項。爲包含正則表達式模式和可用標誌的正則表達式對象。也能夠是包含正則表達式模式和可用標誌的變量名或字符串文字。
說明
若是 match 方法沒有找到匹配,返回 null。若是找到匹配返回一個數組而且更新全局 RegExp 對象的屬性以反映匹配結果。
match 方法返回的數組有三個屬性:input、index和lastIndex。Input 屬性包含整個的被查找字符串。Index 屬性包含了在整個被查找字符串中匹配的子字符串的位置。LastIndex 屬性包含了最後一次匹配中最後一個字符的下一個位置。
若是沒有設置全局標誌 (g),數組的0元素包含整個匹配,而第 1 到 n 元素包含了匹配中曾出現過的任一個子匹配。這至關於沒有設置全局標誌的 exec 方法。若是設置了全局標誌,元素0到n中包含全部匹配。
示例
下面的示例演示了match 方法的用法:
function MatchDemo(){
 var r, re; // 聲明變量。
 var s = "The rain in Spain falls mainly in the plain";
 re = /ain/i; // 建立正則表達式模式。
 r = s.match(re); // 嘗試匹配搜索字符串。
 return(r); // 返回第一次出現 "ain" 的地方。
}
本示例說明帶 g 標誌設置的 match 方法的用法。
function MatchDemo(){
 var r, re; // 聲明變量。
 var s = "The rain in Spain falls mainly in the plain";
 re = /ain/ig; // 建立正則表達式模式。
 r = s.match(re); // 嘗試去匹配搜索字符串。
 return(r); // 返回的數組包含了全部 "ain" 
 // 出現的四個匹配。
View Code
相關文章
相關標籤/搜索