心血来潮,想爬点小说。通过百度选择了个小说网站,随便找了一本小说http://www.23us.so/files/article/html/13/13655/index.html

1、分析html规则

思路是获取小说章节目录,循环目录,抓取所有章节中的内容,拼到txt文本中。最后形成完本小说。

1、获取小说章节目录

通过分析,我在标注的地方获取小说名字及章节目录。

  1. <meta name="keywords" content="无疆,无疆最新章节,无疆全文阅读"/>// 获取小说名字
  2. <table cellspacing="" cellpadding="" bgcolor="#E4E4E4" id="at">// 所有的章节都在这个table中。

下面是利用正则,获取名字与目录。

  1. //获取小说名字
  2. Match ma_name = Regex.Match(html, @"<meta name=""keywords"".+content=""(.+)""/>");
  3. string name = ma_name.Groups[].Value.ToString().Split(',')[];
  4.  
  5. //获取章节目录
  6. Regex reg_mulu = new Regex(@"<table cellspacing=""1"" cellpadding=""0"" bgcolor=""#E4E4E4"" id=""at"">(.|\n)*?</table>");
  7. var mat_mulu = reg_mulu.Match(html);
  8. string mulu = mat_mulu.Groups[].ToString();

2、获取小说正文内容

通过章节a标签中的url地址,查看章节内容。

通过分析,正文内容在<dd id="contents">中。

  1. //获取正文
  2. Regex reg = new Regex(@"<dd id=""contents"">(.|\n)*?</dd>");
  3. MatchCollection mc = reg.Matches(html_z);
  4. var mat = reg.Match(html_z);
  5. string content = mat.Groups[].ToString().Replace("<dd id=\"contents\">", "").Replace("</dd>", "").Replace("&nbsp;", "").Replace("<br />", "\r\n");

