一小时掌握:使用ScrapySharp和C#打造新闻下载器

news2025/1/13 13:50:21

亿牛云

引言

爬虫技术是指通过编程的方式,自动从互联网上获取和处理数据的技术。爬虫技术有很多应用场景,比如搜索引擎、数据分析、舆情监测、电商比价等。爬虫技术也是一门有趣的技术,可以让你发现网络上的各种有价值的信息。

本文将介绍如何使用ScrapySharp和C#语言,打造一个简单的新闻下载器,可以从指定的新闻网站上抓取新闻标题、摘要、正文、作者、发布时间等信息,并保存到本地文件中。本文的目的是让你在一小时内掌握ScrapySharp和C#的基本用法,以及爬虫技术的基本原理和技巧。

ScrapySharp和C#的介绍

ScrapySharp是一个基于.NET的爬虫框架,它提供了一系列的类和方法,可以方便地实现爬虫的功能,比如发送请求、解析响应、提取数据、保存数据等。ScrapySharp的核心类是ScrapingBrowser,它模拟了一个浏览器的行为,可以执行JavaScript、处理Cookie、设置代理等。ScrapySharp还支持CSS选择器和XPath语法,可以灵活地定位网页中的元素。

C#是一种面向对象的编程语言,它是.NET平台的主要语言,可以运行在Windows、Linux、Mac等操作系统上。C#语言简洁、强大、高效,拥有丰富的类库和工具,可以开发各种类型的应用程序,包括桌面应用、网站、移动应用、游戏等。C#还支持多线程编程,可以充分利用CPU的资源,提高程序的性能。

新闻下载器的设计

本文的新闻下载器的设计思路如下:

  • 首先,定义一个News类,用来存储新闻的各种属性,比如标题、摘要、正文、作者、发布时间等。
  • 然后,定义一个NewsDownloader类,用来实现新闻下载器的主要逻辑,包括以下几个方法:
    • 构造方法,用来初始化ScrapingBrowser对象,设置代理、超时、用户代理等参数。
    • GetNewsUrls方法,用来从指定的新闻网站的首页上,获取所有新闻的链接,并返回一个字符串列表。
    • GetNewsContent方法,用来从指定的新闻链接上,获取新闻的内容,并返回一个News对象。
    • SaveNews方法,用来将一个News对象保存到本地文件中,文件名为新闻的标题,文件格式为txt。
    • DownloadNews方法,用来下载所有新闻,并保存到本地文件夹中,文件夹名为新闻网站的域名。
  • 最后,定义一个Program类,用来作为程序的入口,创建一个NewsDownloader对象,并调用其DownloadNews方法,传入要爬取的新闻网站的地址。

新闻下载器的代码

本文的新闻下载器的代码如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using HtmlAgilityPack;
using ScrapySharp.Extensions;
using ScrapySharp.Network;

namespace NewsDownloader
{
    // 定义一个News类,用来存储新闻的各种属性
    public class News
    {
        public string Title { get; set; } // 标题
        public string Summary { get; set; } // 摘要
        public string Content { get; set; } // 正文
        public string Author { get; set; } // 作者
        public string Time { get; set; } // 发布时间
    }

    // 定义一个NewsDownloader类,用来实现新闻下载器的主要逻辑
    public class NewsDownloader
    {
        private ScrapingBrowser browser; // 定义一个ScrapingBrowser对象,用来模拟浏览器的行为
        //亿牛云 设置爬虫代理加强版
        private string proxyDomain = "http://www.16yun.cn"; // 定义代理的域名
        private int proxyPort = 9010; // 定义代理的端口
        private string proxyUser = "16YUN"; // 定义代理的用户名
        private string proxyPass = "16IP"; // 定义代理的密码

        // 构造方法,用来初始化ScrapingBrowser对象,设置代理、超时、用户代理等参数
        public NewsDownloader()
        {
            browser = new ScrapingBrowser();
            browser.Timeout = TimeSpan.FromSeconds(10); // 设置超时时间为10秒
            browser.UserAgent = new FakeUserAgent("Chrome", 88.0); // 设置用户代理为Chrome 88.0
            browser.UseDefaultCookiesParser = false; // 禁用默认的Cookie解析器
            browser.Proxy = new WebProxy(proxyDomain, proxyPort); // 设置代理
            browser.Proxy.Credentials = new NetworkCredential(proxyUser, proxyPass); // 设置代理的凭证
        }

