聊一聊.NET的网页抓取和编码转换

这篇具有很好参考价值的文章主要介绍了聊一聊.NET的网页抓取和编码转换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在本文中,你会了解到两种用于 HTML 解析的类库。另外,我们将讨论关于网页抓取,编码转换和压缩处理的知识,以及如何在 .NET 中实现它们,最后进行优化和改进。

1. 背景

有了 Copilot 的加持,可以让我们快速的完成开发任务,并在极短的时间内完成小工具的开发。谁能想到现如今,写的代码注释却是为了给 AI 看,甚至不需要写注释,AI 都能猜的懂你的意图。如今代码本身更是不值钱了,只有产品才能体现它的价值。

因为平时会看小说作为娱乐消遣,习惯使用本地纯文本的阅读器,这就涉及到小说的下载,有的网站是提供有 TXT 的直接下载,但有的小说网站就没有提供。当然我也有用过 uncle-novel 这样类似的工具,用起来也还是很不错的,但总感觉有些不是很顺手。

2. 网页抓取

在.NET中,HtmlAgilityPack 库是经常使用的 HTML 解析工具,为解析 DOM 提供了足够强大的功能支持,经常用于网页抓取分析任务。

var web = new HtmlWeb();
var doc = web.Load(url);

在我写的小工具中也使用了这个工具库,小工具用起来也是顺手,直到前几天抓取一个小说时,发现竟出现了乱码,这才意识到之前抓取的网页均是 UTF-8 的编码,今次这个是 GBK 的。

虽然 HtmlAgilityPack 提供了 AutoDetectEncoding 功能,也是默认开启状态,但是似乎实际效果并没有起效。通过使用 HttpClient 拿到htmlStream 后喂给 HtmlDocument 启用 OptionReadEncoding 也是一样。

3. 编码转换

既如此,那就直接用 HttpClient 抓了再说,虽然解析还是逃不过 HtmlAgilityPack。对于 GBK 的支持,这里则需要引入System.Text.Encoding.CodePages 包。

对于抓取的网页内容我们先读取 bytes 然后以 UTF-8 编码读取后,通过正则解析出网页的实际的字符编码,并根据需要进行转换。

var client = new HttpClient();
var response = await client.GetAsync(url);
var bytes = await response.Content.ReadAsByteArrayAsync();
var htmldoc = Encoding.UTF8.GetString(bytes);
var match = Regex.Match(htmldoc, "<meta.*?charset=\"?(?<charset>.*?)\".*?>", RegexOptions.IgnoreCase);

4. 网页压缩处理

在使用 HttpClient 抓取网页时,最好是加入个请求头进行伪装一番,Copilot 也是真的省事,注释“设置请求头”一写直接回车,都不用去搜浏览器 UA 的。说起搜索,基本上搜索除了要被搜索引擎的广告折磨外,也有可能被某些吸引人的热搜转移精力,然后就没有然后了……

不过,这次回车可能敲多了,把我敲坑里了。本来只是想加个 UA,觉得提示的也还挺有用的,最后加了一堆:

// 设置请求头
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
    "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36");
client.DefaultRequestHeaders.Add("Accept", "*/*");
client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.9");
client.DefaultRequestHeaders.Add("Connection", "keep-alive");

然后我测试一番,发现我的代码就不能跑了,人麻了,该不是网站有什么高深的防火墙吧:

聊一聊.NET的网页抓取和编码转换,.NET,.net,爬虫

调试了半天,才想起来,莫不是因为加入了压缩的请求头吧?

聊一聊.NET的网页抓取和编码转换,.NET,.net,爬虫

注释掉再次测试,果然是它。哎,本想着你好我好大家好,加上压缩,这抓的速度更快,对面也省流量。

不过,注释是不可能注释掉的,遇到问题就解决问题,直接问 GPT 就是了。大段大段复杂的解决方法,解压缩的方式这里就不说了。当我告诉 GPT 我用的最新的 .NET 开发,你给我优雅一些后,它果然就优雅了起来:

var handler = new HttpClientHandler  
{  
    AutomaticDecompression = System.Net.DecompressionMethods.GZip | System.Net.DecompressionMethods.Deflate  | System.Net.DecompressionMethods.Brotli
};  
var httpClient = new HttpClient(handler);

