扫描"豆瓣音乐"所有专辑的简单Python脚本

我需要一些音乐数据,而 豆瓣音乐 上相关数据是非常齐全的。

即使是十分小众、鲜有人听过的专辑,豆瓣也提供了较为详细的描述。

摆在我面前的第一个问题是,如何将豆瓣音乐上的专辑一网打尽,一个不遗漏地抓取到。

我们观察某个专辑的页面: http://music.douban.com/subject/1415369/

看到subject后跟着一串数字ID,这时候一个简单的思路已经出来了:

将id从1不断递增,扫描完所有的ID,检查哪些ID是存在的

又观察到大多数专辑页面上存在相关推荐,也就是那个“喜欢某某专辑的人也喜欢… …”。

这里存在一对N的超链接映射,最终形成了网络,于是可以有第二个思路:

将某个专辑加入队列,从它出发,通过 “也喜欢” 来获取新专辑,并将这些新专辑加入队尾

每完成一次操作,就从队列中删除队首的专辑

循环上面的过程,直到处理完队列中的所有元素

最终获取到的就是包含第一个元素的网

当然,上面的思路是有缺陷的,那些孤立的专辑无法被包括进来。

我决定使用ID自增的方式来扫专辑。

在python中,直接使用urllib2.urlopen去下载完整的HTML页面是不太经济的,

特别是一开始我并不需要解析HTML,我只是想知道这个页面是否存在。可以使用head请求。

我还观察到直接访问www.douban.com/subject/id可能会产生一个302的重定向,或者404错误

比如访问 http://www.douban.com/subject/1415369/, 会302重定向到

http://music.douban.com/subject/1415369/

于是我可以通过请求www.douban.com/subject/id/来确定对应ID是否是一个音乐专辑的ID

302还可能是重定向到其他douban.com二级域名,比如book、movie,但我只需要music,其他的直接忽略了。

(获取豆瓣所有的电影和图书也很方便,不是吗?)

MySQL下创建表album:

CREATE TABLE `album` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`album_url` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_album_id` (`album_url`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

它包括id字段和album_url字段,但album_url是int,并非varchar,因为我只需要保存数字id。

完整的源代码,请参考:  https://github.com/lijiejie/scan-douban-ids

这里有一点小的技巧:

  1. headers伪装成了goolebot,减小IP被屏蔽的几率
  2. id从1扫描到3000万,这是个估值上界,通过查看豆瓣最近收录的新专辑判断
  3. 同步队列id_queue最大的长度是100,不要忽略了参数,设置成无限长度,3000万太多
  4. 这里有50个线程同时工作,但是数据库连接dbconn是全局的、公用的,使用锁lock来确保每次只有一个线程进入
  5. 在id_queue中加入了50个None,作为结束标志
  6. 可以直接HEAD请求music.douban.com的页面判断是否存在,404表示这个id不存在、302表示这个id是其他内容而不是音乐,只有status返回200才表示对应的专辑存在

使用上面的脚本,从昨晚运行到现在,我已经扫描到了70万个专辑。 🙂

《扫描"豆瓣音乐"所有专辑的简单Python脚本》上有29条评论

    1. 最近几天在准备做一个音乐资源方面的网站。 可以用爬虫去爬几十万个专辑下来,版权是个问题。所以最终是否提供打包下载功能,我还在权衡。

  1. 加锁是一个瓶颈,多线程50个也是一个瓶颈,我觉得使用无锁数据结构,加上内存缓存,以及,client端按照事件驱动的方式进行设计性能会非常好,几个核就起几个进程。进程之间独立,将搜索的数据区间分段到每个独立绑定到核上的进程。

    1. 膜拜搞后台开发的大牛。。。 算法和设计模式方面,我确实非常欠缺。 Python的多线程好像确实不能充分利用多核。

        1. 是的,我自己感觉甚至网络都难以成为瓶颈。我这边12M的ADSL,跑满了可以达到1.4M/s左右。数据库操作确实会成为瓶颈,如果得不到好的优化。其实前几天我也正想向你求助MySQL的优化。有一个表album目前已经有超过100万条记录,表的大小也接近1GB了。有机会了向你求教一下。

          1. 目前我们有很多数据库都超过100w记录,变动大的数据和变动小的基本上都分离开来,优化索引足够小常驻内存。超过1亿条记录的基本不怎么建索引,只做顺序读取。

      1. 对的啊!现在问题是我把路径修改到我电脑里安装的云盘客户端位置,只能打开!点击注册没反因阿~不知道是不是保存在哪了?

          1. 这个程序时间有点长了,没有更新维护过,恐怕是已经失效了。再者现在360云盘似乎是可以免费增加到36TB的,应该不需要注册那么多了。

发表评论

您的电子邮箱地址不会被公开。