2、C#完整代码

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Text;
  8. using System.Text.RegularExpressions;
  9. using System.Web;
  10. using System.Web.Mvc;
  11.  
  12. namespace Test.Controllers
  13. {
  14. public class CrawlerController : BaseController
  15. {
  16. // GET: Crawler
  17. public void Index()
  18. {
  19. //抓取整本小说
  20. CrawlerController cra = new CrawlerController();//顶点抓取小说网站小说
  21. string html = cra.HttpGet("http://www.23us.so/files/article/html/13/13655/index.html", "");
  22.  
  23. //获取小说名字
  24. Match ma_name = Regex.Match(html, @"<meta name=""keywords"".+content=""(.+)""/>");
  25. string name = ma_name.Groups[].Value.ToString().Split(',')[];
  26.  
  27. //获取章节目录
  28. Regex reg_mulu = new Regex(@"<table cellspacing=""1"" cellpadding=""0"" bgcolor=""#E4E4E4"" id=""at"">(.|\n)*?</table>");
  29. var mat_mulu = reg_mulu.Match(html);
  30. string mulu = mat_mulu.Groups[].ToString();
  31.  
  32. //匹配a标签里面的url
  33. Regex tmpreg = new Regex("<a[^>]+?href=\"([^\"]+)\"[^>]*>([^<]+)</a>", RegexOptions.Compiled);
  34. MatchCollection sMC = tmpreg.Matches(mulu);
  35. if (sMC.Count != )
  36. {
  37. //循环目录url,获取正文内容
  38. for (int i = ; i < sMC.Count; i++)
  39. {
  40. //sMC[i].Groups[1].Value
  41. //0是<a href="http://www.23us.so/files/article/html/13/13655/5638725.html">第一章 泰山之巅</a>
  42. //1是http://www.23us.so/files/article/html/13/13655/5638725.html
  43. //2是第一章 泰山之巅
  44.  
  45. //获取章节标题
  46. string title = sMC[i].Groups[].Value;
  47.  
  48. //获取文章内容
  49. string html_z = cra.HttpGet(sMC[i].Groups[].Value, "");
  50.  
  51. //获取小说名字,章节中也可以查找名字
  52. //Match ma_name = Regex.Match(html, @"<meta name=""keywords"".+content=""(.+)"" />");
  53. //string name = ma_name.Groups[1].Value.ToString().Split(',')[0];
  54.  
  55. //获取标题,通过分析h1标签也可以得到章节标题
  56. //string title = html_z.Replace("<h1>", "*").Replace("</h1>", "*").Split('*')[1];
  57.  
  58. //获取正文
  59. Regex reg = new Regex(@"<dd id=""contents"">(.|\n)*?</dd>");
  60. MatchCollection mc = reg.Matches(html_z);
  61. var mat = reg.Match(html_z);
  62. string content = mat.Groups[].ToString().Replace("<dd id=\"contents\">", "").Replace("</dd>", "").Replace("&nbsp;", "").Replace("<br />", "\r\n");
  63.  
  64. //txt文本输出
  65. string path = AppDomain.CurrentDomain.BaseDirectory.Replace("\\", "/") + "Txt/";
  66. Novel(title + "\r\n" + content, name, path);
  67. }
  68. }
  69. }
  70.  
  71. /// <summary>
  72. /// 创建文本
  73. /// </summary>
  74. /// <param name="content">内容</param>
  75. /// <param name="name">名字</param>
  76. /// <param name="path">路径</param>
  77. public void Novel(string content, string name, string path)
  78. {
  79. string Log = content + "\r\n";
  80. //创建文件夹,如果不存在就创建file文件夹
  81. if (Directory.Exists(path) == false)
  82. {
  83. Directory.CreateDirectory(path);
  84. }
  85.  
  86. //判断文件是否存在,不存在则创建
  87. if (!System.IO.File.Exists(path + name + ".txt"))
  88. {
  89. FileStream fs1 = new FileStream(path + name + ".txt", FileMode.Create, FileAccess.Write);//创建写入文件
  90. StreamWriter sw = new StreamWriter(fs1);
  91. sw.WriteLine(Log);//开始写入值
  92. sw.Close();
  93. fs1.Close();
  94. }
  95. else
  96. {
  97. FileStream fs = new FileStream(path + name + ".txt" + "", FileMode.Append, FileAccess.Write);
  98. StreamWriter sr = new StreamWriter(fs);
  99. sr.WriteLine(Log);//开始写入值
  100. sr.Close();
  101. fs.Close();
  102. }
  103. }
  104.  
  105. //Post
  106. public string HttpPost(string Url, string postDataStr)
  107. {
  108. CookieContainer cookie = new CookieContainer();
  109. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
  110. request.Method = "POST";
  111. request.ContentType = "application/x-www-form-urlencoded";
  112. request.ContentLength = Encoding.UTF8.GetByteCount(postDataStr);
  113. request.CookieContainer = cookie;
  114. Stream myRequestStream = request.GetRequestStream();
  115. StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("gb2312"));
  116. myStreamWriter.Write(postDataStr);
  117. myStreamWriter.Close();
  118.  
  119. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  120.  
  121. response.Cookies = cookie.GetCookies(response.ResponseUri);
  122. Stream myResponseStream = response.GetResponseStream();
  123. StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
  124. string retString = myStreamReader.ReadToEnd();
  125. myStreamReader.Close();
  126. myResponseStream.Close();
  127.  
  128. return retString;
  129. }
  130.  
  131. //Get
  132. public string HttpGet(string Url, string postDataStr)
  133. {
  134. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr);
  135. request.Method = "GET";
  136. HttpWebResponse response;
  137. request.ContentType = "text/html;charset=UTF-8";
  138. try
  139. {
  140. response = (HttpWebResponse)request.GetResponse();
  141. }
  142. catch (WebException ex)
  143. {
  144. response = (HttpWebResponse)request.GetResponse();
  145. }
  146.  
  147. Stream myResponseStream = response.GetResponseStream();
  148. StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
  149. string retString = myStreamReader.ReadToEnd();
  150. myStreamReader.Close();
  151. myResponseStream.Close();
  152.  
  153. return retString;
  154. }
  155. }
  156. }

3、最后效果


4、补充

