C#实战:手写简易EMLOG博客爬虫,从底层逻辑到MySQL注入防护

在零点博客日常做项目开发时,经常需要从公开数据源中抽取数据。最近有粉丝在群里问,C#能不能做博客爬虫?尤其是像 EMLOG 这种轻量级系统,数据结构相对简单,是个练手的好对象。今天我就把这段时间开发这个 爬虫开发 工具的底层逻辑拆解出来,顺便讲讲在后端开发中如何通过MySQL预处理语句防止SQL注入,代码都是真实可落地的。

一、 为什么选择 C# 做爬虫?

接口开发或者数据聚合时,C# 的 HttpClient 配合异步处理,抓取效率通常比纯 PHP 或 Python 要高出一截。这次我们要抓取的是 EMLOG 博客列表页,获取标题、链接和发布时间。

二、 核心实现:HtmlAgilityPack 与 正则表达式

我们不需要自己造轮子去解析 HTTP 协议,直接用现成的 HtmlAgilityPack 插件,这是 .NET 生态里处理 HTML 的神器。

首先,准备一个简单的抓取方法。这里直接上干货代码,你可以直接复制到 VS 里跑:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using HtmlAgilityPack;
using System.Text.RegularExpressions;

namespace ZeroBlogSpider
{
    class Program
    {
        // 这里替换成目标 EMLOG 博客的首页链接
        private static string TargetUrl = "https://www.example.com/"; 

        static async Task Main(string[] args)
        {
            // 1. 发起 HTTP 请求
            using (var httpClient = new HttpClient())
            {
                string htmlContent = await httpClient.GetStringAsync(TargetUrl);

                // 2. 加载 HTML 文档
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(htmlContent);

                // 3. 使用 XPath 或 CSS 选择器提取数据
                // EMLOG 的文章列表通常在 class="post" 的 div 里
                var nodes = doc.DocumentNode.SelectNodes("//div[@class='post']");

                if (nodes != null)
                {
                    foreach (var node in nodes)
                    {
                        string title = node.SelectSingleNode(".//h2/a").InnerText.Trim();
                        string link = node.SelectSingleNode(".//h2/a").GetAttributeValue("href", "");

                        // 4. 正则表达式清洗数据,比如提取发布时间
                        string timeText = node.SelectSingleNode(".//span").InnerText;
                        string publishTime = Regex.Match(timeText, @"\d{4}-\d{2}-\d{2}").Value;

                        // 输出结果
                        Console.WriteLine($"标题: {title} | 链接: {link} | 时间: {publishTime}");
                    }
                }
            }
            Console.ReadLine();
        }
    }
}

这段代码涵盖了接口开发中最基础的数据获取。注意看里面的 正则表达式,用来从杂乱的 HTML 文本中提取标准的时间格式,这是做数据清洗必不可少的一步。

三、 底层避坑:爬虫反爬与 IP 代理

做多了你会发现,直接请求容易被封 IP。虽然这次没演示,但在实战中,一定要用第三方代理 IP 池。同时,在 C# 中尽量使用 HttpClientFactory 来管理连接,避免端口耗尽。

四、 真正的难点:MySQL 注入防护与 JSON 解析

抓取下来的数据,最终是要存进 MySQL 数据库的。很多新手喜欢用字符串拼接 SQL,这是大忌!下面我直接展示如何通过SQL注入防护来写入数据,并将数据封装成 JSON 供前端调用。

using System.Data.SqlClient;
using Newtonsoft.Json.Linq;

public void SaveToDatabase(string title, string link, string time)
{
    string connStr = "Server=localhost;Database=blog_db;User Id=root;Password=123;";

    // 使用参数化查询,这是防止 SQL 注入的唯一正解
    // 永远不要写 "INSERT INTO ... VALUES ('" + title + "')"
    string sql = "INSERT INTO articles (title, link, time) VALUES (@p1, @p2, @p3)";

    using (SqlConnection conn = new SqlConnection(connStr))
    {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(sql, conn))
        {
            cmd.Parameters.AddWithValue("@p1", title);
            cmd.Parameters.AddWithValue("@p2", link);
            cmd.Parameters.AddWithValue("@p3", time);
            cmd.ExecuteNonQuery();
        }
    }
}

处理完数据库后,我们可以把多条文章数据转换成 JSON 格式。如果是做在线工具开发,前端只需要请求这个接口就能拿到数据。

五、 总结与实操建议

这套流程下来,从HTML/CSS/JS 前端看到的数据展示,到 C# 后端去抓取,再到 MySQL 里的存储,逻辑是完整的。在零点博客的日常迭代中,我也发现:正则表达式 用得好,能省去一半的调试时间;而SQL注入防护意识强,能少掉几根头发。

如果你正准备学习 C# 开发,不妨试着把上面的代码跑一遍,然后改成定时任务,每天自动更新你的博客数据。技术只有动起手来,才是自己的。