首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用C#也能网页抓取

使用C#也能网页抓取

原创
作者头像
用户7850017
修改2021-09-13 17:56:15
6K0
修改2021-09-13 17:56:15
举报

网页抓取是通过自动化手段检索数据的过程。它在许多场景中都是不可或缺的,例如竞争对手价格监控、房地产清单列表、潜在客户和舆情监控、新闻文章或金融数据聚合等。

在编写网页抓取代码时,您要做出的第一个决定是选择您的编程语言。您可以使用多种语言进行编写,例如Python、JavaScript、Java、Ruby或C#。所有提到的语言都提供强大的网络抓取功能。

在本文中,我们将探索C#并向您展示如何创建一个真实的C#公共网络爬虫。请记住,即使我们使用C#,您也可以将此信息调整为.NET平台支持的所有语言,包括VB.NET和F#

01.C#网页抓取工具

在编写任何代码之前,第一步是选择合适的C#库或包。这些C#库或包将具有下载HTML页面、解析它们以及从这些页面中提取所需数据的功能。一些最流行的C#包如下:

ScrapySharp

Puppeteer Sharp

Html Agility Pack

Html Agility Pack是最受欢迎的C#包,仅Nuget就有近5,000万次下载。其流行有多种原因,其中最重要的原因是该HTML解析器能够直接或使用浏览器下载网页。这个包可以容忍格式错误的HTML并支持XPath。此外,它甚至可以解析本地HTML文件;因此,我们将在本文中进一步使用这个包。

ScrapySharp为C#编程添加了更多功能。这个包支持CSS选择器并且可以模拟网络浏览器。虽然ScrapySharp被认为是一个强大的C#包,但程序员使用它进行维护的概率并不是很高。

Puppeteer Sharp是著名的Node.js Puppeteer项目的.NET端口。它使用相同的Chromium浏览器来加载页面。此外,这个包采用了async-await风格的代码,支持异步及预操作管理。如果您已经熟悉这个C#包并且需要一个浏览器来呈现页面,那么Puppeteer Sharp可能是一个不错的选择。

02.使用C#构建网络爬虫

如前所述,现在我们将演示如何编写将使用Html Agility Pack的C#公共网络抓取代码。我们将使用带有Visual Studio Code.NET 5 SDK。此代码已在 .NET Core 3.NET 5上测试过,它应该适用于其他版本的.NET。

我们将设置一个假设的场景:爬取一家在线书店并收集书名和价格。

在编写C#网络爬虫之前,我们先来设置下开发环境。

03.设置开发环境

对于C#开发环境,请安装Visual Studio Code。请注意,如果您使用Visual StudioVisual Studio Code编写C#代码,则需要注意它们是两个完全不同的应用程序。

安装Visual Studio Code后,安装.NET 5.0或更高版本。您还可以使用.NET Core 3.1。安装完成后,打开终端并运行以下命令以验证.NET CLI或命令行界面是否正常工作:

dotnet --version    

该行命令会输出安装的.NET的版本号

04.项目结构和依存关系

该代码将成为.NET项目的一部分。为简单起见,创建一个控制台应用程序。然后,创建一个文件夹,您将在其中编写C#代码。打开终端并导航到该文件夹。输入以下命令:

dotnet new console 

此命令的输出应该是已成功创建控制台应用程序的信息。

到时间安装所需的软件包了。使用C#抓取公共网页,Html Agility Pack将是一个不错的选择。您可以使用以下命令为该项目安装它:

dotnet add package HtmlAgilityPack   

再安装一个包,以便我们可以轻松地将抓取的数据导出到CSV文件:

dotnet add package CsvHelper    

如果您使用的是Visual Studio而不是Visual Studio Code,请单击文件,选择新建解决方案,然后按控制台应用程序按钮。要安装依赖项,请按照下列步骤操作:

●选择项目;

●单击管理项目依赖项。这将打开NuGet包窗口;

●搜索HtmlAgilityPack并选择它;

●最后,搜索CsvHelper,选择它,然后单击添加包。

Visual Studio中的Nuget包管理器
Visual Studio中的Nuget包管理器

安装了这些包后,我们可以继续编写用于抓取线上书店的代码。