毕竟 HttpClient 是支持自动处理压缩的。可以使用 HttpClientHandler 来启用自动解压缩功能,确实比去找官方文档方便的多。

5. 代码优化

通过前面的调整,我们基本已经写好了核心代码。当然,优化的空间还是很大的,这里我们可以直接请 GPT4 来帮忙处理:

/// <summary>
/// 下载网页内容,并将其他编码转换为 UTF-8 编码
/// </summary>
static async Task<string> GetWebHtml(string url){
    // 使用 HttpClient 下载网页内容

    var handler = new HttpClientHandler();
    // 忽略证书错误
    handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
    handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate | DecompressionMethods.Brotli;
    var client = new HttpClient(handler);
    // 设置请求头
    client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
        "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36");
    client.DefaultRequestHeaders.Add("Accept", "*/*");
    // 加上后不处理解压缩会乱码
    client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br");
    client.DefaultRequestHeaders.Add("Accept-Language", "zh-CN,zh;q=0.9");
    client.DefaultRequestHeaders.Add("Connection", "keep-alive");
    var response = await client.GetAsync(url);
    var bytes = await response.Content.ReadAsByteArrayAsync();

    // 获取网页编码 ContentType 可能为空,从网页获取
    var charset = response.Content.Headers.ContentType?.CharSet;
    if (string.IsNullOrEmpty(charset))
    {
        // 从网页获取编码信息
        var htmldoc = Encoding.UTF8.GetString(bytes);
        var match = Regex.Match(htmldoc, "<meta.*?charset=\"?(?<charset>.*?)\".*?>", RegexOptions.IgnoreCase);
        if (match.Success) charset = match.Groups["charset"].Value;
        else charset = "utf-8";
    }

    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
    Encoding encoding;

    switch (charset.ToLower())
    {
        case "gbk":
            encoding = Encoding.GetEncoding("GBK");
            break;
        case "gb2312":
            encoding = Encoding.GetEncoding("GB2312");
            break;
        case "iso-8859-1":
            encoding = Encoding.GetEncoding("ISO-8859-1");
            break;
        case "ascii":
            encoding = Encoding.ASCII;
            break;
        case "unicode":
            encoding = Encoding.Unicode;
            break;
        case "utf-32":
            encoding = Encoding.UTF32;
            break;
        default:
            return Encoding.UTF8.GetString(bytes);
    }

    // 统一转换为 UTF-8 编码
    var html = Encoding.UTF8.GetString(Encoding.Convert(encoding, Encoding.UTF8, bytes));
    return html;
}

5.1 更换 Html 解析库

事情的起因是 HtmlAgilityPack 库的自动编码解析出现了问题,那么有没有其他替代的库呢?

当然,GPT4 推荐了 AngleSharp ,这个库我简单测试了一下,无需配置可以直接识别网页编码,看起来是比 HtmlAgilityPack 好用一些。另外,其还支持输出 Javascript、Linq 语法、ID 和 Class 选择器、动态添加节点、支持 Xpath 语法。

总的来说,此番虽然是造了轮子,但是编程知识却是增加了嘛。

聊一聊.NET的网页抓取和编码转换,.NET,.net,爬虫

5.2 对于轮子的优化

虽然有以下要优化的地方,但是真的不如直接换轮子来的方便啊,因为换了轮子就没有下面的问题了:

  1. 对于实际的使用,使用静态的 HttpClient 实例,而不是为每个请求创建一个新的 HttpClient 实例。这可以避免不必要的资源浪费。可以将其及其配置移到一个单独的帮助类中如:HttpClientHelper,并在需要时访问它。

  2. 这里我们单独写了一个函数,在其中使用了额外的编码注册 Encoding.RegisterProvider(CodePagesEncodingProvider.Instance),在实际使用中,应该将其放在程序启动时执行。这样,只需在程序启动时注册一次编码提供程序,而不是每次调用方法时都注册。

  3. 其他一些写法上的优化,如 switch 和方法命名等。

6. 最后

这篇文章是我在开发 BookMaker 小工具时的一些关于网页抓取的心得,主要介绍了两个 Html 解析库,解决了编码转换和压缩的一些问题,希望对大家能有所帮助。文章来源地址https://www.toymoban.com/news/detail-526024.html

