zoukankan      html  css  js  c++  java
  • c# 使用正则表达式 提取章节小说正文全本篇

           这一节主要内容是使用正则表达式提取网站的正文,主要面向于小说章节网站。其中涉及到一些其他知识点,比如异步读取、异步流写入等,代码中都会有详细的注解。现在流行的网络文学都是每日一更或几更,没有一个统一的下载入口。以下我将实现一个简单的章节小说下载器的功能,将章节小说以整本的形式下载保存,保守估计能下载网络上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, 0, response.Length - 1);
                    //获取网页字符编码描述信息   
                    var charSetMatch = Regex.Match(content, "<meta([^<]*)charset=([^<]*)"", RegexOptions.IgnoreCase | RegexOptions.Multiline);
    
                    string webCharSet = charSetMatch.Groups[2].Value;
                    if (chartSet == null || chartSet == "")
                        chartSet = webCharSet;
    
                    if (chartSet != null && chartSet != "" && Encoding.GetEncoding(chartSet) != Encoding.Default)
                        content = Encoding.GetEncoding(chartSet).GetString(response, 0, response.Length - 1);
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                //小说主域名
                if (webSiteDomain.Length == 0)
                {
                    var websiteDomainMath = Regex.Match(url, "(http).*(/)", RegexOptions.IgnoreCase);
                    webSiteDomain = websiteDomainMath.Groups[0].Value;
                }
    
                //标题信息
                var titleInfoMath = Regex.Match(content, "(<title>)([^>]*)(</title>)", RegexOptions.IgnoreCase | RegexOptions.Multiline);
                title = titleInfoMath.Groups[2].Value;
    
                content = content.Replace("'", """).Replace("
    ", "");
    
    
                for (int i = 0; i < contextPatterns.Length; i++)
                {
                    var cpattern = contextPatterns[i];
                    if (novelInfo.Length == 0)
                    {    
                        //正文信息
                        var webInfoMath = Regex.Matches(content, cpattern, RegexOptions.IgnoreCase | RegexOptions.Multiline);
    
                        for (int j = 0; j < webInfoMath.Count; j++)
                        {
                            foreach (Group g in webInfoMath[j].Groups)
                            {
                                var value = Regex.Split(g.Value, contextNewLine, RegexOptions.IgnoreCase);
                                if (value.Length > 5)
                                {
                                    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 => "
    "));
                                    break;
                                }
                            }
                        }
    
    
                    }
                    else
                        break;
                }
    
                bytes = null;
    
                for (int i = 0; i < nextPagePatterns.Length; i++)
                {
                    if (nextPageUrl.Length == 0)
                    {
                        //下一页信息
                        var webNextPageMath = Regex.Match(content, nextPagePatterns[i], RegexOptions.IgnoreCase | RegexOptions.Multiline);
                        if (webNextPageMath.Groups.Count > 0)
                        {
                            foreach (Group g in webNextPageMath.Groups)
                            {
                                if (!g.Value.EndsWith("""))
                                    nextPageUrl = g.Value;
                                if (nextPageUrl.StartsWith("/"))
                                    nextPageUrl = nextPageUrl.Substring(1);
                                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 > 0)
                    {
                        writeNovelLog("正在下载章节:" + title);
                    }
    
                    writeNovelLog("章节长度:" + novelInfo.Length);
    
                    cacheNovel.Add(title + novelInfo);
    
                    if (nextPageUrl.Length > 0)
                    {
                        writeNovelLog("下一页:" + nextPageUrl);
    
                        await downLoadNovel(bytes, nextPageUrl);
                    }
                    else
                    {
                        downloadFinish();
                    }
                }
                else
                {
                    writeNovelLog("存在重复的章节,章节名称:" + title + " 地址:" + url);
                    downloadFinish();
                }
            }
    异步下载网页流、解析数据

    最后效果

  • 相关阅读:
    神鬼传奇客户端解包图片(ui\common)
    电子书下载:Pro ASP.NET MVC 3 Framework 3rd Edition
    DDS工具
    Delphi2010中TResourceStream流使用
    电子书下载:Professional C# 4 and .NET 4
    电子书下载:Professional NoSQL
    电子书下载:C# Database Basics
    FancyCache要怎样设置才最大发挥硬盘的性能?
    完美时空Cube Engine 3D引擎
    DELPHI获取CPU信息
  • 原文地址:https://www.cnblogs.com/yzp12sina/p/3520321.html
Copyright © 2011-2022 走看看