05.下载和解析网页数据

任何网页抓取程序的第一步都是下载网页的HTML。此HTML将是一个字符串,您需要将其转换为可以进一步处理的对象,也就是第二步,这部分称为解析Html Agility Pack可以从本地文件、HTML字符串、任何URL和浏览器读取和解析文件。

在我们的例子中,我们需要做的就是从URL获取HTML。Html Agility Pack没有使用.NET本机函数,而是提供了一个方便的类–HtmlWeb.这个类提供了一个Load函数,它可以接受一个URL并返回一个HtmlDocument类的实例,它也是我们使用的包的一部分。有了这些信息,我们可以编写一个函数,接受一个URL并返回HtmlDocument这个实例。

打开Program.cs文件并在类中输入此函数Program

// Parses the URL and returns HtmlDocument object                         
static HtmlDocument GetDocument (string url)
{
  HtmlWeb web = new HtmlWeb();
  HtmlDocument doc = web.Load(url);
  return doc;
}

这样,代码的第一步就完成了。下一步是解析文档。

06.解析HTML:获取书籍链接

在这部分代码中,我们将从网页中提取所需的信息。在这个阶段,文档现在是一个类型的对象HtmlDocument。这个类公开了两个函数来选择元素。这两个函数都接受XPath输入并返回HtmlNode or HtmlNodeCollection

下面是这两个函数的签名:

public HtmlNodeCollection SelectNodes(string xpath);
public HtmlNode SelectSingleNode(string xpath);

我们就SelectNodes先讨论一下。

对于这个例子——C#网络爬虫——我们将从这个页面中抓取所有书籍的详细信息。

首先,需要对其进行解析,以便可以提取到所有书籍的链接。在浏览器中打开上述的书店页面,右键单击任何书籍链接,然后单击按钮“检查”。将打开开发人员工具。

在了解标记后,您要选择的XPath应该是这样的:

//h3/a 

现在可以将此XPath传递给SelectNodes函数。

HtmlDocument doc = GetDocument(url);
HtmlNodeCollection linkNodes = doc.DocumentNode.SelectNodes("//h3/a");

请注意,该SelectNodes函数是由

HtmlDocumentDocumentNode属性调用的。

变量linkNodes是一个集合。我们可以写一个foreach循环,并从每个链接一个一个地获取href值。我们只需要解决一个小问题——那就是页面上的链接是相对链接。因此,在我们抓取这些提取的链接之前,需要将它们转换为绝对URL。

为了转换相对链接,我们可以使用Uri该类。我们使用此构造函数来获取Uri具有绝对URL的对象。

dotnet --version    

一旦我们有了Uri对象,我们就可以简单地检查该AbsoluteUri属性以获取完整的URL。

我们将所有这些写在一个函数中,以保持代码的组织性。

static List<string> GetBookLinks(string url)
{
    var bookLinks = new List<string>();
    HtmlDocument doc = GetDocument(url);
    HtmlNodeCollection linkNodes = doc.DocumentNode.SelectNodes("//h3/a");
    var baseUri = new Uri(url);
    foreach (var link in linkNodes)
    {
        string href = link.Attributes["href"].Value;
        bookLinks.Add(new Uri(baseUri, href).AbsoluteUri);
    }
    return bookLinks;
}

在这个函数中,我们从一个空List<string>对象开始。在foreach循环中,我们将所有链接添加到此对象并返回它。

现在,就可以修改Main()函数了,以便我们可以测试到目前为止编写的C#代码。修改函数如下:

static void Main(string[] args)

{
  var bookLinks = GetBookLinks("http://books.toscrape.com/catalogue/category/books/mystery_3/index.html");
  Console.WriteLine("Found {0} links", bookLinks.Count);
}

要运行此代码,请打开终端并导航到包含此文件的目录,然后键入以下内容:

dotnet run   

输出应如下所示:

Found 20 links    

然后我们转到下一部分,我们将处理所有链接以获取图书数据。

07.解析HTML:获取书籍详细信息

此时,我们有一个包含书籍URL的字符串列表。我们可以简单地编写一个循环,首先使用我们已经编写的函数GetDocument来获取文档。之后,我们将使用该SelectSingleNode函数来提取书名和价格。