        // GetNewsUrls方法,用来从指定的新闻网站的首页上,获取所有新闻的链接,并返回一个字符串列表
        public List<string> GetNewsUrls(string url)
        {
            List<string> newsUrls = new List<string>(); // 定义一个字符串列表,用来存储新闻的链接
            try
            {
                WebPage homePage = browser.NavigateToPage(new Uri(url)); // 使用ScrapingBrowser对象访问新闻网站的首页,并获取WebPage对象
                HtmlNode homeNode = homePage.Html; // 从WebPage对象中获取HtmlNode对象,表示网页的HTML文档
                IEnumerable<HtmlNode> newsNodes = homeNode.CssSelect("a[href*='/news/']"); // 使用CSS选择器,从HtmlNode对象中获取所有包含'/news/'的a标签的HtmlNode对象,表示新闻的链接
                foreach (HtmlNode newsNode in newsNodes) // 遍历所有新闻的链接
                {
                    string newsUrl = newsNode.GetAttributeValue("href", null); // 从HtmlNode对象中获取href属性的值,表示新闻的链接
                    if (newsUrl != null && !newsUrls.Contains(newsUrl)) // 如果新闻的链接不为空,且不在字符串列表中
                    {
                        newsUrls.Add(newsUrl); // 将新闻的链接添加到字符串列表中
                    }
                }
            }
            catch (Exception ex) // 捕获异常
            {
                Console.WriteLine("GetNewsUrls error: " + ex.Message); // 在控制台输出异常信息
            }
            return newsUrls; // 返回字符串列表
        }

        // GetNewsContent方法,用来从指定的新闻链接上,获取新闻的内容,并返回一个News对象
        public News GetNewsContent(string url)
        {
            News news = new News(); // 定义一个News对象,用来存储新闻的内容
            try
            {
                WebPage newsPage = browser.NavigateToPage(new Uri(url)); // 使用ScrapingBrowser对象访问新闻的链接,并获取WebPage对象
                HtmlNode newsNode = newsPage.Html; // 从WebPage对象中获取HtmlNode对象,表示网页的HTML文档
                HtmlNode titleNode = newsNode.CssSelect("h1").FirstOrDefault(); // 使用CSS选择器,从HtmlNode对象中获取第一个h1标签的HtmlNode对象,表示新闻的标题
                HtmlNode summaryNode = newsNode.CssSelect("p.summary").FirstOrDefault(); // 使用CSS选择器,从HtmlNode对象中获取第一个p标签,且class属性为summary的HtmlNode对象,表示新闻的摘要
                HtmlNode contentNode = newsNode.CssSelect("div.article-content").FirstOrDefault(); // 使用CSS选择器,从HtmlNode对象中获取第一个div标签,且class属性为article-content的HtmlNode对象,表示新闻的正文
                HtmlNode authorNode = newsNode.CssSelect("span.author").FirstOrDefault(); // 使用CSS选择器,从HtmlNode对象中获取第一个span标签,且class属性为author的HtmlNode对象,表示新闻的作者
                HtmlNode timeNode = newsNode.CssSelect("span.time").FirstOrDefault(); // 使用CSS选择器,从HtmlNode对象中获取第一个span标签,且class属性为time的HtmlNode对象,表示新闻的发布时间
                if (titleNode != null) // 如果标题节点不为空
                {
                    news.Title = titleNode.InnerText.Trim(); // 从HtmlNode对象中获取文本内容,并去除两端的空白字符,赋值给News对象的Title属性
                }
                if (summaryNode != null) // 如果摘要节点不为空
                {
                    news.Summary = summaryNode.InnerText.Trim(); // 从HtmlNode对象中获取文本内容,并去除两端的空白字符,赋值给News对象的Summary属性
                }
                if (contentNode != null) // 如果正文节点不为空
                {
                    news.Content = contentNode.InnerText.Trim(); // 从HtmlNode对象中获取文本内容,并去除两端的空白字符,赋值给News对象的Content属性
                }
                if (authorNode != null) // 如果作者节点不为空
                {
                    news.Author = authorNode.InnerText.Trim(); // 从HtmlNode对象中获取文本内容,并去除两端的空白字符,赋值给News对象的Author属性
                }
                if (timeNode != null) // 如果时间节点不为空
                {
                    news.Time = timeNode.InnerText.Trim(); // 从HtmlNode对象中获取文本内容,并去除两端的空白字符,赋值给News对象的Time属性
                }
            }
            catch (Exception ex) // 捕获异常
            {
                Console.WriteLine("GetNewsContent error: " + ex.Message); // 在控制台输出异常信息
            }
            return news; // 返回News对象
        }

