C #爬取豆瓣读书TOP250

244 阅读1分钟

1. 准备工作

1.1 环境

Windows10 + VisualStudio 2022 + .Net 6.0

1.2 创建项目

  1. Visual Studio新建项目
  2. 选择C# Console App
  3. 通过NuGet安装HtmlAgilityPack

2. 获取HTML

思路:

  1. 通过HttpClient请求豆瓣读书Top250页面;
  2. 将请求到的Html字符转化为HtmlDocument

代码:

// 请求地址
var url = "https://book.douban.com/top250";
// 获取返回值
var httpClient = new HttpClient();
var html = await httpClient.GetStringAsync(url);
// 构造 HtmlDocument
var htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(html);

HtmlDocument 属于 HtmlAgilityPack 因此需要在头部写入:using HtmlAgilityPack;

3. 解析HTML

3.1 获取每个存储书籍信息的tr标签

思路:

通过观察页面代码可知,每个书籍的基本信息都包含在class="item"tr标签当中,如图所示。

Pasted image 20220615181508.png

因此获取每一页符合条件的tr标签就离成功不远了。

代码:

var trList = htmlDocument.DocumentNode.Descendants("tr")
    .Where(node => node.GetAttributeValue("class", "")
    .Equals("item")).ToList();

3.2 从tr标签当中获取想要的信息

在本例当中我获取了书籍名称与评分信息。

思路:

  1. 书籍名称保存在tr标签下第二个a标签当中;
  2. 评分信息保存在class="rating_num"span标签当中。

Pasted image 20220615182319.png

代码:

var bookName = tr.Descendants("a")
	.ToList()[1].InnerText
	.Trim().Replace(" ", "").Replace("\n", ""); // 清洗数据

var ratingNum = tr.Descendants("span")
    .Where(node => node.GetAttributeValue("class", "")
    .Equals("rating_nums")).ToList()[0].InnerText;

因为书籍名称是通过InnerText获取的,因此会出现数量不定的空格与回车。所以在本例当中通过TrimReplace等函数进行了数据清洗工作。

4. 整体思路

4.1 翻页思路

豆瓣读书Top250的翻页是通过start参数来控制的。

  1. start=0时为第一页
  2. start=25时为第二页 因此通过for循环来控制翻页。
for(int start=0; start<=225; start+=25)
{
    var url = $"https://book.douban.com/top250?start={start}";

	// code
}

4.2 爬虫思路

  1. 获取每一页的Html
  2. 获取每页25个tr
  3. 获取书籍名称与评分
  4. 输出结果

5. 完整代码

using HtmlAgilityPack;

namespace DoubanReadCrawl
{
    class Program
    {
        static async Task Main(string[] args)
        {
            int cnt = 1;
            for(int start=0; start<=225; start+=25)
            {
                var url = $"https://book.douban.com/top250?start={start}";
                var httpClient = new HttpClient();
                var html = await httpClient.GetStringAsync(url);
                var htmlDocument = new HtmlDocument();
                htmlDocument.LoadHtml(html);

                var trList = htmlDocument.DocumentNode.Descendants("tr")
                    .Where(node => node.GetAttributeValue("class", "")
                    .Equals("item")).ToList();

                foreach (var tr in trList)
                {
                    var bookName = tr.Descendants("a").ToList()[1].InnerText.Trim().Replace(" ", "").Replace("\n", "");
                    var ratingNum = tr.Descendants("span")
                        .Where(node => node.GetAttributeValue("class", "")
                        .Equals("rating_nums")).ToList()[0].InnerText;

                    Console.WriteLine($"[{cnt++}] {bookName} {ratingNum}");
                }
            }
            Console.ReadLine();
        }
    }
}