使用scrapy+scrapy-splash爬取网易云音乐歌单
867 字
4 分钟
使用scrapy+scrapy-splash爬取网易云音乐歌单
这是 2018 年写的旧文。网易云音乐的页面和接口此后变化很大,文中的选择器和地址大概率已经失效,这里只作为 Scrapy + Splash 抓取动态页面的思路参考。

创建项目
scrapy startproject music163Scrapycd music163Scrapyscrapy genspider Music163 163.com文件目录如下:

Items.py
生成项目目录之后就可以开始编写代码啦,首先修改items.py,定义我们爬取网页后收集的字段。
import scrapy
class Scrapymusic163Item(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() # 标题 link = scrapy.Field() # 链接 realLink=scrapy.Field() #完整连接 desc = scrapy.Field() # 简述 listenCount = scrapy.Field() #播放数量 posttime = scrapy.Field() # 发布时间 imgUrl=scrapy.Field() # 歌单封面图片url # passMusic163Spider
class Music163Spider(scrapy.Spider):
name = "music163" allowed_domains = ["163.com"] start_urls = [ "https://music.163.com/discover/playlist/?order=new", "https://music.163.com/#/discover/playlist/"
] def parse(self, response): for url in self.start_urls: yield SplashRequest(url=url, callback=self.parseRequest,endpoint='render.json', args={'wait': 1,'html':1,'iframes': 1,'script':1})
def parseRequest(self,response): iframe_html = response.data['childFrames'][0]['html'] sel = parsel.Selector(iframe_html) # for se in sel.xpath('//div[@class="n-rcmd"]/div[@class="v-hd2"]/div[@class="tab"]/a'): for se in sel.xpath("//div[@id='cateListBox']/div[@class='bd']//a")[1:]: item = Scrapymusic163Item() item['title'] = se.xpath('text()')[0].extract() item['link'] = se.xpath('@href')[0].extract() url = response.urljoin(item['link']) yield SplashRequest(url,self.parse_gedan,endpoint='render.json', args={'wait': 2,'html':1,'iframes': 1,'script':1}) def parse_gedan(self, response): iframe_html = response.data['childFrames'][0]['html'] sel = parsel.Selector(iframe_html) for se in sel.xpath('//ul[@id="m-pl-container"]/li'): item = Scrapymusic163Item() item['title'] = se.xpath('p[@class="dec"]/a/text()')[0].extract() item['link'] = se.xpath('p[@class="dec"]/a/@href')[0].extract() url=response.urljoin(item['link']) item['realLink']=url item['listenCount']=se.xpath('div/div/span[@class="nb"]/text()')[0].extract() if(item['listenCount'] and "万" in item['listenCount']): item['listenCount']=int(item['listenCount'].replace("万","0000")) item['listenCount']=int(item['listenCount']) item['imgUrl']=se.xpath('div/img[@class="j-flag"]/@src')[0].extract() yield item next_pages = sel.xpath('//a[@class="zbtn znxt"]')
if next_pages: url = response.urljoin(next_pages.xpath('@href')[0].extract()) yield SplashRequest(url,self.parse_gedan,endpoint='render.json', args={'wait': 2,'html':1,'iframes': 1,'script':1})if __name__ == '__main__': pass上边这段代码是爬取歌单的关键。这里首先说下爬取的思路,打开网易云的网站,找到歌单连接,歌单分为热门和最新两种,每种又根据风格分为72小类,思路就是先爬取所有种类的连接

再打开每类歌单的网页

从上面的图片中,我们可以看到每首歌的标题,连接,收听次数等信息。
scrapy-splash
由于网易云的连接嵌套了动态链接的iframe,这里使用了scrapy-splash来动态渲染iframe,相当于让scrapy-splash来执行网页中的js,并将渲染结果返给我们,这样我们就可以继续使用xpath来筛选自己感兴趣的内容了。
docker 部署scrapy-splash
docker pull scrapinghub/splash
docker run -p 8050:8050 scrapinghub/splash配置
vim setting.py#SPLASH SERVERSPLASH_URL = 'http://127.0.0.1:8050/render.json'
DOWNLOADER_MIDDLEWARES = { 'scrapy_splash.SplashCookiesMiddleware': 723, 'scrapy_splash.SplashMiddleware': 725, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,}
SPIDER_MIDDLEWARES = { 'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,}
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'详细参见scrapy-splash文档
需要注意的是在使用scrapy-splash时需要用SplashRequest来代替scrapy原始的request,这是scrapy-splash对scrapy的request进行了进一步的封装,支持了更多的参数,同时也支持将request的返回配置为不同的格式,如html,json等。这里使用了json返回。
mongodb
ITEM_PIPELINES = { "scrapy_mongodb.MongoDBPipeline":900}
MONGODB_URI = 'mongodb://root:'+urllib.parse.quote('MyNewPass+@321')+'@localhost:27017'MONGODB_DATABASE = 'scrapy'# MONGODB_COLLECTION = 'my_items'# 连接不重复,避免重复爬取MONGODB_UNIQUE_KEY = 'realLink'
MONGODB_SEPARATE_COLLECTIONS = True爬取结果

共爬取了15万左右的歌单。下面是播放次数最多的五个歌单
/* 1 */{ "_id" : ObjectId("5aea7a036d5b76bf8d42659d"), "title" : "华语速爆新歌", "link" : "/playlist?id=924680166", "realLink" : "https://music.163.com/playlist?id=924680166", "listenCount" : 152900000, "imgUrl" : "http://p1.music.126.net/Zcv4NgK5T0bd1yMzAFp8Iw==/109951163276364917.jpg?param=140y140"}
/* 2 */{ "_id" : ObjectId("5aea78a56d5b76bf8d422179"), "title" : "【节奏控】那些超带感的音乐(典藏版)", "link" : "/playlist?id=306397077", "realLink" : "https://music.163.com/playlist?id=306397077", "listenCount" : 140930000, "imgUrl" : "http://p1.music.126.net/RnOZHM0BNxXuy-RwQQI5BA==/3313928048221849.jpg?param=140y140"}
/* 3 */{ "_id" : ObjectId("5aea7fd16d5b76bf8d43b0db"), "title" : "【旋律控】超级好听的外文歌", "link" : "/playlist?id=310970433", "realLink" : "https://music.163.com/playlist?id=310970433", "listenCount" : 101740000, "imgUrl" : "http://p1.music.126.net/2MsstS-M9w5-li0aRy3sUQ==/1380986606815861.jpg?param=140y140"}
/* 4 */{ "_id" : ObjectId("5aea95f76d5b76bf8d46289a"), "title" : "那些只听前奏就中毒的英文歌", "link" : "/playlist?id=37432514", "realLink" : "https://music.163.com/playlist?id=37432514", "listenCount" : 95420000, "imgUrl" : "http://p1.music.126.net/mQy3lRj6YJ0TW3fM9v85YA==/6643249256145165.jpg?param=140y140"}
/* 5 */{ "_id" : ObjectId("5aea789a6d5b76bf8d42194c"), "title" : "【欧美男团】秒杀耳朵系列", "link" : "/playlist?id=117377955", "realLink" : "https://music.163.com/playlist?id=117377955", "listenCount" : 71150000, "imgUrl" : "http://p1.music.126.net/FJAxNkFoq3dGiS9tz_bGgQ==/3405187512421439.jpg?param=140y140"}github地址
参考
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
使用scrapy+scrapy-splash爬取网易云音乐歌单
https://tracerzzz.cn/posts/scrapy-netease-music-playlist/相关文章智能推荐
1
一家多诊室的医院:用类比理解 Go 的 GMP 调度
Go用"医院看病"的类比讲清楚 Go 的 GMP 调度:G、M、P、全局队列、偷任务、抢占、系统调用、netpoller 和 sysmon 各自做什么,顺带回顾用户态和内核态,对比 Python asyncio、Node.js 和 Go 的调度分层,最后用两个小程序亲眼看看调度器在干什么。
2
让 Mac 和 iPhone 指定网站走 eSIM:sing-box 分流实录
工具家里 Wi-Fi 访问一部分境外网站不稳定,iPhone 上的境外 eSIM 访问正常但流量很少。这篇记录怎么让 Mac(通过手机热点)和 iPhone 自己都只把指定网站分给 eSIM,其他流量照常走 Wi-Fi。最后两台设备共用一份 sing-box 配置,用 iCloud 同步,规则全部来自社区规则集,基本不用手动维护。附完整配置、一路补过的漏洞和换设备时的快速清单。
3
给 2016 款 MacBook Pro 装上 macOS Sonoma:OpenCore Legacy Patcher 实录
工具家里有一台 2016 款 15 英寸 MacBook Pro,官方最高只能升到 macOS 12,装不了要求 macOS 13 以上的新软件。用 OpenCore Legacy Patcher 把它升到了 Sonoma 14,这篇记录选版本的考虑、安装步骤,以及装完后遇到的屏幕闪烁、Wi-Fi 消失、指纹失效、iCloud 退不出去、睡眠唤醒死机这些坑。
4
让医生别闲着:用 Python 协程把成本数据产出提速十倍
工作在百度云 CDN 做成本分摊时,日均要对 Palo 发 80 万次以上的查询,大部分时间都花在等结果上。这篇用"医院看病"做类比讲清楚异步非阻塞,顺带对比多进程、多线程、协程三种并发方式,最后讲我先用单进程协程(asyncio + aiomysql)并发查询,再加上多进程、用队列汇总结果,把数据产出时间缩短到原来的十分之一的过程;最后对比浏览器、Node.js 和 Python asyncio 的事件循环调度原理。
5
CDN 新客户接入前的价格测算:用波形拟合算出最低成本价
工作火山 CDN 经营分析平台上的价格测算功能:销售拿到一个新客户的带宽打点,平台把它和大盘拟合,判断客户是否错峰、算出边际超卖倍数,再结合资源诉求的加权成本和包头系数,给出不同计费方式下的最低成本价。这篇讲它的输入、计算过程、示例和后续的优化方向。
随机文章随机推荐