        // SaveNews方法,用来将一个News对象保存到本地文件中,文件名为新闻的标题,文件格式为txt
        public void SaveNews(News news, string folder)
        {
            try
            {
                string fileName = news.Title + ".txt"; // 定义文件名为新闻的标题加上.txt后缀
                string filePath = Path.Combine(folder, fileName); // 定义文件路径为文件夹和文件名的组合
                using (StreamWriter writer = new StreamWriter(filePath, false, Encoding.UTF8)) // 使用StreamWriter对象,以UTF-8编码,覆盖模式,打开或创建文件
                {
                    writer.WriteLine("标题:" + news.Title); // 写入新闻的标题
                    writer.WriteLine("摘要:" + news.Summary); // 写入新闻的摘要
                    writer.WriteLine("正文:" + news.Content); // 写入新闻的正文
                    writer.WriteLine("作者:" + news.Author); // 写入新闻的作者
                    writer.WriteLine("时间:" + news.Time); // 写入新闻的时间
                }
            }
            catch (Exception ex) // 捕获异常
            {
                Console.WriteLine("SaveNews error: " + ex.Message); // 在控制台输出异常信息
            }
        }

        // DownloadNews方法,用来下载所有新闻,并保存到本地文件夹中,文件夹名为新闻网站的域名
        public void DownloadNews(string url)
        {
            try
            {
                Uri uri = new Uri(url); // 定义一个Uri对象,表示新闻网站的地址
                string folder = uri.Host; // 定义文件夹名为Uri对象的Host属性,表示新闻网站的域名
                if (!Directory.Exists(folder)) // 如果文件夹不存在
                {
                    Directory.CreateDirectory(folder); // 创建文件夹
                }
                List<string> newsUrls = GetNewsUrls(url); // 调用GetNewsUrls方法,获取所有新闻的链接
                Parallel.ForEach(newsUrls, newsUrl => // 使用Parallel类的ForEach方法,对所有新闻的链接进行并行处理,提高采集效率
                {
                    News news = GetNewsContent(newsUrl); // 调用GetNewsContent方法,获取新闻的内容
                    SaveNews(news, folder); // 调用SaveNews方法,将新闻保存到本地文件中
                    Console.WriteLine("Downloaded: " + news.Title); // 在控制台输出下载成功的新闻的标题
                });
                Console.WriteLine("Download completed!"); // 在控制台输出下载完成的提示
            }
            catch (Exception ex) // 捕获异常
            {
                Console.WriteLine("DownloadNews error: " + ex.Message); // 在控制台输出异常信息
            }
        }
    }

    // 定义一个Program类,用来作为程序的入口
    class Program
    {
        static void Main(string[] args)
        {
            NewsDownloader downloader = new NewsDownloader(); // 创建一个NewsDownloader对象
            downloader.DownloadNews("https://www.bbc.com/news"); // 调用其DownloadNews方法,传入要爬取的新闻网站的地址
            Console.ReadKey(); // 等待用户按键
        }
    }
}

结论

本文介绍了如何使用ScrapySharp和C#语言,打造一个简单的新闻下载器,可以从指定的新闻网站上抓取新闻标题、摘要、正文、作者、发布时间等信息,并保存到本地文件中。本文的目的是让你在一小时内掌握ScrapySharp和C#的基本用法,以及爬虫技术的基本原理和技巧。

