【Python】豆瓣FM API分析

Python 专栏收录该内容
81 篇文章 2 订阅

原文地址

原理

  • 豆瓣并没有开放 douban.fm 的API
  • 以下的分析只是通过抓包,并结合网上前人的研究,猜测参数的作用
  • 通过python的requests模块来测试
  • 根据Arguments构造传入参数结构体,发送http请求
  • 获取到的是json数据,用json.loads()转成字典进行操作

登录接口

使用 douban.fm 并不需要使用豆瓣的 OAuth 认证,只需要简单地把用户名密码 POST 过去,并保存 Token 和 Expire 即可。

URL: http://www.douban.com/j/app/login

Method: POST

Arguments:

  • app_name: radio_desktop_win

  • version: 100

  • email: 用户帐号

  • password: 明文密码

Header: Content-Type: application/x-www-form-urlencoded

Response ( application/json )

测试使用(发送http请求,获取对应url):
- 根据Arguments构造参数结构体,以Method的方式发送请求到URL
- 返回结果的text中存放着登录参数

#-*- coding: utf-8 -*-
import requests
import urllib
import json

# 构造Arguments中的传入参数结构体
login_data = {
                'app_name': 'radio_desktop_win',
                'version': '100',
                'email': '243027571@qq.com',
                'password': 'xxxxxxxx'
             }

# 这里的Method是Post,则将结构体传入,按照Post方式发送
user_data = requests.post('http://www.douban.com/j/app/login',login_data)
udata = json.loads(user_data.text)

user_id = udata['user_id']
expire = udata['expire']
token = udata['token']

# 定义获取歌曲列表结构体
song_list = {
                'app_name': 'radio_desktop_win',
                'version': '100',
                'user_id' : user_id,
                'expire' : expire,
                'token': token,
                'type' : 'n',
                'channel' : 0,
            }

# 获取歌曲列表
url = 'http://www.douban.com/j/app/radio/people?' + urllib.urlencode(song_list)
song = requests.get(url)
s = json.loads(song.text)
print s['song'][0]
print s['song'][0]['title']


登录成功(r的值为0)

{
    "user_id": "<user_id>",
    "err": "ok",
    "token": "<token_string>",
    "expire": "<expire_time_in_millisecond>",
    "r": 0,
    "user_name": "xxx",
    "email": "<user_account>"
}

登录失败(r为1,err会给出错误原因)

{
    "r": 1,
    "err": "wrong_password"
}

在获得user_id,token和expire后,保存起来,在使用获取歌曲列表、红心等API时,把它们放到请求参数中即可

获取频道列表

这个接口获取的频道列表是一个比较固定的列表,并非douban.fm网页版上那么多样的列表。网页版的频道列表是直接服务器生成在HTML里面的,无法直接获得(可使用爬虫),但它的channel_id可以用,如有兴趣可把这些channel_id收集起来。

{
    "channels": [
        {
            "name": "私人兆赫",
            "seq_id": 0,
            "abbr_en": "My",
            "channel_id": 0,
            "name_en": "Personal Radio"
        },
        {
            "name": "华语",
            "seq_id": 1,
            "abbr_en": "CH",
            "channel_id": 1,
            "name_en": "Chinese"
        },
        {
            "name": "欧美",
            "seq_id": 2,
            "abbr_en": "EN",
            "channel_id": 2,
            "name_en": "Euro-American"
        },
        ...
}

如上可看出,有频道名,有channel_id,这个id用于请求相应的歌曲列表。seq_id只是一个简单的列表排序index,可忽略

获取歌曲列表

歌曲列表的获取最为复杂,其参数也比较多

所有的这些都会返回一个json字符串,其中都会包括歌曲列表(上面得到的歌曲URL,只会在一定时间内有效,过期之后就不能再访问了,因此猜测每次访问都返回一些歌曲就是想更新一下后面的曲库,因为当前这首不能播了,很可能后面的也不能播)。

r若为1即出错,err里面会写上出错原因,而r为0即调用成功。
其中的歌曲列表格式是

{
    "r": 0,
    "version_max": 100,
    "song": [
        {
            "album": "/subject/5952615/",
            "picture": "http://img3.douban.com/mpic/s4616653.jpg",
            "ssid": "e1b2",
            "artist": "Bruno Mars / B.o.B",
            "url": "http://mr3.douban.com/201308250247/4a3de2e8016b5d659821ec76e6a2f35d/view/song/small/p1562725.mp3",
            "company": "EMI",
            "title": "Nothin' On You",
            "rating_avg": 4.04017,
            "length": 267,
            "subtype": "",
            "public_time": "2011",
            "sid": "1562725",
            "aid": "5952615",
            "sha256": "2422b6fa22611a7858060fd9c238e679626b3173bb0d161258b4175d69f17473",
            "kbps": "64",
            "albumtitle": "2011 Grammy Nominees",
            "like": 1
        },
        ...
    }
}

参数都可以直接从名字看出其意义
- album 专辑跳转地址
- picture 专辑图片地址
- ssid 未知
- artist 艺术家
- url 歌曲的URL
- company 唱片公司
- title 歌曲名
- rating_avg 平均分数
- length 长度
- subtype 子类型(有些广告的字类型会是T)
- public_time 出版年份
- sid 歌曲id
- aid 专辑id
- kbps 码率
- albumtitle 专辑名
- like 是否已喜欢,0为false,1为true

获取歌曲URL后调用相应播放器播放,如mplayer

#!/usr/bin/python
import requests
import urllib
import json
import subprocess

login_data = {
                'app_name': 'radio_desktop_win',
                'version': '100',
                'email': '243027571@qq.com',
                'password': 'xxxxxxx'
             }


user_data = requests.post('http://www.douban.com/j/app/login',login_data)
udata = json.loads(user_data.text)

user_id = udata['user_id']
expire = udata['expire']
token = udata['token']


song_list = {
                'app_name': 'radio_desktop_win',
                'version': '100',
                'user_id' : user_id,
                'expire' : expire,
                'token': token,
                'type' : 'n',
                'channel' : 0,
            }

url = 'http://www.douban.com/j/app/radio/people?' + urllib.urlencode(song_list)
song = requests.get(url)
songlist = json.loads(song.text)

for sdata in songlist['song']:
    surl = sdata['url']
    subprocess.call(["mplayer",surl], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值