这一节主要内容是使用正则表达式提取网站的正文,主要面向于小说章节网站。其中涉及到一些其他知识点,比如异步读取、异步流写入等,代码中都会有详细的注解。现在流行的网络文学都是每日一更或几更,没有一个统一的下载入口。以下我将实现一个简单的章节小说下载器的功能,将章节小说以整本的形式下载保存,保守估计能下载网络上70%以上小说。

先看看小说网站的网页源码,天蚕土豆的大主宰第一章。

http://www.biquge.com/4_4606/991334.html 笔趣网

http://www.fqxsw.com/html/11739/4636404.html 番茄小说网

 正文正则

结果发现正文内容一般都是嵌套在div中,样式表可能会略有不同,所以正则表达式可以这样表示

(<div).*</div>

当然有div标签的不一定是正文内容,还有可能是其中不相关的数据。那么按照一般小说的规律,我们指定一个匹配符。

<br\\s*>

只有当匹配符超过5个以上的,我们才认为这是正文内容。

下一页正则

再来找下一页的链接。下一页的链接的格式一般存在两种格式

或是

所以正则表达式可以这样表示

<a.*href=(")(([^<]*[^"])[^>])(\s*)?>.*((→)|(下一页))

异步读取网页流

读取网页数据使用HttpClient异步方法,在读取过程中将主控制权返回到UI层,不会阻塞界面。具体原理请查看我上一篇文章

await httpClient.GetByteArrayAsync(url);

配置文件

为了匹配更多的网站信息,我把正则表达式存在一个ini文件中,在需要的时候可以继续扩充。