本文的技术文章和代码仅供参考,你可以根据自己的需求和兴趣,修改或扩展它们,实现更多的功能,比如添加异常处理、日志记录、数据清洗、数据分析等。希望本文能对你的学习和开发有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1374482.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux -- Nginx服务基础

4.1Nginx服务基础 Nginx(发音为[engine x])专为性能优化而开发&#xff0c;其最知名的优点是它的稳定性和低系统资源消 耗&#xff0c;以及对HTTP并发连接的高处理能力&#xff08;单台物理服务器可支持30000~50000个并发请求&#xff09;&#xff0c;正因 为如此&#xff0c;…

ffmpeg 视频分辨率修改 质量压缩

随着手机像素的提高&#xff0c;拍摄视频也越来越大&#xff0c;10秒的视频动辄 二三十兆&#xff0c;这给视频传输和播放都带来了 诸多不变。一般都需要 前端或或者后端 对视频进行压缩。由于我这边前端是 H5&#xff0c;所以只能后端进行压缩&#xff0c; 采用主流压缩库采用…

bmp图像文件格式超详解

0 BMP简介 BMP(Bitmap-File)图形文件&#xff0c;又叫位图文件&#xff0c;是Windows采用的图形文件格式&#xff0c;在Windows环境下运行的所有图像处理软件都支持BMP图像文件格式。Windows系统内部各图像绘制操作都是以BMP为基础的。一个BMP文件由四部分组成&#xff1a; B…

手轮脉冲平滑处理笔记

