尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
音乐排行榜爬虫完整指南:Python数据采集与工程实践从零到稳定运行
1. 拆解“音乐排行榜爬虫”先搞清楚你要爬的到底是什么提起“音乐排行榜爬虫”很多人第一反应就是“写个脚本把歌曲名和歌手抓下来存进表格”。但实际做起来会发现真正麻烦的从来不是抓取本身而是榜单数据背后的结构和语义。音乐平台上的榜单五花八门有实时榜、飙升榜、新歌榜、热歌榜、原创榜不同榜单更新频率不一样榜单里每首歌的字段也不一样有的平台返回的是歌曲ID和播放链接有的则直接给出完整的专辑封面和MV信息。如果不提前把这些搞清楚代码写一半就会卡住。我当年第一次动手做的时候以为就是从某个网页里解析出歌名列表半小时就能收工。结果真上手才发现光“榜单的URL长什么样”就折腾了几个小时——有的平台榜单藏在二级页面里需要先请求接口才能拿到有的平台桌面端网页和移动端接口返回的数据结构完全不同。所以第一步别急着写代码先做“侦察”打开目标页面把榜单的类型、URL、更新频率、返回格式是HTML还是JSON全部记下来做成一个清单。这一步做好了后面就是体力活。这个项目适合谁适合刚学完Python基础、想练手requests和解析库的人也适合已经有爬虫经验、想系统性梳理一下“真实场景下怎么设计一个稳定爬虫”的人。因为音乐排行榜数据量不大但更新频繁正好用来练习“增量更新”、“异常重试”、“数据落库”这几个进阶技能。而且这个项目可以做得非常完整从定时调度、日志记录、数据归档到简单的趋势分析都能围绕“排行榜”这一个主题串起来练完等于走了一遍小型数据管道项目。音乐排行榜爬虫的核心价值不在于“爬到榜单”而在于“稳定地、按节奏地、不重复地把榜单变化记录下来”。你爬下来的榜单如果只跑一次那只是一张静态截图如果你每天定时跑、每次记录排名变化那积累下来的就是一首歌的热度曲线、一个歌手的蹿升趋势、甚至整个排行榜的更替规律。这才是这个项目真正有意思的地方。2. 技术选型与设计思路别一上来就框架先行2.1 语言和库的选择Python依然是最顺手的做音乐排行榜爬虫我默认推荐Python。不是因为它性能最好而是因为这个场景下生态太全了遇到问题搜一下就有答案不用自己造轮子。核心就四个库requests发HTTP请求拿HTML或JSON回来。简单直接比urllib好用太多。BeautifulSoup4或lxml解析HTML时用后者速度更快但语法稍繁琐新手优先用前者。json标准库处理JSON接口时必备。pandas把解析结果整理成表格或者进一步分析时用。如果你是想做一个长期稳定的采集任务建议再加APScheduler做定时调度SQLite或MySQL做数据存储logging记录运行日志。但这些属于“进阶装配”刚开始跑通一个单次脚本就行别让工具选择变成负担。有人会问“为什么不直接上Scrapy”Scrapy确实强大但它是“重型武器”配置项多、学习曲线陡做排行榜这种轻量场景属于杀鸡用牛刀。我的建议是先用requests跑通逻辑确认能拿到数据了再考虑要不要迁移到Scrapy。很多时候你会发现根本不需要迁移一个小脚本加个循环就能满足全部需求。2.2 目标数据结构先画出你要的“表”动手前花十分钟思考我最终要存下什么我的建议是至少包含这几个字段歌曲名歌手名排名所属榜单名称采集时间前四个字段好理解“采集时间”是很多人忽略的重中之重。有了采集时间你才能回答“这首歌上周排第几、这周排第几、是升了还是降了”这类问题。所以每次采集时间字段必须由程序自动写入不要用歌名查库补充那样既麻烦又容易出错。如果你还想做更深入的分析可以增加歌曲ID平台内部编号、专辑名、上榜天数、歌词摘要、封面图URL、播放链接等。字段越多后期分析空间越大但采集和清洗的工作量也会上升。我的经验是先跑通最小字段集再按需加字段。一上来就想抓全字段容易被各种异常格式拖住进度。2.3 榜单来源的特点分析网页端和接口的差异很大不同音乐平台的榜单获取方式大致分三类纯静态HTML页榜单内容直接在网页源码里解析起来最省事requests拿到HTML用BeautifulSoup提取即可。带渲染的动态页面榜单数据在页面源码里找不到是JS动态加载的。这种要么用Selenium模拟浏览器要么去Network面板里找背后的XHR/JSON接口。直接提供JSON API平台有内部接口返回结构化数据。这种最理想连解析都省了直接转成Python字典处理。我强烈建议优先找JSON接口。因为JSON接口返回的数据结构清晰、字段完整还带有歌曲ID等关键标识比解析HTML可靠得多。怎么找打开浏览器开发者工具的Network面板刷新页面筛选XHR请求找一个返回内容里包含榜单数据的请求把它的URL记下来分析参数。比如有些榜单接口只需要传一个榜单ID和页码参数就能翻页拿到全部数据比处理HTML舒服太多。提示不管用哪种方式一定要遵守目标平台的服务条款和数据使用规范。个人学习研究没问题但大量高频抓取会消耗平台资源务必控制频率、合理使用。3. 核心细节解析请求、解析、存储每一环都有坑3.1 请求配置别拿到数据就被封了IP请求部分的坑主要集中在Header设置上。很多平台对非浏览器的请求有识别所以必须把User-Agent伪装成正常的浏览器。看一段最小配置import requests headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Accept: application/json, text/plain, */*, Referer: https://music.example.com/, } url https://api.example.com/chart/toplist params {id: 26, page: 1, limit: 100} resp requests.get(url, headersheaders, paramsparams, timeout10) print(resp.status_code)这里的要点有三个timeout必须设置否则遇到慢响应会一直挂在那。不要在代码里写死同一个IP高频请求两次请求之间至少间隔1-2秒。爬排行榜这种轻量任务用time.sleep(2)就够了不需要搞代理池。用params传参数不要自己拼URL。带上中文参数时requests会帮你做URL编码省去一堆麻烦。关于反爬我要多说一句音乐排行榜数据属于常规公开数据大多数平台的限制并不严格。真正需要担心的是自己代码写得不稳比如没有异常处理、没有重试机制导致一个网络抖动就挂了。所以请求部分的核心不是“对抗”而是“稳健”。3.2 解析策略HTML和JSON两手准备如果是JSON接口解析就是一句话的事data resp.json() for item in data[data][list]: song_name item[songName] artist item[singerName] rank item[rank]如果是HTML就要用BeautifulSoup来找节点。但网页结构经常调所以我的建议是写解析代码时把“选择器”单独抽出来放在一个配置区不要散落在代码各处。比如这样SELECTORS { song: div.song-name, artist: p.artist, rank: span.rank-num, }这样以后页面改版了只需要改一处不用满文件找选择器。解析的时候还有一个高发问题榜单里偶尔会混入一些异常行比如“广告推荐位”“小编推荐”这种非歌曲条目。它们没有正常的歌名或歌手字段解析时会报错。所以取字段时尽量用.get()或者try-except兜底遇到缺字段的条目直接跳过不要让整批数据失败。3.3 存储与去重排行榜爬虫最容易被忽略的环节很多人爬完榜单直接打印看一下就完了图省事不存库。但如果你要做趋势分析必须落库。我个人推荐第一版就用SQLitePython标准库自带sqlite3零配置单文件非常适合这种规模的数据。建表语句很简单CREATE TABLE IF NOT EXISTS music_rank ( id INTEGER PRIMARY KEY AUTOINCREMENT, song_name TEXT NOT NULL, artist TEXT, rank INTEGER, chart_type TEXT, create_time TEXT DEFAULT (datetime(now, localtime)) );每次跑完榜单把数据按批次插入。这里有一个去重细节同一首歌可能连续几天都在榜上如果你每次采集都往里插表里就会有很多重复记录。正确的做法是判断“这首歌今天是不是已经在榜了”——如果今天已经采过这个榜单就先删除今天的记录再插入或者用“榜单类型歌曲ID采集日期 ”做一个联合唯一键存在就更新排名不存在就插入。cursor.execute( SELECT id FROM music_rank WHERE song_name? AND chart_type? AND date(create_time)date(now), (song_name, chart_type) ) if cursor.fetchone(): cursor.execute( UPDATE music_rank SET rank?, artist? WHERE song_name? AND chart_type? AND date(create_time)date(now), (rank, artist, song_name, chart_type) ) else: cursor.execute( INSERT INTO music_rank (song_name, artist, rank, chart_type) VALUES (?, ?, ?, ?), (song_name, artist, rank, chart_type) )这套逻辑看着简单但能解决“榜单每日更新、数据不能重复”这个核心问题。等数据积累几周后你想查“某首歌的排名变化曲线”一条SQL就出来了。4. 实操过程从零到跑通一个能用的排行榜爬虫4.1 第零步选定一个目标榜单作为练手对象假设我们要做一个“某平台热歌榜”的爬虫榜单URL为https://music.example.com/chart/26打开页面后按F12在Network里翻一下找到返回榜单数据的接口https://api.example.com/chart/list?id26page1。这步最关键确认接口行为后再动手写代码。4.2 第一步验证接口打印原始返回写代码前先在Python里直接请求一次接口把返回的JSON打印出来看看字段长什么样。这一步叫“探数据”能帮你省掉后面80%的解析问题。你需要在返回结果里确认榜单数据放在哪个键下面是data.list还是data.song每首歌的字段名是什么歌曲名是songName还是title歌手是singerName还是artist分页参数怎么传总页数从哪里获取resp requests.get(https://api.example.com/chart/list, params{id: 26, page: 1}, headersheaders, timeout10) data resp.json() print(json.dumps(data, ensure_asciiFalse, indent2)[:3000])我每次做新站点爬虫都会先把这段探数据代码保存成一个单独的文件以后换目标时改URL就行。4.3 第二步写解析函数根据上面探到的字段结构写一个解析函数把单页数据转成列表def parse_page(data): result [] for item in data.get(data, {}).get(list, []): song_name item.get(songName) or item.get(title) artist item.get(singerName) or item.get(artist) rank item.get(rank) if not song_name or not artist: continue # 跳过异常行 result.append({ song_name: song_name.strip(), artist: artist.strip(), rank: rank }) return result这里用dict.get()加or的写法是为了兼容不同平台字段命名差异遇到空值跳过则保证后续入库不报错。4.4 第三步写主流程和控制频率主流程就是“循环翻页每页解析后入库”。这是整个爬虫里最容易失控的地方——不控制频率疯狂请求接口结果就是被平台限制。我的做法是PAGE_COUNT 3 # 先跑3页看看效果 for page in range(1, PAGE_COUNT 1): resp requests.get(url, params{id: 26, page: page}, headersheaders, timeout10) if resp.status_code 200: page_data parse_page(resp.json()) save_to_db(page_data) print(f第{page}页完成共{len(page_data)}条) time.sleep(2) # 间隔2秒很克制不要因为排行榜数据量小就一次把所有页全拉完尤其是第一次调试跑两页验证逻辑没问题再放开到全量。4.4 第四步加日志和异常重试日志这东西前期写代码时总觉得麻烦等脚本跑挂了、你想知道“到底挂在哪一页哪条数据”的时候就能体会到它的珍贵了。我的做法是用logging模块把每次采集的开始时间、完成页数、成功条数、失败原因都记录下来import logging logging.basicConfig( filenamechart_spider.log, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s ) logging.info(开始采集热歌榜) try: # 采集逻辑 logging.info(采集完成共写入%d条, total) except Exception as e: logging.error(采集失败: %s, e, exc_infoTrue)异常重试也很简单包一层循环最多重试3次每次退避2秒def fetch_with_retry(url, params, headers, retries3): for i in range(retries): try: resp requests.get(url, paramsparams, headersheaders, timeout10) if resp.status_code 200: return resp.json() except Exception as e: logging.warning(第%d次请求失败: %s, i 1, e) time.sleep(2) return None这一点点额外的代码能让你的爬虫从“跑一次碰运气”变成“能稳定地长期跑”。5. 常见问题与排查技巧实录5.1 请求返回403或429403通常意味着你的请求被识别为非浏览器行为检查User-Agent、Referer、Accept这些Header是否完整429则是请求频率太高被限流了。解决方法是加大间隔时间、降低并发、必要时加入随机延时。排行榜爬虫完全没必要高并发老老实实跑就行。5.2 接口返回的数据和浏览器里看到的不一样这种情况经常出现在“接口需要登录态”的平台上浏览器里能看到是因为你带着Cookie而代码里没带。排查方法很简单打开Network里的请求把Cookie字段复制到代码的Header里基本就能解决。但要注意Cookie会过期不是长久解决方案长期跑的话研究一下平台是否有公开开放的榜单接口。5.3 页面结构改版选择器失效音乐平台改版频率不低尤其换季或节日时会调整页面。如果哪天跑完脚本发现解析结果为0大概率是页面结构变了。这时候不要慌重新打开页面用开发者工具定位到榜单区域看看新的节点结构改选择器配置就行。这也是为什么我之前强调“选择器要单独抽出来”改起来真的快。5.4 中文乱码问题请求返回HTML时如果没设置正确的编码中文就容易变成乱码。resp.encoding resp.apparent_encoding可以自动猜编码但偶尔会猜错。更稳妥的方式是查看页面源码里的charset声明直接指定编码。JSON接口一般不会乱码因为JSON标准默认UTF-8。注意这是我从多次踩坑里得出的经验——排查时先看原始返回内容不要一上来就去改解析逻辑。很多时候你以为解析写错了其实是请求的URL不对或参数传错了打印出来一眼就能看出来。5.5 常见问题速查表现象可能原因排查方式请求返回403Header不全或被识别为机器人补全User-Agent、Referer、Accept请求返回429频率太高触发了限流加大请求间隔减少并发返回数据为空列表榜单ID错误或参数过期用浏览器验证接口URL是否还返回数据解析报KeyError字段结构变化打印原始JSON确认字段名中文乱码编码设置错误明确指定resp.encoding跑了一天后不再入库可能被平台封了IP或Cookie失效检查日志看返回状态码歌曲重复入库去重逻辑没加加联合唯一键或先查后插5.6 一个典型排查案例有次我的脚本前一天还能跑第二天突然返回数据为空。我先打印了原始响应发现接口返回了一段HTML而不是JSON——说明URL没有变但接口需要通过特定入口访问直接访问时就跳转到了验证页面。解决办法是补上Referer头让请求看起来像是从榜单页面内部发出的。这个案例说明遇到问题时从“请求层面”检查的顺序要优先于“解析层面”。6. 反爬应对策略不是对抗而是规范6.1 放慢节奏比什么技巧都管用音乐榜单数据更新的频率本质上是小时级的你根本不需要在一分钟内抓完所有内容。给自己定个规矩每个请求间隔至少2秒全部榜单跑完控制在几分钟内。这个频率对大多数平台来说完全友好也远低于触发限流的阈值。6.2 随机延时与Time-Out固定的间隔时间更容易被识别可以加一点随机性import random time.sleep(2 random.uniform(0, 2))另外每个请求都要设置超时时间防止一个慢请求拖住整个脚本。6.3 遵守robots协议与平台条款学习项目中爬取公开榜单数据用于个人分析在大多数场景下是可以接受的。但如果要大规模采集或商用请务必先查看目标平台的服务条款和数据规范必要时联系平台获取授权。6.4 不要爬取需要登录才能访问的数据需要登录才能看到的榜单明细意味着数据本身就不适合公开抓取。如果学习场景需要练习“带Cookie的请求”建议自己搭一个测试站点或者用本地假数据来模拟不要拿真实平台做实验。7. 扩展方向从“爬榜单”到“做分析”爬到数据只是第一步把数据用起来才是真正的价值点。这里给出几个我验证过的扩展方向榜单变化趋势追踪每天记录榜单算出每首歌排名的升降幅度找出连续上涨的“潜力股”和连续下跌的“掉榜王”。歌手热度对比同一个歌手有多首歌在榜时可以聚合计算出歌手的总热度指数对比不同歌手的走势。新歌上榜速度分析结合歌曲发行时间统计一首新歌从发布到进入榜单花了多久哪些歌是“空降冠军”。定时报告推送把每日榜单变化生成简短的文字摘要通过企业微信或钉钉机器人推送到群里方便团队每天看数据。可视化大屏把榜单数据做成动态柱状图或排序动画观察歌曲位次的实时变化趣味性强而且展示效果好。这些方向在每个榜单数据量都不大的情况下用pandas加matplotlib或者Plotly就能实现不需要上重型数据框架。关键是先把数据采集做规范后面分析才有得玩。我在实际项目中做得最多的扩展其实是“榜单变化播报”每天上午定时跑一次爬虫用SQL对比昨天和今天的排名生成一条类似“歌曲《xxx》上升了5位进入前十”的消息推送出来。这个功能看着不起眼但来自动化运维监控的经验就是——排行榜这种高频变化的数据最大的价值是趋势不是快照。数据攒起来之后时间会帮你说话。8. 写在最后的几点实操心得排行榜爬虫这个项目技术难度不算高但很能锻炼工程思维。它逼着你从“单次能跑”到“长期稳定跑”去思考问题比如怎么控制频率、怎么做异常重试、怎么去重、怎么记录日志。这些能力是通用的做完这个项目直接迁移到其他数据采集场景也不费力。如果你是在校生或刚入门的开发者建议照着我上面的思路从最简单的单页抓取开始逐步加上定时调度、数据库存储、趋势分析这些模块每加一个模块就重写一次代码直到你觉得每个环节都顺手了这个项目就算真正吃透了。最后再分享一个细节代码里所有关于榜单类型的常量比如榜单ID、榜单名称、接口URL模板都放到配置文件或代码顶部的常量区不要散落在函数里。等到你想切换另一个榜单跑的时候直接改配置就能完成不用动核心逻辑。这个习惯我坚持了很多年每次回头维护老项目时都庆幸当时这么做了。
RELATED

相关推荐

林伽一 · AI科技日报 |出口管制十天两反转、纯CPU超算登顶、AI编程降本35%:用TaoToken统一Key复盘AI编程降本路径

林伽一 · AI科技日报 |出口管制十天两反转、纯CPU超算登顶、AI编程降本35%:用TaoToken统一Key复盘AI编程降本路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/12 5:17:40
PDF自动添加书签-在线工具

PDF自动添加书签-在线工具

PDF自动添加书签在线工具

📅 2026/10/12 5:17:40
本地缓存选型:Guava Cache、Caffeine 与 Cache2k

本地缓存选型:Guava Cache、Caffeine 与 Cache2k

本地缓存选型:Guava Cache、Caffeine 与 Cache2k 摘要:配置表、玩家数据、会话状态,游戏服里到处要用本地缓存。候选绕来绕去就三个:Guava Cache、Caffeine、Cache2k。这篇把三者的真实差异讲清楚,用一个"Loading…

📅 2026/10/12 5:17:40
MORE NEWS

更多资讯

📰

STM32 | CLion + ST-Link下载调试完整流程

一、下载程序 先创建一个文件夹: 命名:stlink.cfg 写入以下代码: # choose st-link/j-link/dap-link etc. #adapter driver cmsis-dap #transport select swdsource [find interface/stlink.cfg]transport select hla_swdsource [find target/stm32f4x.…

📰

Python代码打包成exe文件详解

一、pyhon代码打包成exe文件1-1:安装打包工具在PyCharm底部的 终端(Terminal) 里输入:pip install pyinstaller1-2:输入打包命令在同一个终端里输入(直接复制):pyinstaller --onefile --noconsole --hidden…

📰

知识工作插件化:从信息捕获到配置同步的效率体系

平时做知识工作,最耗时间的往往不是思考本身,而是信息的搬运。你从网页摘一段话,粘贴进笔记里,格式全乱;你复制了一段关键论述,过了几天想找来源,翻遍聊天记录和文档都找不到;你给十…

📰

LangChain MultiVectorRetriever:一个文档存多个向量

个人主页&#xff1a;> for_ever_love__ <&#xff08;欢迎各位大佬莅临&#x1f60a;&#xff09; 其他栏目: > 大模型开发从0到1 < 其他栏目: > iOS项目总结大全 < 其他栏目: > 我想学python了 < 其他栏目: > iOS UI < 文章目录LangChain Mult…

📰

LangChain SelfQueryRetriever:让模型自己写过滤条件

个人主页&#xff1a;> for_ever_love__ <&#xff08;欢迎各位大佬莅临&#x1f60a;&#xff09; 其他栏目: > 大模型开发从0到1 < 其他栏目: > iOS项目总结大全 < 其他栏目: > 我想学python了 < 其他栏目: > iOS UI < 文章目录LangChain Self…

📰

Scratch图形化四级真题拆解:从执行思维到算法思维的分水岭

考完Scratch图形化四级&#xff0c;我带的几个孩子出来以后表情都很微妙——不是难到崩溃&#xff0c;而是“感觉都会&#xff0c;但有一两题心里没底”。这种状态其实比“完全不会”更值得警惕&#xff0c;因为它说明四级开始真正考察算法思维&#xff0c;而不是单纯的操作熟练…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