有朋友问到:
“我需要得到一个web page的title,因为这个title一般都比较靠前,只要取得html
的前面少量内容就可以了。因为要取得很多个页面的title,如果下载整个html code,
肯定比较浪费时间。.net好像没有现成的类可以干这件事情(取得部分html) ,我应该如何去实现?”
一种比较"廉价"(即较小成本条件下)的解决思路:
第一步:取出含有页面title部分的最小集合。这是“廉价”的关键!
第二步:用正则表达式取出<title>和</title>之间的部分即可。
先看下效果:
下面我们来分析:
页面title 一般都在靠近开始处,所以我们从开始读取Stream流,(如果靠近结尾,则如何?)读取到什么地方为止呢?有个比较明显的标志是
</title>
遇到它结束就可以了。
以什么方式读取,我这里选取的是:逐行读取,取到标志符即终止。
方法如下:
#region
获取所需要的页面内容
///
<summary>
///
获取所需要的页面内容 by tony 2009.9,16
///
邀月(downmoon):3w@live.cn
///
<param name="strUrl">
所要查找的远程网页地址
</param>
///
<param name="timeout">
超时时长设置,一般设置为8000
</param>
///
<param name="enterType">
是否输出换行符,0不输出,1输出文本框换行
</param>
///
<param name="EnCodeType">
编码方式
</param>
///
<returns></returns>
public
static
string
GetRequestString(
string
strUrl,
int
timeout,
int
enterType, Encoding EnCodeType)
{
if
(strUrl.Equals(
"
about:blank
"
))
return
null
; ;
if
(
!
strUrl.StartsWith(
"
http://
"
)
&&
!
strUrl.StartsWith(
"
https://
"
)) { strUrl
=
"
http://
"
+
strUrl; }
string
strResult
=
string
.Empty;
System.IO.StreamReader sr
=
null
;
string
temp
=
string
.Empty;
try
{
HttpWebRequest myReq
=
(HttpWebRequest)HttpWebRequest.Create(strUrl);
myReq.Timeout
=
timeout;
myReq.UserAgent
=
"
User-Agent:Mozilla/5.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 2.0.40607; .NET CLR 1.1.4322; .NET CLR 3.5.30729)
"
;
myReq.Accept
=
"
*/*
"
;
myReq.KeepAlive
=
true
;
myReq.Headers.Add(
"
Accept-Language
"
,
"
zh-cn,en-us;q=0.5
"
);
HttpWebResponse HttpWResp
=
(HttpWebResponse)myReq.GetResponse();
if
(HttpWResp.StatusCode
==
System.Net.HttpStatusCode.OK)
{
StringBuilder strBuilder
=
new
StringBuilder();
Stream myStream
=
HttpWResp.GetResponseStream();
sr
=
new
StreamReader(myStream, EnCodeType);
string
tmp
=
string
.Empty;
while
((temp
=
sr.ReadLine())
!=
null
)
{
strBuilder.Append(temp);
//
if has </title> then end by downmoon(邀月)2009.9.16
tmp
=
strBuilder.ToString();
if
(tmp.IndexOf(
"
</title>
"
)
>
0
) {
break
; }
if
(enterType
==
1
) { strBuilder.Append(
"
/r/n
"
); }
}
strResult
=
strBuilder.ToString();
return
strResult;
}
return
string
.Empty;
}
catch
(Exception ex)
{
//
#region Loghandle by Tony 2008.11.21
return
strResult;
//
#endregion
}
finally
{
if
(sr
!=
null
) { sr.Close(); } }
}
#endregion
取出后就是再用正则取出<title>和</title>之间的部分。
这部分浪费了些时间,因为邀月的正则功底不行啊!·
先后试过如下正则表达式:
1
//
string strRegEx ="<[^>]*>";
2
//
string strRegEx = "<title>.*([^</title>])";
3
//
string strRegEx = "<title>(.*?)</title>";
4
//
string strRegEx = "<title>.*?</title>";
均不能达到想要的“经济廉价”的效果,最终,找到这个:
public
static
string
GetContextByHtml(
string
sHtml)
{
//
string regex="(<title[>])(.*)(<//title>)";
string
regex
=
@"
(?<=<title.*>)([/s/S]*)(?=</title>)
"
;
System.Text.RegularExpressions.Regex ex
=
new
System.Text.RegularExpressions.Regex(regex, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
return
ex.Match(sHtml).Value.Trim();
}
演示效果如上图:
后续问题:
1、将继续实现代理方式躲过IP;
2、将尝试另外一种通过Request.Filter方式直接替换来实现。
欢迎交流。
助人等于自助! 3w@live.cn