到了这里,关于聊一聊.NET的网页抓取和编码转换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python爬虫抓取网页

    本节讲解第一个 Python 爬虫实战案例:抓取您想要的网页,并将其保存至本地计算机。 首先我们对要编写的爬虫程序进行简单地分析,该程序可分为以下三个部分: 拼接 url 地址 发送请求 将照片保存至本地 明确逻辑后,我们就可以正式编写爬虫程序了。 本节内容使用 urll

    2024年02月08日
    浏览(32)
  • 爬虫项目(五):抓取网页所有图片

    推荐本人书籍《Python网络爬虫入门到实战》 ,详细介绍见👉: 《Python网络爬虫入门到实战》 书籍介绍 原理:抓取该链接中所有的图片格式。基于selenium来获取,自动下载到output文件夹中。

    2024年02月07日
    浏览(39)
  • 如何使用 Python 爬虫抓取动态网页数据

    随着 Web 技术的不断发展,越来越多的网站采用了动态网页技术,这使得传统的静态网页爬虫变得无能为力。本文将介绍如何使用 Python 爬虫抓取动态网页数据,包括分析动态网页、模拟用户行为、使用 Selenium 等技术。 在进行动态网页爬取之前,我们需要先了解动态网页和静

    2023年04月24日
    浏览(45)
  • 聊一聊synchronized

    在 Java 中, synchronized 可以用于实现线程同步,有以下几种常见的使用方式: 修饰代码块:将 synchronized 放在代码块的前面, 例如: 在这种方式下,会为给定的对象 obj 获取锁,在代码块执行期间,只有持有该锁的线程才能进入代码块执行。 修饰方法:将 sync

    2024年01月22日
    浏览(46)
  • 聊一聊 TLS/SSL

    哈喽大家好,我是咸鱼 当我们在上网冲浪的时候,会在浏览器界面顶部看到一个小锁标志,或者网址以 \\\"https://\\\" 开头 这意味着我们正在使用 TLS/SSL 协议进行安全通信。虽然它可能看起来只是一个小小的锁图标和一个 “https” ,但实际上,这个协议在保护我们的在线隐私和安

    2024年02月08日
    浏览(41)
  • 聊一聊模板方法模式

    统一抽取,制定规范; 模板方法模式,又叫模板模式,属于23种设计模式中的 行为型模式 。在抽象类中公开定义了执行的方法,子类可以按需重写其方法,但是要以抽象类中定义的方式调用方法。总结起来就是: 定义一个操作的算法结构,而将一些步骤延迟到子类中。在不

    2024年02月04日
    浏览(38)
  • 聊一聊AIGC

    “UGC不存在了”——借鉴自《三体》 ChatGPT 的横空出世将一个全新的概念推上风口——AIGC( AI Generated Content)。 GC即创作内容(Generated Content),和传统的UGC、PGC,OGC不同的是,AIGC的创作主体由人变成了人工智能。 xGC PGC:Professionally Generated Content,专业生产内容 UGC:User G

    2024年02月10日
    浏览(51)
  • 聊一聊大模型

    事情还得从ChatGPT说起。 2022年12月OpenAI发布了自然语言生成模型ChatGPT,一个可以基于用户输入文本自动生成回答的人工智能体。它有着赶超人类的自然对话程度以及逆天的学识。一时间引爆了整个人工智能界,各大巨头也纷纷跟进发布了自家的大模型,如:百度-文心一言、科

    2024年02月05日
    浏览(45)
  • 聊一聊Vue和Ts

    1 前言 Vue3 已经正式发布了一段时间了,各种生态已经成熟。最近使用 taro+vue3 重构冷链的小程序,经过了一段时间的开发和使用,有了一些自己的思考。 总的来说,Vue3 无论是在底层原理还是在实际开发过程中,都有了很大的进步。 从源码层面来说,使用 Proxy 代替 Object.d

    2023年04月08日
    浏览(59)
  • 聊一聊适配器模式

    接口不能用?行,我帮你适配 适配器模式(Adapter),是23种设计模式中的 结构型模式 之一;它就像我们电脑上接口不够时,需要用到的拓展坞,起到转接的作用。它可以将新的功能和原先的功能连接起来,使由于需求变动导致不能用的功能,重新利用起来。 上图的Mac上,只

    2024年02月04日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包