1. 前言
相信很多人做开发时都有过这样的需求:从网页中准确提取所需的内容。思前想后,方法无非是以下几种:(本人经验尚浅,有更好的方法还请大家指点)
1. 使用正则表达式匹配所需元素。(缺点:同类型的元素如果有不同的属性,比如<div class=‘first‘>aaa</div><div class=‘last‘>bbb</div>, 如果想要匹配所有div元素时,将会相当麻烦,而且容易得到不想要的结果,漏掉需要的结果。)
2. 将网页转换成XML文档,使用Linq to XML。(缺点:需要一次转换过程,而且效率不高。)
3. 使用网站提供的WebServices或WebAPI等接口直接获取所需数据。(缺点:需要先获得接口文档,一般都不会匿名提供。)
最近几年前端的兴起,越来越多的人开始认识JQuery这个强大的工具并被其折服,其中很重要的一点就是JQuery 选择器,它的简洁,高效,易学使得前端工程师大大提高了工作效率。细想一下,提取网页内容就是和前端打交道,如果可以用JQuery选择器,那就完美了!!!
2. 理论准备
难道要在.NET下自己去做一个选择器?非也,这可不是我等小辈能做出来的。。。。既然已经有JQuery了,为什么不能直接就用它的选择器呢?
1. .NET获得网页内容
这里可以选择webbrowser控件,其实它就是一个微型IE,IE能做的它都能做。有些人会问为什么不用WebClient直接下载网页内容呢?请看第二点。
2. .NET与JS交互
使用webbrowser控件,不仅可以获得网页内容,更加重要的是它提供了与网页交互的功能。使用内置的Document属性,我们可以往网页中注入所需的JS代码并且执行它。
3. 提取并返回所需内容
在.NET中,我们可以用Docment的InvokeScript函数来执行相应的JS函数并获得返回结果。
既然理论都准备好了,接下来我们就实现它吧。
3. 功能实现
测试网页:http://www.mmeinv.com/ (福利网站哦,不过绝无邪恶内容,请编辑明鉴!)
功能需求:提取所有“福利”!!!!
先上图:
从图上可以看出,“福利”都准确地提取出来了。并且可以只获取所需的属性值。你要做的只是输入短短的15个字符。
下面再看看代码实现:
其中wb就是webbrowser控件,此段主要为了在一些不包括JQuery库的网页中注入JQuery库。
1
2
3
4
5
6
7
|
void InjectJQuery()
{ HtmlElement jquery = wb.Document.CreateElement( "script" );
wb.Document.Body.AppendChild(jquery);
JQueryInjected = true ;
} |
这里是注入需要执行的JS函数,因为不同的需求有不同的代码,所以不能重复注入,需求改变时只需要更改已注入的函数即可以。
1
2
3
4
5
6
7
8
9
|
JQScript = wb.Document.GetElementById( "JQScript" );
if (JQScript == null )
{ JQScript = wb.Document.CreateElement( "script" );
JQScript.SetAttribute( "id" , "JQScript" );
JQScript.SetAttribute( "type" , "text/javascript" );
wb.Document.Body.AppendChild(JQScript);
} |
这里是关键代码, 根据是否要提取属性而生成不同的代码。注入的代码非常简单,相信懂一点点前端的朋友一看就明白了。而最后的一行代码就是执行注入的函数并获取返回值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
if (txtAttribute.Text.Trim() == string .Empty)
JQScript.SetAttribute( "text" , "function GetJQValue() { if ($(‘"
+ txtSelector.Text + "‘).length == 1) {"
+
"return $(‘"
+ txtSelector.Text + "‘)[0].outerHTML; }"
+
" else if ($(‘"
+ txtSelector.Text + "‘).length > 1) {"
+
" var allhtml = ‘‘;"
+
" $(‘"
+ txtSelector.Text + "‘).each(function() {allhtml=allhtml+$(this)[0].outerHTML+‘\\r\\n‘;});"
+
" return allhtml;}"
+
" else return ‘no item found.‘;}" );
else { JQScript.SetAttribute( "text" , "function GetJQValue() { if ($(‘"
+ txtSelector.Text + "‘).length == 1) {"
+
"return $(‘"
+ txtSelector.Text + "‘).attr(‘"
+ txtAttribute.Text + "‘); }"
+
" else if ($(‘"
+ txtSelector.Text + "‘).length > 1) {"
+
" var allhtml = ‘‘;"
+
" $(‘"
+ txtSelector.Text + "‘).each(function() {allhtml=allhtml+$(this).attr(‘"
+ txtAttribute.Text + "‘)+‘\\r\\n‘;});"
+
" return allhtml;}"
+
" else return ‘no item found.‘;}" );
} textBox2.Text = wb.Document.InvokeScript( "GetJQValue" ).ToString();
|
相信到这里,大家都已经一目了然,短短10几行代码,就可以使用强大的JQuery选择器,效率比以前的旧方法高了不知多少倍,何乐而不为呢?
4. 知识延伸
1. 只要你前端知识够硬,就可以注入更复杂的函数,实现更复杂的内容提取。
2. 在Android和IOS里,理论上也是可以实现这样的功能。
3. 也许有一天,我们会有类似的选择器去代替SQL,实现数据库的高效查询??????????
PS: 小弟文笔极差,知识面不广,如有纰漏,请大家斧正!
PPS:啰嗦也要说了,文章版权本人所有,转载请明确标示并保留原文链接,谢谢大家!