这是一个求手脉倍率((Hw_Control.mult_ratio)与手脉脉冲计数延迟次数即累计过去n次的平均值(Hw_Control.lag_num)之间关系算法的计算过程笔记文档 1、已知 mult_ratio=1时 lag_num=10; mult_ratio=10时 lag_num=20; .mult_ratio==100时 lag_num=30; 以此类推 2、设lag_num…

【目标跟踪】多相机多目标跟踪

文章目录 前言一、计算思路二、代码三、结果 前言 单相机目标跟踪之前博客已经有过基本介绍&#xff0c;本篇博客主要介绍一种多相机目标跟踪的计算方法已知各相机内外参&#xff0c;如何计算共视区域像素投影&#xff1f;废话不多说&#xff0c;见下图。 同一时刻相机A与相机…

创建ROS模型与小机器人地图规划

1、打开自己的VM系统 2、安装小机器人的安装包&#xff0c;输入如下命令&#xff0c;回车输入密码(自己设的)&#xff1a; sudo apt install ros-noetic-turtlebot3-simulations ros-noetic-turtlebot3-slam ros-noetic-turtlebot3-navigation 提示我之前安装过了 3、用rosla…

ansible:如何在centos 7上重新启动auditd服务得到关于依赖的错误

在我的剧本中&#xff0c;我有一个更新 audit.rules 的任务&#xff0c;然后通知应该重新启动 auditd 服务的处理程序。 task:- name: 6.6.7 - audit rules configurationtemplate: srcX/ansible/templates/auditd_rules.j2dest/etc/audit/rules.d/audit.rulesbackupyesownerr…

在线图表编辑工具Draw.io本地部署并结合内网穿透实现远程协作办公

前言 提到流程图&#xff0c;大家第一时间可能会想到Visio&#xff0c;不可否认&#xff0c;VIsio确实是功能强大&#xff0c;但是软件为收费&#xff0c;并且因为其功能强大&#xff0c;导致安装需要很多的系统内存&#xff0c;并且是不可跨平台使用。所以&#xff0c;今天给…

ChatGPT | Team套餐来了,每人 25美元,你怎么看?

最近&#xff0c;ChatGPT 在原有的plus会员的基础上 加了一个Team套餐 价格要更贵一些 收费 每人每月 25 美元 套餐包含 Plus 中的所有内容&#xff0c;以及&#xff1a; GPT-4 和 DALLE、浏览、高级数据分析等 创建 GPT 并将其与工作区共享 用于工作区管理的管理控制台 保证不…

shrio漏洞

sudo apt install tomcat9//安装tomcat9sudo systemctl status tomcat9//查看安装状态 编辑配置文件 sudo nano /etc/tomcat9/tomcat-users.xml 编辑配置文件&#xff0c;设置密码 sudo systemctl restart tomcat9 重启生效 访问 Tomcat 管理页面&#xff1a;在浏览器中输入…

网络安全B模块(笔记详解)- 网络爬虫渗透测试

ARP协议渗透测试 1.进入渗透机场景BT5中的/root目录,完善该目录下的arp_spoof.py文件,填写该文件当中空缺的Flag1字符串,将该字符串作为Flag值(形式:Flag1字符串)提交;(arp_spoof.py脚本功能见该任务第6题) 根据缺少的发现是要time模块 Flag:time 2.进入渗透机场景B…

独享静态代理IP在海外市场调研中的独特优势

独享静态代理IP在海外市场调研中扮演着至关重要的角色&#xff0c;提供了一系列无可比拟的优势。独享静态代理IP的稳定性和可靠性对于长期的市场调研至关重要&#xff0c;它保证了连接的持续性和数据的准确性。通过这些方面的综合优势&#xff0c;独享静态代理IP成为海外市场调…

生成学习全景:从基础理论到GANs技术实战

本文全面探讨了生成学习的理论与实践&#xff0c;包括对生成学习与判别学习的比较、详细解析GANs、VAEs及自回归模型的工作原理与结构&#xff0c;并通过实战案例展示了GAN模型在PyTorch中的实现。 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产…

Visual Studio Code 连接远程服务器方法

1、输入用户名和服务器ip连接远程服务器 2、选择配置文件 配置文件路径&#xff1a;C:\Users\Administrator\.ssh\config config的内容大致如下&#xff1a; Host 192.168.134.3HostName 192.168.134.3User zhangshanHost 192.168.134.3HostName 192.168.134.3User lisiHost…

Open CASCADE学习|一种快速定位缺失的链接库的方法

OCCT代码中&#xff0c;缺少链接库一般报错LNK2019、LNK1120等&#xff0c;如下表所示。该错误说明中提供了类名及成员函数&#xff0c;这是找到缺少的链接库的线索。 严重性 代码 说明 项目 文件 行 禁止显示状态 详细信息 错误 LNK2019 无法解析的外部符号 "p…

C/C++动态内存管理

文章目录 前言1.C/C内存分布2.C语言中动态内存管理方式&#xff1a;malloc/calloc/realloc/free3.C内存管理方式3.1 new/delete操作内置类型3.2 new和delete操作自定义类型 4. operator new与operator delete函数4.1 operator new与operator delete函数 5. new和delete的实现原…

Python实用小工具(4)——邮件轰炸机,给朋友搞点乐子(附源码+exe文件)

欢迎来到MatpyMaster&#xff01;今天我们将使用Python来批量发送邮件&#xff0c;让你的邮件推送变得更加高效。废话不多说&#xff0c;直接开搞&#xff01;使用声明&#xff1a; 请确保你的邮箱开启了SMTP服务&#xff0c;并获取了授权码。 选择合适的发送间隔&#xff0c;…

创建mysql普通用户

一、创建mysql普通用户的原因&#xff1a; 权限控制&#xff1a;MySQL的权限系统允许您为每个用户分配特定的权限。通过创建普通用户&#xff0c;您可以根据需要为每个用户分配特定的数据库和表权限&#xff0c;而不是将所有权限授予一个全局管理员用户。这有助于提高数据库的…

2024年华夏银行总行社会招聘公告

信息科技部自动化测试与开发类岗  工作地点&#xff1a;北京市 学历要求&#xff1a;本科及以上 工作职责 1、持续推进自动化测试的开展&#xff0c;提升自动化测试覆盖率,包括方案设计、测试分析、测试执行和总结等。 2、负责自动化测试工具和框架搭建&#xff0c;根据…

关于报错 curl: (56) Recv failure: Connection reset by peer

curl ip没问题 curl localhost 则报错 curl: (56) Recv failure: Connection reset by peer 出现这个报错有很多原因, 其中之一就是terminal代理 而关闭代理应用之后, 其实由于配置的终端都是 export指定的代理 所以导致还是一直报错. 通过 curl -v 可以发现 指向了代理ip和…