文章目录
- 领域热榜爬取函数
- 领域热榜按钮
- 功能实现
热榜分析系列: CSDN热榜分析🔥 UI界面🔥 领域热榜
领域热榜爬取函数
CSDN热榜共有21个子领域,包括C++、云原生、人工智能、前沿技术、软件工程、后端、Java、JavaScript、PHP、Python、区块链、大数据、移动开发、嵌入式、开发工具、结构与算法、微软技术、测试、游戏、网络、运维等。
这些领域热榜的地址https://blog.csdn.net/rank/list/content?type=?,问好表示所在榜单名称,例如Python领域热榜的地址是https://blog.csdn.net/rank/list/content?type=python。
而且领域热榜和总榜的html结构是完全相同的,也就是说之前用于总榜的getHeatInfos可以继续使用。唯一不同是,领域热榜只排到第50名,而且有些可能不足50名,所以需要做一个标记来终止其运行,最终getHeatInfos修改如下
def getHeatInfos(callback, key=None):URL_ALL = 'https://blog.csdn.net/rank/list'URL_SUB = f'https://blog.csdn.net/rank/list/content?type={key}'nBlogs = 50 if key else 100driver = openEdge(URL_SUB if key else URL_ALL)titleClass = "floor-rank-item"ts, nTs, it = [], 0, 0# 获取100篇热榜博客while len(ts) < nBlogs:script = "window.scrollTo(0,document.body.scrollHeight)"driver.execute_script(script)ts = driver.find_elements(By.CLASS_NAME, titleClass)time.sleep(0.5)info = f"已读取到{len(ts)}篇热榜博客"if callback: callback([], info)it = it+1 if len(ts) == nTs else 0nTs = len(ts)if it > 5 : breakcallback([], f"已读取到所有热榜博客,开始处理")blogs = []for t in ts:ws = t.text.split('\n')blogs.append([ws[i] for i in [0, 1, 10, 2, 4, 6, 8]])b = blogs[-1]callback(blogs, f"正在处理第{b[0]}篇博客,热度{b[-1]}")callback(blogs, f"全部热榜博客处理完毕")return blogs
领域热榜按钮
接下来添加一个领域热榜的按钮,考虑到这些领域实在太多,不太好每个领域给个热榜,故而用Menubutton来实现。又考虑到一个一个去爬太费劲,所以除了各领域之外,提供一个全部爬取的选项。
def setFrmHeat(self, frmHeat):# 省略。。。mb = ttk.Menubutton(frmHeat, width=10, text="领域内容榜")mb.pack(side=tk.LEFT)m = tk.Menu(mb, tearoff=False)m.add_command(label="全部领域", command = lambda : self.mbSubHeatCrawler(None))for key in SUB_HEATS:m.add_command(label=key,command = lambda : self.mbSubHeatCrawler(key)) mb.config(menu=m)# 省略。。。def mbSubHeatCrawler(self, key):pass
setFrmHeat函数在之前的博客中已经定义了,上面只给出需要添加的Menubutton的代码。其中SUB_HEATS被做成了一个全局变量,便于引用。
SUB_HEATS = ["C++", "云原生", "人工智能", "前沿技术", "软件工程", "后端", "Java", "JavaScript", "PHP", "Python", "区块链", "大数据", "移动开发", "嵌入式", "开发工具", "结构与算法", "微软技术", "测试", "游戏", "网络", "运维"]
界面效果如下
功能实现
接下来要实现mbSubHeatCrawler函数,同时需要更新导出热榜按钮的功能,即既可以导出总榜,也可以导出领域热榜。
同时,为了能够一次性把所有领域热榜都爬取一遍,需要再实现一个函数,这个函数写在类外面,和getHeatInfos级别相同。
def getAllSubHeatInfos(callback):blogs = {}for key in SUB_HEATS:callback(blogs, f"正在读取{key}领域热榜")blogs[key] = getHeatInfos(callback, key)callback(blogs, f"{key}已经读取完成")callback(blogs, f"所有领域热榜都已读取完毕")
然后就是重头戏,领域热榜的爬取逻辑。由于每个领域都有自己的榜单,所以存储领域热榜的数据用字典最为合适,故而添加一个类成员self.subHeats。有关各领域热榜的实现逻辑如下。
def mbSubHeatCrawler(self, field):if not field:self.subHeats = {}Thread(target = getAllSubHeatInfos,args=(self.backAllSubHeat, ), daemon=True).start()else:func = lambda L, info : self.backOneSubHeat(L, info, field)Thread(target = getHeatInfos,args=(func, field), daemon=True).get()def backOneSubHeat(self, L, info, field=None):self.subheats[field] = Lself.infoCSDN.update(dct)if info.endswith("完毕"):n = len(self.subheats[field])self.addLogs(f"共读取了{key}领域{n}篇博客")def backAllSubHeat(self, dct, info):if type(dct) == dict:self.subHeats.update(dct)self.infoCSDN.set(info)if info.endswith("完毕"):self.addLogs(f"共读取了{len(self.subHeats)}个领域")
同时,热榜导出函数也要更新
def mbExportHeat(self):heatHead = ["序号", "标题", "作者", "浏览", "评论", "收藏", "热度"]if len(self.heatBlogs) > 0:self.mbExport(self.heatBlogs, heatHead, "热榜博客")if len(self.subHeats) > 0:subs = []for k,v in self.subHeats.items():subs.extend([[k]+L for L in v])subHead = ["领域"] + heatHeadself.mbExport(subs, subHead, "各领域热榜博客")