1. 准备工作
1.1 环境
Windows10 + VisualStudio 2022 + .Net 6.0
1.2 创建项目
- Visual Studio新建项目
- 选择C# Console App
- 通过NuGet安装
HtmlAgilityPack
2. 获取HTML
思路:
- 通过
HttpClient请求豆瓣读书Top250页面; - 将请求到的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标签当中,如图所示。
因此获取每一页符合条件的tr标签就离成功不远了。
代码:
var trList = htmlDocument.DocumentNode.Descendants("tr")
.Where(node => node.GetAttributeValue("class", "")
.Equals("item")).ToList();
3.2 从tr标签当中获取想要的信息
在本例当中我获取了书籍名称与评分信息。
思路:
- 书籍名称保存在
tr标签下第二个a标签当中; - 评分信息保存在
class="rating_num"的span标签当中。
代码:
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获取的,因此会出现数量不定的空格与回车。所以在本例当中通过Trim,Replace等函数进行了数据清洗工作。
4. 整体思路
4.1 翻页思路
豆瓣读书Top250的翻页是通过start参数来控制的。
- start=0时为第一页
- start=25时为第二页 因此通过for循环来控制翻页。
for(int start=0; start<=225; start+=25)
{
var url = $"https://book.douban.com/top250?start={start}";
// code
}
4.2 爬虫思路
- 获取每一页的Html
- 获取每页25个
tr - 获取书籍名称与评分
- 输出结果
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();
}
}
}