wlong 同学提了个建议,说用NSoup解析html更方便,我就去查了查,目前没有太大的感触,可能不太会用。DLL下载地址http://nsoup.codeplex.com/

NSoup版:

  1. NSoup.Nodes.Document doc = NSoup.NSoupClient.Parse(html);
  2. //获取小说名字
  3. //<meta name="keywords" content="无疆,无疆最新章节,无疆全文阅读"/>
    //获取meta
  4. NSoup.Select.Elements ele = doc.GetElementsByTag("meta");
  5. string name = "";
  6. foreach (var i in ele)
  7. {
  8. if (i.Attr("name") == "keywords")
  9. {
  10. name = i.Attr("content").ToString();
  11. }
  12. }
  13. //获取章节
  14. NSoup.Select.Elements eleChapter = doc.GetElementsByTag("table");//查找table,获取table里的html
  15. NSoup.Nodes.Document docChild = NSoup.NSoupClient.Parse(eleChapter.ToString());
  16. NSoup.Select.Elements eleChild = docChild.GetElementsByTag("a");//查找a标签
  17. //循环目录,获取正文内容
  18. foreach (var j in eleChild)
  19. {
  20. string title = j.Text();//获取章节标题
  21.  
  22. string htmlChild = cra.HttpGet(j.Attr("href").ToString(), "");//获取文章内容
  23. }

HtmlAgilityPack版(NaYoung提供):

DLL下载地址:HtmlAgilityPack.1.4.6.zip

  1. HtmlWeb htmlWeb = new HtmlWeb();
  2. HtmlDocument document = htmlWeb.Load("http://www.23us.so/files/article/html/13/13694/index.html");
  3. HtmlNodeCollection nodeCollection = document.DocumentNode.SelectNodes(@"//table/tr/td/a[@href]"); //代表获取所有
  4. string name = document.DocumentNode.SelectNodes(@"//meta[@name='keywords']")[].GetAttributeValue("content", "").Split(',')[];
  5. foreach (var node in nodeCollection)
  6. {
  7. HtmlAttribute attribute = node.Attributes["href"];
  8. String val = attribute.Value; //章节url
  9. var title = htmlWeb.Load(val).DocumentNode.SelectNodes(@"//h1")[].InnerText; //文章标题
  10. var doc = htmlWeb.Load(val).DocumentNode.SelectNodes(@"//dd[@id='contents']");
  11. var content = doc[].InnerHtml.Replace("&nbsp;", "").Replace("<br>", "\r\n"); //文章内容
  12. //txt文本输出
  13. string path = AppDomain.CurrentDomain.BaseDirectory.Replace("\\", "/") + "Txt/";
  14. Novel(title + "\r\n" + content, name, path);
  15. }

Jumony版:

C# 爬虫 Jumony-html解析

