c#实现网页正文抓取

需要记住的,随笔记一下

1、抓取远程网页源码,这里要实现自动判断网页编码,否则有可能抓到乱码。我是先看应答的 http头的chareset,一般这个很准,但像csdn的新闻比较变态http应答的头里的chareset和网页的meta里声明的 chareset不一致,所以我手工加了一下判断,如果不一致再在内存流里用网页声明的编码读取一遍源码 2、把网页分割成几大块。试用了一下tidy的.net包装及HtmlParse的.net版本,都不太好用。于是我自己写了个算法,可以把网页里的div块,td块等都提取出来,支持嵌套的情况。一般只提取div的文字块儿就行了。 3、把汉字少于200的文本块去了,一般少于200字的文本块不会是正文,即便是正文,一般来说也不会有太多的价值,我直接去掉。 4、 因为div支持嵌套,所以剩下的文本块,有可能是重复的,一个是另一个的父节点,所以要把最里层的文本块找出来,最里层的文本块肯定是汉字最多的,而其它 文本最少的,所以要计算出剩余文本块中汉字占所有字符比例最高的文本块,基本上它就是正文的文本块了。当然有的网页正文里也可能还有div的文本块,这时 候可能会判断错误,但只要正文嵌套的Div文本块的汉字少于200字,我的算法还是能准确提取正文文本块的。这一步我用写了一个自定义的方法传递给 List的Sort方法。 5、把<p><br>等标签替换成特殊占位符[p][br]等,因为最终的正文需要保留段落和回车换行等格式。这一步用正则实现。 6、把最后剩下的文本块的html标签去掉,我用正则过滤的。 7、把[p]替换成回车换行加俩空格,把[br]替换成回车换行,这步也用正则。到此,正文提取完毕

主要代码:

[csharp] view plain copy

  1. <span style="font-size:18px;">public class GetMainContentHelper
  2. {
  3. ///<summary>
  4. /// 判断两段儿文本里哪个中文占的比例高
  5. ///</summary>
  6. ///<param name="x"></param>
  7. ///<param name="y"></param>
  8. ///<returns></returns>
  9. public static int CompareDinosByChineseLength(string x, string y)
  10. {
  11. if (x == null)
  12. {
  13. if (y == null)
  14. {
  15. return 0;
  16. }
  17. else
  18. {
  19. return -1;
  20. }
  21. }
  22. else
  23. {
  24. if (y == null)
  25. {
  26. return 1;
  27. }
  28. else
  29. {
  30. Regex r = new Regex("[\u4e00-\u9fa5]");
  31. float xCount = (float)(r.Matches(x).Count) / (float)x.Length;
  32. float yCount = (float)(r.Matches(y).Count) / (float)y.Length;
  33. int retval = xCount.CompareTo(yCount);
  34. if (retval != 0)
  35. {
  36. return retval;
  37. }
  38. else
  39. {
  40. return x.CompareTo(y);
  41. }
  42. }
  43. }
  44. }
  45. ///<summary>
  46. /// 获取一个网页源码中的标签列表,支持嵌套,一般或去div,td等容器
  47. ///</summary>
  48. ///<param name="input"></param>
  49. ///<param name="tag"></param>
  50. ///<returns></returns>
  51. public static List<string> GetTags(string input, string tag)
  52. {
  53. StringReader strReader = new StringReader(input);
  54. int lowerThanCharCounter = 0;
  55. int lowerThanCharPos = 0;
  56. Stack<int> tagPos = new Stack<int>();
  57. List<string> taglist = new List<string>();
  58. int i = 0;
  59. while (true)
  60. {
  61. try
  62. {
  63. int intCharacter = strReader.Read();
  64. if (intCharacter == -1) break;
  65. char convertedCharacter = Convert.ToChar(intCharacter);
  66. if (lowerThanCharCounter > 0)
  67. {
  68. if (convertedCharacter == ‘>‘)
  69. {
  70. lowerThanCharCounter--;
  71. string biaoqian = input.Substring(lowerThanCharPos, i - lowerThanCharPos + 1);
  72. if (biaoqian.StartsWith(string.Format("<{0}", tag)))
  73. {
  74. tagPos.Push(lowerThanCharPos);
  75. }
  76. if (biaoqian.StartsWith(string.Format("</{0}", tag)))
  77. {
  78. if (tagPos.Count < 1)
  79. continue;
  80. int tempTagPos = tagPos.Pop();
  81. string strdiv = input.Substring(tempTagPos, i - tempTagPos + 1);
  82. taglist.Add(strdiv);
  83. }
  84. }
  85. }
  86. if (convertedCharacter == ‘<‘)
  87. {
  88. lowerThanCharCounter++;
  89. lowerThanCharPos = i;
  90. }
  91. }
  92. finally
  93. {
  94. i++;
  95. }
  96. }
  97. return taglist;
  98. }
  99. ///<summary>
  100. /// 获取指定网页的源码,支持编码自动识别
  101. ///</summary>
  102. ///<param name="url"></param>
  103. ///<returns></returns>
  104. public static string getDataFromUrl(string url)
  105. {
  106. string str = string.Empty;
  107. HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
  108. //设置http头
  109. request.AllowAutoRedirect = true;
  110. request.AllowWriteStreamBuffering = true;
  111. request.Referer = "";
  112. request.Timeout = 10 * 1000;
  113. request.UserAgent = "";
  114. HttpWebResponse response = null;
  115. try
  116. {
  117. response = (HttpWebResponse)request.GetResponse();
  118. if (response.StatusCode == HttpStatusCode.OK)
  119. {
  120. //根据http应答的http头来判断编码
  121. string characterSet = response.CharacterSet;
  122. Encoding encode;
  123. if (characterSet != "")
  124. {
  125. if (characterSet == "ISO-8859-1")
  126. {
  127. characterSet = "gb2312";
  128. }
  129. encode = Encoding.GetEncoding(characterSet);
  130. }
  131. else
  132. {
  133. encode = Encoding.Default;
  134. }
  135. //声明一个内存流来保存http应答流
  136. Stream receiveStream = response.GetResponseStream();
  137. MemoryStream mStream = new MemoryStream();
  138. byte[] bf = new byte[255];
  139. int count = receiveStream.Read(bf, 0, 255);
  140. while (count > 0)
  141. {
  142. mStream.Write(bf, 0, count);
  143. count = receiveStream.Read(bf, 0, 255);
  144. }
  145. receiveStream.Close();
  146. mStream.Seek(0, SeekOrigin.Begin);
  147. //从内存流里读取字符串
  148. StreamReader reader = new StreamReader(mStream, encode);
  149. char[] buffer = new char[1024];
  150. count = reader.Read(buffer, 0, 1024);
  151. while (count > 0)
  152. {
  153. str += new String(buffer, 0, count);
  154. count = reader.Read(buffer, 0, 1024);
  155. }
  156. //从解析出的字符串里判断charset,如果和http应答的编码不一直
  157. //那么以页面声明的为准,再次从内存流里重新读取文本
  158. Regex reg =
  159. new Regex(@"<meta[\s\S]+?charset=(.*)""[\s\S]+?>",
  160. RegexOptions.Multiline | RegexOptions.IgnoreCase);
  161. MatchCollection mc = reg.Matches(str);
  162. if (mc.Count > 0)
  163. {
  164. string tempCharSet = mc[0].Result("$1");
  165. if (string.Compare(tempCharSet, characterSet, true) != 0)
  166. {
  167. encode = Encoding.GetEncoding(tempCharSet);
  168. str = string.Empty;
  169. mStream.Seek(0, SeekOrigin.Begin);
  170. reader = new StreamReader(mStream, encode);
  171. buffer = new char[255];
  172. count = reader.Read(buffer, 0, 255);
  173. while (count > 0)
  174. {
  175. str += new String(buffer, 0, count);
  176. count = reader.Read(buffer, 0, 255);
  177. }
  178. }
  179. }
  180. reader.Close();
  181. mStream.Close();
  182. }
  183. }
  184. catch (Exception ex)
  185. {
  186. Trace.TraceError(ex.ToString());
  187. }
  188. finally
  189. {
  190. if (response != null)
  191. response.Close();
  192. }
  193. return str;
  194. }
  195. ///<summary>
  196. /// 从一段网页源码中获取正文
  197. ///</summary>
  198. ///<param name="input"></param>
  199. ///<returns></returns>
  200. public static string GetMainContent(string input)
  201. {
  202. string reg1 = @"<(p|br)[^<]*>";
  203. string reg2 =
  204. @"(

    ([^=]*)(=[^

    ]*)?\][\s\S]*?

    /\1

    )|(?<lj>(?=[^\u4E00-\u9FA5\uFE30-\uFFA0,."");])<a\s+[^>]*>[^<]{2,}</a>(?=[^\u4E00-\u9FA5\uFE30-\uFFA0,."");]))|(?<Style><style[\s\S]+?/style>)|(?<select><select[\s\S]+?/select>)|(?<Script><script[\s\S]*?/script>)|(?<Explein><\!\-\-[\s\S]*?\-\->)|(?<li><li(\s+[^>]+)?>[\s\S]*?/li>)|(?<Html></?\s*[^> ]+(\s*[^=>]+?=[‘""]?[^""‘]+?[‘""]?)*?[^\[<]*>)|(?<Other>&[a-zA-Z]+;)|(?<Other2>\#[a-z0-9]{6})|(?<Space>\s+)|(\&\#\d+\;)";

  205. //1、获取网页的所有div标签
  206. List<string> list = GetTags(input, "div");
  207. //2、去除汉字少于200字的div
  208. List<string> needToRemove = new List<string>();
  209. foreach (string s in list)
  210. {
  211. Regex r = new Regex("[\u4e00-\u9fa5]");
  212. if (r.Matches(s).Count < 300)
  213. {
  214. needToRemove.Add(s);
  215. }
  216. }
  217. foreach (string s in needToRemove)
  218. {
  219. list.Remove(s);
  220. }
  221. //3、把剩下的div按汉字比例多少倒序排列,
  222. list.Sort(CompareDinosByChineseLength);
  223. if (list.Count < 1)
  224. {
  225. return "";
  226. }
  227. input = list[list.Count - 1];
  228. //4、把p和br替换成特殊的占位符[p][br]
  229. input = new Regex(reg1, RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(input, "[$1]");
  230. //5、去掉HTML标签,保留汉字
  231. input = new Regex(reg2, RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(input, "");
  232. //6、把特殊占维护替换成回车和换行
  233. input = new Regex("\\[p]", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(input, "\r\n ");
  234. input = new Regex("\\[br]", RegexOptions.Multiline | RegexOptions.IgnoreCase).Replace(input, "\r\n");
  235. return input;
  236. }
  237. }
时间: 2024-10-14 09:49:29

c#实现网页正文抓取的相关文章

java 网页页面抓取标题和正文

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.reg

Android登录客户端,验证码的获取,网页数据抓取与解析,HttpWatch基本使用

大家好,我是M1ko.在互联网时代的今天,如果一个App不接入互联网,那么这个App一定不会有长时间的生命周期,因此Android网络编程是每一个Android开发者必备的技能,博主是在校大学生,自学Android一年半多,正好通过一个模拟登录校园网软件,来给大家演示如何在网页上抓取我们想要的数据,以及将数据Post给服务器.如果有什么错误或改进欢迎大家指正=-= ,如果想交流博主qq 136057505 好的废话不多说看一下我们的重点 Httpwatch等软件抓取Post请求 如何获取验证码

简述php关于网页元素抓取方面的技术

对于php抓取网页的内容,可能比较难的就是dom解析这一部分了,这儿的话有几种技术推荐给大家,具体使用哪种就看自己的喜欢了 1.php自带的xpath解析技术 xpath的话具体可以百度一下他的用法,我只举几个简单的例子,废话不多说,代码如下 <?php error_reporting(0); $url='http://www.baidu.com';//此处写抓取的网页的网址,我随便写的 $html=file_get_contents($url); $dom=new DOMDocument; $

C#网页爬虫抓取行政区划

借鉴C#网页爬虫抓取行政区划,从国家统计局获取了最新行政区域数据. 以下为代码贴片: 数据库类: public class City { public decimal ID { get; set; } public string Name { get; set; } public string Code { get; set; } public string Org_Level { get; set; } public string ParentCode { get; set; } public

网页中抓取数据

下面写个例子,实现从网页中抓取数据. 这个例子中,只是从网页中获取了数据,但是没有进行任何处理,只是将数据保存到一个txt文件中. 该例子是在android工程中写的. package com.example.creepertest; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.I

爬虫---selenium动态网页数据抓取

动态网页数据抓取 什么是AJAX: AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML.过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面.因为传统的在传输数据格式方面,使用的是XML语法.因此叫做AJAX,其实现在数据交互基本上都是使用JSON.使用AJAX加载的数据,即使使用了JS,将数

第四章爬虫进阶之动态网页数据抓取

动态网页数据抓取 什么是AJAX: AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML.过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面.因为传统的在传输数据格式方面,使用的是XML语法.因此叫做AJAX,其实现在数据交互基本上都是使用JSON.使用AJAX加载的数据,即使使用了JS,将数

htmlparser实现从网页上抓取数据

package parser; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.

网页数据抓取(B/S)

C# 抓取网页内容(转) 1.抓取一般内容 需要三个类:WebRequest.WebResponse.StreamReader 所需命名空间:System.Net.System.IO 核心代码: 1 WebRequest request = WebRequest.Create("http://www.cftea.com/"); 2 WebResponse response = request.GetResponse(); 3 StreamReader reader = new Stre