ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

用CSDN列表页API快速获取全部博文数据:100秒实现年度盘点

用CSDN列表页API快速获取全部博文数据:100秒实现年度盘点 做技术写作这行每年年底自然要做一次内容盘点。我今年的复盘对象是CSDN上的博文一共写了几百篇真要一篇篇从后台复制标题、记录数据估计得耗掉一整天。结果我发现CSDN博文list页面背后直接架着一条数据接口接口返回的是干净的JSON标题、发布时间、阅读数、评论数全在里面。整个流程从分析接口到跑完全量数据压缩在100秒内就能完成这就是我在2025年最想分享的一个效率工具用list页面API快速拿回自己的博文数据自由。这篇内容适合内容创作者、运维同学以及所有需要在CSDN上做数据统计的人。我会从接口原理讲到实际代码再到容易踩的坑完整拆一遍。1. 为什么盯上CSDN的博文列表数据它能解决什么问题1.1 年终盘点时的真实痛点写博客的人到了年底多少会想做一份年度创作报告。标题写了哪些、哪篇阅读量最高、评论最多、一年下来更新频率是怎样的这些数据都散落在CSDN的各个页面里。后台数据看板能看到一部分汇总但拿不到明细也没有导出按钮。文章管理页虽然有列表但默认是分页加载一页二十来篇还需要手动翻页。我大概算过一笔账三百篇文章手工复制标题加记录阅读数最快也要两三个小时这还不算中途被其他事情打断的情况。这个痛点并不小众。很多技术人在CSDN写文章本质上是把自己解决问题的过程沉淀下来。到了复盘阶段数据就是衡量内容价值的证据。没有数据年度总结只能凭感觉写。所以我当时就想能不能直接从页面背后的接口把数据一次性取出来。前端页面再怎么渲染数据总归要从服务端过来浏览器能看到的每一个字段网络请求里一定有一份对应的数据源。1.2 列表页API和普通HTML抓取的区别最笨的办法是写爬虫去解析HTML把整个页面的标签结构读一遍再抽取出标题、时间等信息。这个方案问题很大。CSDN页面结构里有很多推荐模块、广告位、侧边栏真正的文章列表只占一小块。HTML解析需要针对具体的Dom结构写选择器而一旦页面布局调整选择器就全部失效需要重新适配。list页面API则完全不一样。它直接返回结构化数据通常是JSON格式字段是现成的不需要关心页面渲染逻辑。API接口的地址、请求参数、返回结构才是需要关注的核心。对比一下HTML解析依赖页面结构页面一改就崩解析成本高数据清洗麻烦。API获取依赖数据接口的字段结构接口稳定返回字段可直接映射效率高成本低。当然前提是你能找到这个接口。找到接口并不难浏览器开发者工具里抓一下Network请求就能看到列表数据是从哪个地址回来的。1.3 通过数据自由能做出哪些东西拿到全部博文数据之后能做的事情就多了。最基础的是导出成表格做年度复盘再进一步可以做标题词频分析看看自己整年都在写哪些技术话题还可以把阅读量、评论量排序找出真正被读者认可的Top10文章指导下一年的写作方向。如果把数据接上可视化工具还能做出一份个人创作数据面板发布时间分布、月度产量趋势、读者互动情况一屏全部展示出来。这些都是数据自由带来的附加价值。核心前提只有一个先快速、稳定地把数据拿到手。2. 理清CSDN列表页的数据流转机制2.1 列表页是服务端渲染还是异步加载要找到接口首先得搞明白页面数据究竟是怎么渲染出来的。打开自己CSDN博客主页的任意一篇文章列表页按F12进入开发者工具切到Network面板刷新页面观察请求列表。这里面会看到大量资源请求包括js、css、图片以及若干XHR或Fetch请求。如果页面数据是服务端渲染的那么HTML响应里直接包含文章列表内容不需要额外的异步请求。但CSDN的博文列表页实际采用的是服务端渲染加部分异步更新的混合模式。初次打开页面时服务端会返回一版渲染好的HTML保证内容可以被搜索引擎收录而当你点击翻页、切换排序方式时浏览器会向后端发起异步请求获取下一批数据。这就是关键突破口。浏览器控制台里能直观看到每次翻页都会发出一个以list相关的接口请求返回的内容是一段JSON或带有数据的HTML片段。这个接口就是我们需要的list页面API。2.2 接口地址和请求参数的基本形态在不同版本的CSDN页面中这个数据接口的具体地址会有差异。以我实测到的为例比较常见的一个接口形态是博客社区接口地址大致形如 blog.csdn.net 域名下的一个 /community/home-api/v1/get-business-list 路径通过GET或POST请求传入分页参数就能拿到当前用户的博文列表。实际请求参数通常包含这几个核心字段page页码从第1页开始。size每页数量常见是20或40。businessType业务类型博文列表场景一般传blog。username博主用户名接口靠它区分查询哪个用户的文章。除了这些可能还会有orderBy、noMore等辅助字段用来控制排序方式和判断是否还有更多数据。这些参数并不神秘全部能从浏览器的Network面板里看到。复制出这条请求在Python里模拟同样参数发出就能获得完全相同的数据。2.3 返回数据结构的关键字段接口返回的数据一般包含一个data对象里面是文章列表数组和分页信息。拿我抓到的结构做参考每个文章对象大致包含articleId文章ID唯一标识。title文章标题。description摘要文章开头的一段文字。viewCount阅读数。commentCount评论数。publishTime发布时间通常是时间戳。type文章类型区分原创还是转载。这些字段基本覆盖了做年度盘点时需要统计的全部维度。唯一要注意的是不同时期的CSDN接口字段名可能有细微差别比如有的版本叫viewCount有的叫viewNum有的直接叫reads。遇到字段对不上时先打印一条数据看看实际结构再调整字段名映射关系。2.4 身份认证和请求头的要求这里必须说明一个实际情况CSDN的list页面API在请求时对身份认证的要求并不一致。公开的博文列表部分场景下不登录也能直接访问但有些排序维度、某些后台接口则需要携带登录后的Cookie信息否则返回的数据不完整甚至直接403。所以最稳妥的做法是把自己在浏览器里已登录的Cookie手动复制到请求头里。具体操作是在Network面板找到任意一个请求在Request Headers区域复制整段Cookie字段。这个Cookie相当于你的身份凭证服务器靠它判断是你本人在请求数据。有一点要提醒Cookie有有效期过期之后需要重新复制。请求头的另一个重点是User-Agent。很多服务端会用这个字段判断请求来自正常浏览器还是脚本。推荐直接复制浏览器里的完整User-Agent字符串而不要用Python库的默认值。Referer字段也可以一并加上指向自己的博客主页这样更接近真实用户行为。3. 实操100秒内获取全部博文数据3.1 环境准备与依赖安装动手之前先准备好运行环境。我用的Python3配合requests做网络请求、pandas做数据处理、openpyxl做Excel导出。这三个库是常规组合在绝大多数Python环境里都能直接安装。pip install requests pandas openpyxl如果你的环境里已经装了Anaconda那么pandas和openpyxl大概率自带只需要补装requests即可。接下来把代码分模块写好先跑通单页请求再扩展到全量抓取。3.2 从单个页面的请求开始验证写代码的第一步不是一上来就写循环抓全部而是先把单页接口调通。用最少的代码验证接口地址、参数和Cookie是否正确避免后面全量请求时出问题还不知道错在哪。import requests import json username 你的用户名 cookie 复制浏览器里的Cookie整段 url https://blog.csdn.net/community/home-api/v1/get-business-list params { page: 1, size: 20, businessType: blog, orderBy: , noMore: false, username: username } headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36, Referer: fhttps://blog.csdn.net/{username}, Cookie: cookie } resp requests.get(url, paramsparams, headersheaders, timeout10) print(状态码:, resp.status_code) print(json.dumps(resp.json(), ensure_asciiFalse, indent2)[:1000])这段代码的作用是验证链路是否通畅。如果返回的状态码是200data里有文章列表说明接口没问题。如果看到403或者返回的JSON里提示需要登录那就是Cookie缺失或者过期了。先把这一段跑通再继续往下封装函数。3.3 自动翻页抓取全量数据单页通了之后就可以写翻页逻辑。分页接口的停止条件可以从返回结果里判断。有的接口会返回total字段告诉你有多少数据有的返回noMore字段标记是否还有下一页。以noMore和返回列表长度双条件作为停止依据更稳妥。def fetch_all_articles(username, headers): articles [] page 1 while True: params { page: page, size: 40, businessType: blog, orderBy: , noMore: false, username: username } resp requests.get(url, paramsparams, headersheaders, timeout10) data resp.json() items data[data][list] if not items: break articles.extend(items) print(f第{page}页累计获取{len(articles)}篇) # 判断是否还有下一页 if data[data].get(noMore) or len(items) int(params[size]): break page 1 return articles翻页的节奏要注意每页之间加一个短暂延时避免请求频率过高触发服务端限制。这里建议用time.sleep(0.5)平滑一点。如果只是几百篇文章分页请求加处理时间全部跑完也就在几十秒上下。3.4 数据清洗与字段整理拿到原始JSON数组后肯定不能直接用里面有很多无关字段还要把时间戳转成可读格式。用pandas处理这一步非常快。import pandas as pd import time df pd.DataFrame(articles) # 只保留需要的列 df_clean df[[ articleId, title, description, viewCount, commentCount, publishTime, type ]].copy() # 时间戳转成日期字符串 df_clean[publishTime] pd.to_datetime(df_clean[publishTime], unitms) # 重命名字段为更友好的名称 df_clean.columns [文章ID, 标题, 摘要, 阅读数, 评论数, 发布时间, 类型] # 输出统计信息 print(f共获取 {len(df_clean)} 篇文章) print(f总阅读量: {df_clean[阅读数].sum()}) print(f文章标题长度均值: {df_clean[标题].str.len().mean():.1f} 字)清洗后的DataFrame可以直接用于统计也可以导出成Excel。3.5 导出Excel表格与可视化前的准备导出Excel的核心代码很简单用pandas的to_excel方法就能完成。但有几处细节值得处理一下。with pd.ExcelWriter(csdn_articles.xlsx, engineopenpyxl) as writer: df_clean.to_excel(writer, sheet_name全部文章, indexFalse) # 额外生成一张阅读量排序表 df_top df_clean.sort_values(阅读数, ascendingFalse).head(20) df_top.to_excel(writer, sheet_name阅读Top20, indexFalse)Excel里有两个Sheet一个放全部数据一个是阅读量Top20。后续如果再接入图表工具直接从Excel读取就行。导出后建议快速检查一下总行数是否和CSDN后台显示的文章数一致对不上就说明还有分页没抓全回头检查noMore判断逻辑。3.6 批量获取文章详情扩充维度列表接口返回的字段已经够做年终盘点了但如果你还想要每篇文章的点赞数、收藏数甚至正文里的图片数量那就需要进入每篇文章的详情页再抓一次。这属于增强操作不建议在第一次跑的时候就做完整因为详情页请求量是文章数的N倍耗时和触发风控的概率都会上升。如果确实要跑可以做一些节流措施每请求一篇文章详情后sleep 1到2秒只对Top50或者某一时间段内的文章做详情抓取请求失败时记录日志全部跑完后再重试失败项。这样既保证数据完整也不至于把服务端惹毛。4. 常见问题与排查技巧实录4.1 请求返回403或400问题出在哪403是最常见的状态码。多发生在Cookie失效、请求头缺少Referer、或者触发了访问频率限制。处理方式按优先级排查先检查Cookie是否复制完整再确认User-Agent是不是浏览器默认的最后看Referer是否正确指向自己的博客页面。还有一个容易忽略的点某些请求头的顺序或大小写不敏感但Cookie里的关键字段被删减会导致权限不足。400错误往往是参数问题。比如接口要求的businessType必须传blog但传成了article或者size不能超过某个上限超过后直接拒绝。遇到400先去翻接口文档或对比浏览器里发出的请求参数逐字段核对特别是数字类型的参数不要传成字符串。4.2 返回的字段被整体包成字符串怎么还原这个情况我在调试时遇到过接口返回的文章标签字段本身是一个List但被序列化成了字符串形如“[Python, API]”。直接用这个字段做分析会出问题因为整段字符串都不是一个真正的列表。处理方式是使用Python标准库里的ast.literal_eval安全地把字符串还原成列表再展开统计。import ast def parse_tag(tag_str): try: tag_list ast.literal_eval(tag_str) return tag_list if isinstance(tag_list, list) else [] except Exception: return [] df_clean[标签] df_clean[标签字符串].apply(parse_tag)用ast.literal_eval而不是eval是因为前者只处理Python字面量表达式安全性更高。这个排查思路适用于一类问题接口返回的字段类型和你预期不一致时先看看是不是被外层包了字符串。4.3 请求一多就被限流怎么调整节奏跑全量抓取时刚开始可能一切正常几十页之后突然连续返回429或者503。这是服务端在做限流。最简单有效的对策是加大间隔。单线程场景下把相邻两次请求的间隔从0.5秒提高到1到1.5秒一般就能解决。如果文章数量特别多还可以在连续请求失败时自动退避失败次数越多等待时间越长。import time import random def gentle_sleep(fail_count0): base_sleep 1.0 if fail_count 0: time.sleep(base_sleep * (2 ** fail_count) random.random()) else: time.sleep(base_sleep)这种指数退避策略在调用各类接口时都通用。我自己的习惯是宁愿多花几十秒也不要因为请求太猛而浪费更多时间在解锁限制上。4.4 接口结构更新后如何快速适配CSDN页面升级接口字段名变动这事情我遇到过几次。每次变动的规律基本一致接口地址可能不变但返回字段名会有调整。快速适配的办法是不要硬编码字段而是先打印原始JSON结构再写一层字段映射。def normalize_article(raw): return { 文章ID: raw.get(articleId) or raw.get(id), 标题: raw.get(title) or raw.get(articleTitle), 阅读数: raw.get(viewCount) or raw.get(viewNum) or raw.get(reads), 发布时间: raw.get(publishTime) or raw.get(createTime), }这层映射函数是适配接口变动的最佳缓冲。万一某个字段在新版本里被改名只需要在normalize函数里补一个or分支改动成本极低。4.5 抓到的文章数和后台对不上这是很多做数据抓取的人都会遇到的坑。跳转和置顶文章可能不在普通列表接口里草稿和审核中的文章也不会出现在对外接口。如果只是做年度盘点这个偏差可以接受如果要求精确就需要结合后台管理接口再补一次数据。后台管理接口一般对登录态要求更高Cookie过期风险也更大建议在确认必要后再额外处理。5. 数据自由之后可以做的几件事5.1 用词频分析找出自己这一年到底在写什么拿到标题字段后最有趣的分析是词频统计。用jieba把标题切成词过滤掉没有实际含义的停用词剩下的高频词基本就是你这一年的技术关注点。import jieba from collections import Counter stopwords set([使用, 实现, 一个, 开发, 部署]) words [] for title in df_clean[标题]: words.extend([w for w in jieba.cut(title) if w not in stopwords and len(w.strip()) 1]) top_words Counter(words).most_common(20) print(top_words)从结果里你能非常直观地看到自己这一年到底是在深耕某一个方向还是在多个话题之间横跳。这种判断靠直觉往往不准确数据摆出来会诚实很多。5.2 做一份年度创作趋势曲线把发布时间按月分组统计每个月发布的文章数量就能画出一条创作趋势线。我自己的数据跑出来之后发现某几个月产量明显偏低一回忆那段时间确实在忙其他项目基本没怎么更新。这条曲线能帮助你复盘自己的创作节奏是否合理也能为下一年的更新计划提供参考。月度产量的统计代码非常简单monthly df_clean.copy() monthly[月份] monthly[发布时间].dt.to_period(M) monthly_count monthly.groupby(月份).size()统计结果可以输出成CSV也可以直接喂给Excel透视表做图表。不需要额外的可视化依赖。5.3 把脚本固化成每周自动执行的小工具数据自由的价值在于可持续性。第一次跑完拿到的是年度快照如果希望随时能查看最新数据可以把这段脚本固化下来接到服务器的定时任务里。每周自动跑一次把结果追加到同一个Excel文件里长期积累之后你就有了一份属于自己的完整创作数据时间序列。脚本固化时有两个注意点Cookie到期需要手动更新这是最麻烦的另外CSDN接口偶尔会改字段名建议给脚本加一个告警逻辑一旦返回的数据结构和预期不符就发一条通知出来而不是默默地抓到一堆空数据。这个习惯能帮你在接口变更时第一时间发现而不是等到月底复盘时才发现数据全是空的。5.4 数据面板化之后的衍生价值对个人来说一份数据表格已经能满足年终复盘需求。但如果你的内容会对外输出比如做技术分享、接商业合作那么一份清晰的数据面板就更有说服力了。把阅读量Top10、评论量Top10、月度发布量这些维度整理成截图或PDF能让你的内容价值一目了然。这也是为什么我建议整个流程尽量自动化因为数据是需要持续更新的手工拉数撑不了几个月。写在最后的一点体会我从2024年开始做个人内容数据的定期整理最开始也是手工复制粘贴后来逐步摸索出了这套基于list页面API的获取方式。最深的体会有两点第一点是数据接口其实一直都在那里关键是养成看Network面板的习惯不要被页面的花哨结构吓退第二点是代码本身不难难的是把异常情况处理好Cookie过期、字段变动、请求限流每一样都需要在实战中积累对策。最后分享一个我自己的小技巧不要只在年底才跑一次数据平时每个月跑一次把结果存档年底复盘时拿出十二个月的数据做对比整个人的创作轨迹会非常清晰。这样做还有一个好处就是对这套脚本足够熟悉等真正需要的时候100秒只是启动成本真正值钱的其实是持续稳定的数据积累。
返回列表