C# 爬虫 抓取小说的更多相关文章

  1. Python 爬虫-抓取小说《盗墓笔记-怒海潜沙》

    最近想看盗墓笔记,看了一下网页代码,竟然不是js防爬虫,那就用简单的代码爬下了一节: """ 爬取盗墓笔记小说-七星鲁王宫 """ from ...

  2. Python 爬虫-抓取小说《鬼吹灯之精绝古城》

    想看小说<鬼吹灯之精绝古城>,可是网页版的好多广告,还要一页一页的翻,还无法复制,于是写了个小爬虫,保存到word里慢慢看. 代码如下: """ 爬取< ...

  3. C# 爬虫 正则、NSoup、HtmlAgilityPack、Jumony四种方式抓取小说

    心血来潮,想爬点小说.通过百度选择了个小说网站,随便找了一本小说http://www.23us.so/files/article/html/13/13655/index.html. 1.分析html规 ...

  4. 笔趣看小说Python3爬虫抓取

    笔趣看小说Python3爬虫抓取 获取HTML信息 解析HTML信息 整合代码 获取HTML信息 # -*- coding:UTF-8 -*- import requests if __name__ ...

  5. 爬虫技术 -- 进阶学习(七)简单爬虫抓取示例(附c#代码)

    这是我的第一个爬虫代码...算是一份测试版的代码.大牛大神别喷... 通过给定一个初始的地址startPiont然后对网页进行捕捉,然后通过正则表达式对网址进行匹配. List<string&g ...

  6. Node.js爬虫抓取数据 -- HTML 实体编码处理办法

    cheerio DOM化并解析的时候 1.假如使用了 .text()方法,则一般不会有html实体编码的问题出现 2.如果使用了 .html()方法,则很多情况下(多数是非英文的时候)都会出现,这时, ...

  7. python 爬虫抓取心得

    quanwei9958 转自 python 爬虫抓取心得分享 urllib.quote('要编码的字符串') 如果你要在url请求里面放入中文,对相应的中文进行编码的话,可以用: urllib.quo ...

  8. 爬虫技术(四)-- 简单爬虫抓取示例(附c#代码)

    这是我的第一个爬虫代码...算是一份测试版的代码.大牛大神别喷... 通过给定一个初始的地址startPiont然后对网页进行捕捉,然后通过正则表达式对网址进行匹配. List<string&g ...

  9. 如何利用Python网络爬虫抓取微信朋友圈的动态(上)

    今天小编给大家分享一下如何利用Python网络爬虫抓取微信朋友圈的动态信息,实际上如果单独的去爬取朋友圈的话,难度会非常大,因为微信没有提供向网易云音乐这样的API接口,所以很容易找不到门.不过不要慌 ...

随机推荐

  1. (转)Linux命令grep

    场景:grep命令在文件搜索中经常会使用到,所以熟练掌握该命令对于日常日志搜索相当有必要! Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.g ...

  2. (转)SqlServer基础之(触发器)(清晰易懂)

    阅读目录 一:触发器的优点 二:触发器的作用 三:触发器的分类 四:触发器的工作原理 五:创建触发器 六:管理触发器 概念:   触发器(trigger)是SQL server 提供给程序员和数据分析 ...

  3. robot framework 怎么点击文本总结

    点击文本有一下几种方式 1.

  4. Qt5构建出错问题解决办法

    我之前用的Qt其他版本,因为一些原因我更换了Qt版本,从Qt5.9.1又更换到之前用的Qt5.3.2,但是发现无法build,问题提示如下: 19:54:03: 为项目untitled执行步骤 ... ...

  5. 使用Modelsim进行简单仿真

    这里记载一下使用modelsim进行简单的仿真,方便以后使用的时候进行查看.所谓的简单的仿真,就是没有IP核.只用图形界面不用tcl脚本进行的仿真.简单的仿真步骤为: 1.改变路径到工作环境下的路径下 ...

  6. webpack开发与生产环境配置

    前言 作者去年就开始使用webpack, 最早的接触就来自于vue-cli.那个时候工作重点主要也是 vue 的使用,对webpack的配置是知之甚少,期间有问题也是询问大牛 @吕大豹.顺便说一句,对 ...

  7. 暑假集训D11总结

    %dalao 今天某学长来讲一个极其高深的数据结构——线段树(woc哪里高深了),然而并没有时间整理笔记= =,所以明天在扔笔记咯= = 考试 今天考试,一看数据范围,woc暴力分给的真足,然后高高兴 ...

  8. 种下一棵树:有旋Treap

    第一个平衡树板子,有旋Treap.用随机函数规定一个堆,维护点权的同时维护堆的性质,可以有效地避免退化成链.按我的理解,建立一棵二叉排序树,树的形态会和给出节点的顺序有关.按照出题人很机智定理,数据肯 ...

  9. 使用jquery获取url及url参数的方法

    使用jquery获取url以及使用jquery获取url参数是我们经常要用到的操作 1.jquery获取url很简单,代码如下: window.location.href; 其实只是用到了javasc ...

  10. 让这三个月来的更猛烈些吧,前端react同构项目

    昨天一篇文章讲述了我在这三个月中由.net到java的过程,其中踩坑填坑的细节真不是三言两语可以道尽,而完成时的喜悦也远非寻常可比(仅次于涨工资).然而到这并不算完结,作为前后端分离的忠实粉丝,我认为 ...