为了让数据清晰有条理,我们从一个类开始。这个类将代表一本书,有两个属性-Title和Price.示例如下:

public class Book
{
  public string Title { get; set; }
  public string Price { get; set; }
}

然后,为Title – //h1在浏览器中打开一个书页。为价格创建 XPath 有点棘手,因为底部的附加书籍应用了相同的类。

价格的XPath

价格的XPath将是这样的:

//div[contains(@class,"product_main")]/p[@class="price_color"]

请注意,XPath包含双引号。我们将不得不通过在它们前面加上反斜杠来转义这些字符。

现在我们可以使用SelectSingleNode函数来获取节点,然后使用InnerText属性获取元素中包含的文本。我们可以将所有内容放在一个函数中,如下所示:

static List<Book> GetBookDetails(List<string> urls)
{
var books = new List<Book>();
foreach (var url in urls)
   {
    HtmlDocument document = GetDocument(url);
    var titleXPath = "//h1";
    var priceXPath = "//div[contains(@class,\"product_main\")]/p[@class=\"price_color\"]";
    var book = new Book();
    book.Title = document.DocumentNode.SelectSingleNode (priceXPath).InnerText;
    book.Price = document.DocumentNode.SelectSingleNode(priceXPath).InnerText;
    books.Add(book);
    }
return books;
}

此函数将返回一个Book对象列表。是时候更新Main()函数了:

static void Main(string[] args)
{
  var bookLinks = GetBookLinks("http://books.toscrape.com/catalogue/category/books/mystery_3/index.html");
  Console.WriteLine("Found {0} links", bookLinks.Count);
  var books = GetBookDetails(bookLinks);
}

这个网络抓取项目的最后一部分是将数据导出为CSV

08.导出数据

如果您尚未安装CsvHelper,则可以通过

dotnet add package CsvHelper 

在终端内运行命令来完成此操作。

导出功能非常简单。首先,我们需要创建一个StreamWriter并发送CSV文件名作为参数。接下来,我们将使用此对象创建一个CsvWriter.最后,我们可以使用该WriteRecords函数在一行代码中编写所有书籍。

为了确保所有资源都正确关闭,我们可以使用using我们还可以将所有内容包装在一个函数中,如下所示:

static void exportToCSV(List<Book> books)
{
using (var writer = new StreamWriter("./books.csv"))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
    {
    csv.WriteRecords(books);
    }
}

最后,我们可以从Main()函数中调用这个函数:

static void Main(string[] args)
{
  var bookLinks = GetBookLinks("http://books.toscrape.com/catalogue/category/books/mystery_3/index.html");
  var books = GetBookDetails(bookLinks);
  exportToCSV(books);
}

要运行此代码,请打开终端并运行以下命令:

dotnet run

在几秒钟内,您将创建一个books.csv文件。

09.结论

如果您想用C#编写一个网络爬虫,您可以使用多个包。在本文中,我们展示了如何使用Html Agility Pack,这是一个功能强大且易于使用的包。也是一个可以进一步增强的简单示例;例如,您可以尝试将上述逻辑添加到此代码中以处理多个页面。

如果您想了解更多有关使用其他编程语言进行网络抓取的工作原理,可以查看使用Python进行网络抓取的指南。我们还有一个关于如何使用JavaScript编写网络爬虫的分步教程

常见问题

Q:C#适合网页抓取吗?

A:与Python类似,C#被广泛用于网页抓取。在决定选择哪种编程语言时,选择您最熟悉的一种至关重要。不过您将能够在Python和C#中找到示例的网页抓取工具。

Q:网络抓取合法吗?

A:如果在不违反任何法律的情况下使用代理,则它们可能是合法的。然而,在与代理进行任何活动之前,您应该就您的特定案件获得专业的法律建议。可以参见我们的文章“网络抓取合法吗?

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 01.C#网页抓取工具
  • 02.使用C#构建网络爬虫
  • 03.设置开发环境
  • 04.项目结构和依存关系
  • 05.下载和解析网页数据
  • 06.解析HTML:获取书籍链接
  • 07.解析HTML:获取书籍详细信息
  • 08.导出数据
  • 09.结论
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档