先看一下效果吧
1. 分析
说实话, 之前还真没在乎过博客园的排名和积分, 博客园默认也不给显示. 需要自己到选项里面勾选才可以.
之前也有几个大佬写过类似的文章, 不过是很早了. 博客园关于获取积分的 API 已经变了.
也不算是 API 吧, 毕竟不是官方公开的. 不过自己可以通过查看页面元素, 找到博客园的积分 url.
在你勾选了上面的选项之后, 打开你的博客主页, 比如我的就是 https://www.cnblogs.com/hupo376787/
按 F12, 调出开发者工具, 进入 Network 选项卡.
如果在下面的列表里面没有数据, F5 刷新一下页面即可.
然后, 点击 [sidecolumn.aspx] , 右侧就会出现相信的信息.
右击 [sidecolumn.aspx] ,[copy link address] , 这个 url 就是我们要找的.
然后根据这个 url 返回的信息, 我们利用正则表达式或者其他手段找到积分和排名的数据即可.
2. 写 Xaml 界面
既然根据上面的分析, 可以拿到积分和排名的数据, 那么写代码就简单多了.
我这里使用 C# 来写的, 语言只是一种工具, 你也可以用 Java,Swift,JavaScript,Flutter 等, 还可以用 Python 写.
无论哪一种, 只要能拿到数据, 用图表展示出来即可.
在 xaml 中, 定义一下用户名输入框, 还有一个图表控件.
图表使用的 Microcharts. 这是一个开源的图表控件, GitHub 上已经斩获 1000 多个
- <StackPanel>
- <TextBox
- x:Name="textBlockUser"
- Background="Transparent"
- Padding="0, 5"
- BorderThickness="0"
- Width="200"
- HorizontalAlignment="Left"
- PlaceholderText="hupo376787"
- TextChanged="User_TextChanged"/>
- <TextBlock x:Name="textBlockDate"/>
- <TextBlock x:Name="textBlockScore"/>
- <TextBlock x:Name="textBlockRank"/>
- <charts:ChartView x:Name="microChart"
- Height="300"/>
- </StackPanel>
3. 获取网页数据
利用 HttpClient 写代码, 获取指定 url 的网页源代码.
user 是文本框可以输入的用户 id.
然后根据 Http 返回来的数据, 做成一个 List<string>. 这样就不用写正则表达式查找了.
其实主要是我不大会写正则表达式而已.
不好意思暴露了.
- string url = "https://www.cnblogs.com/" + user + "/ajax/sidecolumn.aspx";
- HttpClient client = new HttpClient();
- HttpResponseMessage message = await client.GetAsync(url);
- string content = await message.Content.ReadAsStringAsync();
- List<string> lines = content.Replace("积分与排名", "").Split("\n").ToList();
- var scoreHeaderIndex = lines.FindIndex(x => x.Contains("积分"));
- var rankHeaderIndex = lines.FindIndex(x => x.Contains("排名"));
- int score = Convert.ToInt32(lines[scoreHeaderIndex + 1]);
- int rank = Convert.ToInt32(lines[rankHeaderIndex + 1]);
4. 生成图表
因为要做成趋势图, 并且博客园返回的数据只是当天的信息, 并不不包含历史记录.
所以需要手动记录数据, 并存放在本地.
之前那几个大佬也是这样子, 写成了 python 或者 JS, 每天自动运行一次, 保存数据.
UWP 想要记录数据, 需要一点额外的权限.
因为需要记录 txt 文件, 而这样的文本文件最好放在 user/document 文件夹下.
首先, 用记事本打开 Package.appxmanifest, 加上
- <Capabilities>
- <uap:Capability Name="documentsLibrary" />
- </Capabilities>
然后在 vs 中打开 Package.appxmanifest, 添加声明. 按照图示设置.
这样就有权限写入 txt 到文档文件夹了.
- StorageFolder storageFolder = KnownFolders.DocumentsLibrary;
- StorageFile file = await storageFolder.CreateFileAsync("cnBlogs.txt", CreationCollisionOption.OpenIfExists);
- string existData = await FileIO.ReadTextAsync(file);
- List<string> list = existData.Split("\r\n").ToList();
我这儿首先读取了 txt 里面的数据, 如果这个 txt 不存在, 就创建. 已经存在的话, 直接打开读取数据.
然后绘图
- Random rnd = new Random();
- List<ChartEntry> entries = new List<ChartEntry>();
- foreach(var item in list)
- {
- if (item.Trim() == "")
- continue;
- var singleLineArray = item.Split(",");
- var entry = new ChartEntry((float)Convert.ToDouble(singleLineArray[1]))
- {
- Label = singleLineArray[0],
- ValueLabel = singleLineArray[1],
- Color = SKColor.Parse(String.Format("#{0:X6}", rnd.Next(0x1000000)))
- };
- entries.Add(entry);
- }var chart = new LineChart {
- Entries = entries,
- MinValue = 100000,
- BackgroundColor = SKColors.Transparent
- };
- this.microChart.Chart = chart;
如果在生成折线图的时候, 不加上
BackgroundColor = SKColors.Transparent
生成的图表默认白色. 但是背景透明好看.
5. 记录获取的积分和排名数据
为了防止一天内多次打开 App, 重复记录, 所以我做了一个检查.
利用 System.IO 写入数据.
- string contentToWrite = "";
- //Add Today
- if (!existData.Contains(DateTime.Now.ToString("yyyy-MM-dd")))
- {
- var entryToday = new ChartEntry((float)Convert.ToDouble(score))
- {
- Label = score.ToString(),
- ValueLabel = DateTime.Now.ToString("yyyy-MM-dd"),
- Color = SKColor.Parse(string.Format("#{0:X6}", rnd.Next(0x1000000)))
- };
- entries.Append(entryToday);
- contentToWrite = existData + "\r\n" + DateTime.Now.ToString("yyyy-MM-dd") + "," + score + "," + rank;
- }
- else
- contentToWrite = existData;
- //Write
- await FileIO.WriteTextAsync(file, contentToWrite);
6. 完成的代码
- private async Task GetData(string user)
- {
- try
- {
- string url = "https://www.cnblogs.com/" + user + "/ajax/sidecolumn.aspx";
- HttpClient client = new HttpClient();
- HttpResponseMessage message = await client.GetAsync(url);
- string content = await message.Content.ReadAsStringAsync();
- List<string> lines = content.Replace("积分与排名", "").Split("\n").ToList();
- var scoreHeaderIndex = lines.FindIndex(x => x.Contains("积分"));
- var rankHeaderIndex = lines.FindIndex(x => x.Contains("排名"));
- int score = Convert.ToInt32(lines[scoreHeaderIndex + 1]);
- int rank = Convert.ToInt32(lines[rankHeaderIndex + 1]);
- textBlockDate.Text = DateTime.Now.ToString("yyyy-MM-dd");
- textBlockScore.Text = score.ToString();
- textBlockRank.Text = rank.ToString();
- StorageFolder storageFolder = KnownFolders.DocumentsLibrary;
- StorageFile file = await storageFolder.CreateFileAsync("cnBlogs.txt", CreationCollisionOption.OpenIfExists);
- string existData = await FileIO.ReadTextAsync(file);
- List<string> list = existData.Split("\r\n").ToList();
- Random rnd = new Random();
- List<ChartEntry> entries = new List<ChartEntry>();
- foreach(var item in list)
- {
- if (item.Trim() == "")
- continue;
- var singleLineArray = item.Split(",");
- var entry = new ChartEntry((float)Convert.ToDouble(singleLineArray[1]))
- {
- Label = singleLineArray[0],
- ValueLabel = singleLineArray[1],
- Color = SKColor.Parse(String.Format("#{0:X6}", rnd.Next(0x1000000)))
- };
- entries.Add(entry);
- }
- string contentToWrite = "";
- //Add Today
- if (!existData.Contains(DateTime.Now.ToString("yyyy-MM-dd")))
- {
- var entryToday = new ChartEntry((float)Convert.ToDouble(score))
- {
- Label = score.ToString(),
- ValueLabel = DateTime.Now.ToString("yyyy-MM-dd"),
- Color = SKColor.Parse(string.Format("#{0:X6}", rnd.Next(0x1000000)))
- };
- entries.Append(entryToday);
- contentToWrite = existData + "\r\n" + DateTime.Now.ToString("yyyy-MM-dd") + "," + score + "," + rank;
- }
- else
- contentToWrite = existData;
- var chart = new LineChart {
- Entries = entries,
- MinValue = 100000,
- BackgroundColor = SKColors.Transparent
- };
- this.microChart.Chart = chart;
- //Write
- await FileIO.WriteTextAsync(file, contentToWrite);
- }
- catch
- {
- }
- }
之所以加了 try{ ... } catch{ ... }, 是因为在输入用户名的时候, 可以根据文本变化, 实时检测是不是有效的用户, 并生成图表.
7. 总结
获取并显示数据, 本身不是一件很难的事情, 关键是怎么利用得到的数据, 并把它很有的呈现出来.
当然, 我这里也少做了一步, 就是让应用自启动, 开机的时候获取一次数据, 这样就可以防止某天忘记打开, 导致数据断层的问题了.
关于 uwp 如何随开机启动, 我还没研究过, 以后有时间的写一些分享心得.
OK,Merry Christmas!Lonely Christians!
来源: https://www.cnblogs.com/hupo376787/p/12094009.html