核心代码

    private async Task downLoadNovel(byte[] bytes, string url)
{
title = string.Empty;
nextPageUrl = string.Empty;
content = string.Empty;
novelInfo = string.Empty; try
{
byte[] response = bytes;
if (bytes == null)
{
response = await httpClient.GetByteArrayAsync(url);
}
content = Encoding.Default.GetString(response, , response.Length - );
//获取网页字符编码描述信息
var charSetMatch = Regex.Match(content, "<meta([^<]*)charset=([^<]*)\"", RegexOptions.IgnoreCase | RegexOptions.Multiline); string webCharSet = charSetMatch.Groups[].Value;
if (chartSet == null || chartSet == "")
chartSet = webCharSet; if (chartSet != null && chartSet != "" && Encoding.GetEncoding(chartSet) != Encoding.Default)
content = Encoding.GetEncoding(chartSet).GetString(response, , response.Length - );
}
catch (Exception ex)
{
throw ex;
}
//小说主域名
if (webSiteDomain.Length == )
{
var websiteDomainMath = Regex.Match(url, "(http).*(/)", RegexOptions.IgnoreCase);
webSiteDomain = websiteDomainMath.Groups[].Value;
} //标题信息
var titleInfoMath = Regex.Match(content, "(<title>)([^>]*)(</title>)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
title = titleInfoMath.Groups[].Value; content = content.Replace("'", "\"").Replace("\r\n", ""); for (int i = ; i < contextPatterns.Length; i++)
{
var cpattern = contextPatterns[i];
if (novelInfo.Length == )
{
//正文信息
var webInfoMath = Regex.Matches(content, cpattern, RegexOptions.IgnoreCase | RegexOptions.Multiline); for (int j = ; j < webInfoMath.Count; j++)
{
foreach (Group g in webInfoMath[j].Groups)
{
var value = Regex.Split(g.Value, contextNewLine, RegexOptions.IgnoreCase);
if (value.Length > )
{
novelInfo = g.Value;
foreach (var pattern in filterPatterns)
novelInfo = Regex.Replace(novelInfo, pattern, new MatchEvaluator(p => null)); novelInfo = Regex.Replace(novelInfo, contextNewLine, new MatchEvaluator(p => "\r\n"));
break;
}
}
} }
else
break;
} bytes = null; for (int i = ; i < nextPagePatterns.Length; i++)
{
if (nextPageUrl.Length == )
{
//下一页信息
var webNextPageMath = Regex.Match(content, nextPagePatterns[i], RegexOptions.IgnoreCase | RegexOptions.Multiline);
if (webNextPageMath.Groups.Count > )
{
foreach (Group g in webNextPageMath.Groups)
{
if (!g.Value.EndsWith("\""))
nextPageUrl = g.Value;
if (nextPageUrl.StartsWith("/"))
nextPageUrl = nextPageUrl.Substring();
if (!nextPageUrl.StartsWith("http", true, null) && (Regex.IsMatch(nextPageUrl, "[a-z]") || Regex.IsMatch(nextPageUrl, "[0-9]")) && !url.EndsWith(nextPageUrl))
{
nextPageUrl = webSiteDomain + nextPageUrl;
}
try
{
bytes = await httpClient.GetByteArrayAsync(nextPageUrl);
break;
}
catch
{
continue;
}
} }
}
else
break;
}
bool isAdd = false;
cacheNovel.ForEach(p =>
{
if (p == (title + novelInfo))
{
isAdd = true;
}
}); if (!isAdd)
{
if (title.Length > )
{
writeNovelLog("正在下载章节:" + title);
} writeNovelLog("章节长度:" + novelInfo.Length); cacheNovel.Add(title + novelInfo); if (nextPageUrl.Length > )
{
writeNovelLog("下一页:" + nextPageUrl); await downLoadNovel(bytes, nextPageUrl);
}
else
{
downloadFinish();
}
}
else
{
writeNovelLog("存在重复的章节,章节名称:" + title + " 地址:" + url);
downloadFinish();
}
}

异步下载网页流、解析数据

最后效果

c# 使用正则表达式 提取章节小说正文全本篇的更多相关文章

  1. 将RegEx(正则表达式提取器)与JMeter一起使用

    JMeter的,最流行的开源性能测试工具,可以工作正则表达式,用正则表达式提取.正则表达式是一种用于通过使用高级操作提取文本的必需部分的工具.正则表达式在测试Web应用程序时很流行,因为它们可用于验证 ...

  2. JMeter中的关联-正则表达式提取(2)

    JMeter获取正则表达式中的提取的所有关联值的解决方法: 需求如下: { : ", : "results": : [ : : { : : : "total_e ...

  3. JMeter中的关联-正则表达式提取(1)

    运用Jmeter正则提取器,可以从请求的响应结果中取到需要的内容,从而实现关联. jmeter之关联 的个人理解: 关联是请求与请求之间存在数据依赖关系,需要从上一个请求获取下一个请求需要回传回去的数 ...

  4. asp.net正则表达式提取网页网址、标题、图片实例以及过滤所有HTML标签实例

    无论你用什么语言,正则表达式的处理方法都是非常灵活.高效的,尤其是对某些字符串的抓取.过滤方面,更显其优势. 正则表达式的写法通常比较简单,几行短代码便能轻松完成看似很复杂的事情,更值得称赞的是,它的 ...

  5. Jmeter—5 关联 响应数据传递-正则表达式提取器

    在测试过程中,遇到一个问题:用户登录成功后服务器会返回一个登录凭证,之后所有的操作都需要带上此凭证.我们怎么获取登录凭证并传递给后续的操作? Jmeter提供了正则表达式提取器,用变量提取参数,后续通 ...

  6. JMeter学习-011-JMeter 后置处理器实例之 - 正则表达式提取器(三)多参数获取进阶引用篇

    前两篇文章分表讲述了 后置处理器 - 正则表达式提取器概述及简单实例.多参数获取,相应博文敬请参阅 简单实例.多参数获取. 此文主要讲述如何引用正则表达式提取器获取的数据信息.其实,正则表达式提取器获 ...

  7. JMeter学习-009-JMeter 后置处理器实例之 - 正则表达式提取器(二)多参数获取

    前文简述了通过后置处理器 - 正则表达式提取器 获取 HTTP请求 响应结果中的特定数据,未看过的亲,敬请参阅 JMeter学习-008-JMeter 后置处理器实例之 - 正则表达式提取器(一). ...

  8. JMeter学习-008-JMeter 后置处理器实例之 - 正则表达式提取器(一)概述及简单实例

    上文我们讲述了如何对 HTTP请求 的响应数据进行断言,以判断响应是否符合我们的预期,敬请参阅:JMeter学习-007-JMeter 断言实例之一 - 响应断言 那么我们如何获取 HTTP请求 响应 ...

  9. Jmeter正则表达式提取器的使用方法(转)

    下面简单介绍一下Jmeter正则表达式提取器的使用方法. 1.添加Jmeter正则表达式提取器:在具体的Request下添加Jmeter正则表达式提取器(Jmeter正则表达式在“后置处理器”下面)  ...

随机推荐

  1. 快还要更快,让PHP 7 运行更加神速

    导读 PHP 7 比5.x 快上很多,即使只有单纯的版本升级就已经很有感,不过大家还是希望它变得越来越快,这时再做些小调整就会更有fu,Let's try it! 事前准备 说到PHP 7,那一定跑不 ...

  2. ASP注入靶机

     ASP:   <%  Dim Db,MyDbPath dim conn '可修改设置一:========================定义数据库类别,1为SQL数据库,0为Access数据库 ...

  3. 三款SDR平台对比:HackRF,bladeRF和USRP

    这篇文章是Taylor Killian今年8月发表在自己的博客上的.他对比了三款平价的SDR平台,认为这三款产品将是未来一年中最受欢迎的SDR平台.我觉得这篇文章很有参考价值,简单翻译一份转过来.原文 ...

  4. 又一款linux提权辅助工具

    又一款linux提权辅助工具 – Linux_Exploit_Suggester 2013-09-06 10:34 1455人阅读 评论(0) 收藏 举报 https://github.com/Pen ...

  5. ASP.NET MVC 的URL路由介绍

    在这个教程中,向你介绍每个ASP.NET MVC一个重要的特点叫做URL路由.URL路由模块是负责映射从浏览器请求到特定的控制器动作. 在教程的第一部分,你将学习标准路由表如何映射到控制器的动作.在教 ...

  6. String是引用类型

    关于String为值类型还是引用类型的讨论一直没有平息,最近一直在研究性能方面的问题,今天再次将此问题进行一次明确.希望能给大家带来点帮助. 如果有错误请指出. 来看下面例子: //值类型 ; int ...

  7. hdu2089

    基本的数位dp #include <cstdio> #include <cstring> using namespace std; #define D(x) x ; int n ...

  8. ios获取一个文件夹下的文件(夹)列表

    NSArray* ary=[[NSFileManager defaultManager] contentsOfDirectoryAtPath:[[NSBundle mainBundle] pathFo ...

  9. discuz 学习

    一.Discuz首页“今日”“昨日”“欢迎新会员”等文字删除添加 搜索templeta/default/forum/discuz.htm   (使用非默认模版的请修改当前使用模版的discuz.htm ...

  10. Action返回类型

    1.返回ascx页面return PartialView(); 2.Content(),返回文本ContentResultreturn Content("这是一段文本"); 3.J ...