UWP 获取博客园积分,并以图表形式呈现变化趋势
先看一下效果吧
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 Christmas!
❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️
⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄
🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄
🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅
🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎
🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