Python 详解爬取并统计CSDN全站热榜标题关键词词频流程

发布时间:2026/10/8 16:02:34
Python 详解爬取并统计CSDN全站热榜标题关键词词频流程 前言先直接点破标题里不准确的地方全站这个词不该照字面执行。一个技术社区有海量页面为统计词频而向对方站点发起全站量级的请求会给对方服务器带来实实在在的负担也几乎必然会触发限流甚至封禁。本文演示的是一个小规模、带节流、只读公开热榜页的流程明确遵守 robots 协议使用可识别的真实 User-Agent 与联系方式请求之间严格限速只取公开可见的页面内容。还有一条红线不绕过任何登录墙、付费墙、验证码或反爬机制。如果目标页面对匿名访问不可见那么它就不该出现在这个流程里。合规不是附加说明而是这个任务能否成立的前提。本文的代码全部使用 Python 标准库urllib.request、urllib.robotparser、re、collections不依赖任何第三方库本机没有解释器代码只能逐行人工推演。词频统计部分是本文最实在、最保值的部分。一、先讲合规什么能做、什么不能做在写任何一行抓取代码之前先确认边界事项应当做的绝对不做的robots.txt先读取并遵守其 Disallow 规则无视 Disallow 硬抓身份标识使用真实、可识别的 User-Agent注明联系方式伪造浏览器身份伪装请求频率严格 sleep 限速失败指数退避并发压站、多线程猛刷访问范围只取公开、匿名可见的页面绕过登录墙、付费墙、验证码数据用途统计分析、学习研究大规模转售、恶意消耗对方资源urllib.robotparser就是标准库里做这件事的工具。它的用法是构造解析器、设置 robots.txt 地址、读取然后用can_fetch询问某个 User-Agent 能不能抓某个 URL。# 适用于 Python 3.8import urllib.robotparserrp urllib.robotparser.RobotFileParser()rp.set_url(https://www.example.com/robots.txt)rp.read()allowed rp.can_fetch(MyResearchBot/1.0 (contact: meexample.com),https://www.example.com/hot)print(是否允许抓取:, allowed)注意上面这个例子里同时用了crawl_delay这类可选信息——如果 robots.txt 里写了抓取延迟就应当取那个值和自己的限速值中更保守的一个。二、抓取一个可识别、可节制的请求标准库里的做法是构造一个urllib.request.Request显式设置 User-Agent 和联系方式再用urlopen带上超时发出去。# 适用于 Python 3.8import timeimport urllib.errorimport urllib.requestUA MyResearchBot/1.0 (contact: meexample.com)HEADERS {User-Agent: UA, Accept-Language: zh-CN,zh;q0.9}def polite_get(url, min_interval3.0, retries3):带限速与指数退避的单页抓取。min_interval 是两次请求的最小间隔秒数。last_err Nonefor attempt in range(retries):try:req urllib.request.Request(url, headersHEADERS)with urllib.request.urlopen(req, timeout15) as resp:raw resp.read()charset resp.headers.get_content_charset() or utf-8time.sleep(min_interval) # 无论成败都等待避免连打return raw.decode(charset, errorsreplace)except urllib.error.HTTPError as exc:last_err excif exc.code in (403, 429): # 被拒或被限流退避绝不换招硬闯time.sleep(min_interval * (2 ** attempt))else:raiseexcept urllib.error.URLError as exc:last_err exctime.sleep(min_interval * (2 ** attempt))raise RuntimeError(重试次数用尽) from last_err三个设计要点显式 User-Agent。库默认的 User-Agent 往往是一串通用字符串站长无从判断你是谁。写上机器人名和联系邮箱对方遇到问题时能找到你这是最基本的技术礼貌。失败不是硬闯的理由。收到 403 或 429正确反应是退避与放慢而不是换 User-Agent、换 IP 继续试。那类操作正是被禁止的绕过行为。无论成败都 sleep。把等待放在 finally 性质的位置避免失败得快反而变成打得更快。三、解析标题先看清页面结构抓回来的热榜页是 HTML。解析它的前提是先人工打开页面确认标题所在标签的层级与 class 名。不同时间、不同端Web / 移动的页面结构可能完全不同所以解析逻辑要写得足够防御找不到就返回空列表而不是抛异常炸掉整条流程。# 适用于 Python 3.8import reTAG_RE re.compile(r[^])def strip_tags(html):把 HTML 标签剥掉得到纯文本。这里只做最保守的处理。text TAG_RE.sub( , html)text text.replace(amp;, ).replace(lt;, ).replace(gt;, )return textdef extract_titles(html):示意用正则从某个已知结构的标签里取标题。真实项目里请先打开页面确认结构结构变化时返回空列表而非报错。pattern re.compile(ra[^]*class[^]*hot-item-title[^]*[^]*(.*?)/a,re.S,)titles []for match in pattern.finditer(html):title strip_tags(match.group(1))title re.sub(r\s, , title).strip()if title:titles.append(title)return titles这里的要点是正则解析 HTML 是脆弱的页面结构一变就失效。它在这个小规模场景里够用是因为我们只盯着一类结果而且失败了只是拿到空列表、不会误伤数据。如果需求变复杂应当换用专门的 HTML 解析库那又是另一个话题。四、分词与词频统计本文最硬的部分拿到标题列表后统计词频。中文没有空格分词常见做法是把连续的中文字符切成二元组bigram再过滤掉标点和纯数字英文单词则按字母切。# 适用于 Python 3.8import refrom collections import CounterCJK re.compile(r[一-鿿])WORD re.compile(r[A-Za-z][A-Za-z0-9#.\-]*)def tokenize(title, stopwordsfrozenset()):把一条标题切成词元中文取二元组英文按词。tokens []for chunk in CJK.findall(title): # 连续的汉字片段if len(chunk) 1:tokens.append(chunk)else:tokens.extend(chunk[i:i 2] for i in range(len(chunk) - 1))tokens.extend(w.lower() for w in WORD.findall(title))return [t for t in tokens if t not in stopwords]def word_frequency(titles, top_n30):counter Counter()for title in titles:counter.update(tokenize(title))return counter.most_common(top_n)if __name__ __main__:demo [Python 爬虫入门教程,Python 数据分析实战,python 爬虫进阶,]for word, freq in word_frequency(demo):print(f{word}\t{freq})几个关键点Counter.update(iterable)逐元素计数比手写字典d[w] d.get(w, 0) 1更简洁而且它是原地修改、返回None。most_common(n)返回出现次数最多的 n 项形式是(元素, 次数)的列表。不传n时返回全部。Counter的/-是多重集运算会合并计数-只保留正数计数。如果只想减去某几个词的计数、允许出现负数要用subtract它是原地操作且不丢弃非正计数。归一是必要的。Python 和 python 应当算同一个词所以统一小写全角标点、多余空格也要先清洗否则同一个词会被拆成几个键。常见坑点把全站当成字面目标。❌ 为了统计更全面对社区全站页面发起遍历式抓取。 ✅ 明确高频请求会给对方站点造成负担改为只取公开热榜页这类小样本并在正文里说清样本范围。无视 robots.txt。❌ 代码里根本不读 robots.txt直接开抓。 ✅ 每次上线前用RobotFileParser检查目标路径是否被允许并遵循其中声明的抓取延迟。失败就换身份硬闯。❌ 遇到 403 或 429 就改 User-Agent、挂代理继续重试。 ✅ 遇到拒绝或限流应当退避、降速甚至停止这属于合规红线不是技术技巧问题。用默认 User-Agent 隐藏身份。❌ 使用库自带的通用 User-Agent或者伪装成浏览器。 ✅ 使用可识别、可联系的机器人标识让对方有办法找上门。把限速写在成功分支里。❌ 只在请求成功后才 sleep异常路径下反而密集重试。 ✅ 把等待放在所有分支都会经过的位置并采用指数退避控制重试节奏。忘记设置超时。❌urlopen不传 timeout个别请求挂住导致整条流程停滞。 ✅ 显式设置超时秒数并对超时按失败处理。用一个正则硬解整个页面。❌ 认为页面结构不会变正则匹配不到就抛异常中断。 ✅ 解析失败时返回空结果并记录日志结构变化能被及时发现而不是静默出错。中文分词直接按标点切。❌ 用re.split按标点把中文句子切成整段词组词频统计被长词主导。 ✅ 中文用 n-gram 或专业分词工具切成词元再统计并做好大小写与标点归一。总结环节正确做法关键边界合规读 robots.txt、真实 UA、严格限速不碰登录墙与反爬机制请求超时 指数退避 每次都等待被拒就退避不换身份硬闯解析先人工确认结构失败返回空正则解析 HTML 天然脆弱分词中文 n-gram、英文按词、统一小写归一化不做词频就不可信统计Counter.updatemost_commonupdate原地改并返回 None一句话这个任务的难点不在怎么写爬虫而在知道哪些不做。把全站降级为公开热榜页的小样本把请求节制做扎实再用Counter老老实实统计词频就是一份经得起审视的流程。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询