Fork me on GitHub

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!

❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️❄️

⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄⛄

🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄🎄

🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅🎅

🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎🍎

 🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦🧦

 
posted @ 2019-12-24 22:58  猫叔Vincent  阅读(809)  评论(0编辑  收藏  举报