CP Vanity Lite






4.99/5 (29投票s)
这是 Luc Pattyn 著名 CP Vanity 应用程序的轻量级版本。
引言
这是 Luc Pattyn 广受欢迎的 CP Vanity 应用程序的精简版。 由于不可避免的网站更改,Luc 厌倦了经常修改解析代码,并且自上次重大网站更新(几周前)以来,他的应用程序一直未更新。 这促使我编写了这个应用程序,它是他的应用程序的迷你版。 与 CP Vanity 不同,CP Vanity Lite 并没有深入研究细节,而是只获取很可能具有高声誉分数的成员的总声誉分数。 我采用了 Luc 相同的方法,即根据发帖量和文章量获取排名靠前的成员,然后获取每个成员的声誉分数。 我在每个类别中获取前 125 名,但由于某些成员同时出现在两个组中,您会发现获取声誉分数的成员总数少于 250。 除了总分数外,它还显示每日平均分数,该分数是根据总分数和成员注册的天数计算得出的。
使用 CP Vanity Lite
使用该应用程序并不难,您只需运行该应用程序并等待 UI 填充。 标题栏将显示 fetching,因为正在执行 HTTP 提取,一旦所有数据可用,它将显示 完成。 UI 是一个简单的 ListView
,可以按 声誉分数 列排序。 每次单击标题时,排序在升序和降序之间切换,如果您厌倦了看到 CG 的名字排在最前面,这非常方便! 数据通过工作线程异步填充,因此该应用程序将在整个提取期间响应。 即使在提取所有数据之前,您也可以对数据进行排序,但请记住,新添加的行将不会被排序,尽管您可以根据需要多次排序。 一旦所有数据被提取,导出为 CSV 按钮将被启用,您可以保存一个 CSV 文件,然后可以在 Excel 等应用程序中打开该文件,以进行各种花哨的数据操作和图表制作。 看看图 2,您会看到 CG 领先于竞争对手的程度,他拥有的声誉分数比 John 和 Pete 加起来还多! 如果您定期运行该应用程序并保存 CSV 文件,您就可以很好地进行基于日期的数据解析,以确定分数的变化以及某人的追赶速度(如果您是统计学好奇类型)。
代码
HTML 抓取是在一个名为 RepScoreScraper
的类中完成的。 代码将被阻塞,因此由调用代码从工作线程或通过某些不会阻塞主线程的异步/任务模式使用它。 通过查询“谁是谁”页面获取潜在高分成员的 ID,以获取热门消息发布者和热门文章作者。 使用正则表达式提取信息。(我已包装了代码块以防止滚动,实际的源代码不会像这样包装)
private Regex memberNumberRegex = new Regex("Member No. (\\d*)");
private Regex repScoreRegex = new Regex(
"<span id=\"ctl00_.*?_TotalRep\" class=\"large-text\">([\\s\\S]*?)</span>");
private Regex displayNameRegex = new Regex(
"<h2 id=\"ctl00_.*?_P_Name\">([\\s\\S]*?)</h2>");
private Regex memberSinceRegex = new Regex("Member since (.+)\n");
请注意,我已在此处的代码段中剪掉了 URL,以防止水平滚动。
public void StartScraping()
{
string[] ml_obs = new[] { "ArticleCount", "MessageCount" };
HashSet<int> ids = new HashSet<int>();
for (int j = 0; j < ml_obs.Length; j++)
{
for (int page = 1; page <= 5; page++)
{
string url = String.Format(
"**SNIPPED**?ml_ob={0}&mgtid=-1&mgm=False&pgnum={1}",
ml_obs[j], page);
string html = GetHttpPage(url, timeOut);
var memberNumberMatches = memberNumberRegex.Matches(html);
var repScoreMatches = repScoreRegex.Matches(html);
var displayNameMatches = displayNameRegex.Matches(html);
var memberSinceMatches = memberSinceRegex.Matches(html);
if (memberNumberMatches.Count == repScoreMatches.Count
&& memberNumberMatches.Count == displayNameMatches.Count
&& memberNumberMatches.Count == memberSinceMatches.Count)
{
for (int i = 0; i < memberNumberMatches.Count; i++)
{
int id = -1;
double score = -1.0;
double scorePerDay = 0.0;
DateTime memberSince = ParseDateTime(memberSinceMatches[i].Value);
if (memberNumberMatches[i].Groups.Count == 2 &&
Int32.TryParse(memberNumberMatches[i].Groups[1].Value, out id) &&
repScoreMatches[i].Groups.Count == 2 &&
Double.TryParse(repScoreMatches[i].Groups[1].Value, out score) &&
displayNameMatches[i].Groups.Count == 2)
{
if (!ids.Contains(id))
{
ids.Add(id);
if (memberSince != DateTime.MinValue)
{
scorePerDay = Math.Round(
score / (DateTime.Now - memberSince).TotalDays, 2);
}
var handler = MemberInfoScraped;
if (handler != null)
{
handler(this, new RepScoreScraperEventArgs()
{
Id = id,
DisplayName = StripOffHtml(
displayNameMatches[i].Groups[1].Value.Trim()),
ReputationScore = (int)score,
DailyAverage = scorePerDay
});
}
}
}
}
}
}
}
var finishedHandler = ScrapeFinished;
if (finishedHandler != null)
{
finishedHandler(this, EventArgs.Empty);
}
}
就这样。 如果您遇到任何问题,请使用下面的论坛报告这些问题,我会尽力解决。 谢谢。
致谢
- RaviRanjankr - 用于 beta 测试该应用程序并提供有用的反馈,这促使我改进和简化了提取代码。
历史
- 2010 年 11 月 17 日:首次发布
- 2010 年 11 月 19 日
- 添加了排名和每日平均列。
- 您现在可以刷新分数了。