前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >酷狗音乐爬虫

酷狗音乐爬虫

作者头像
caoayu
修改2023-09-24 19:10:58
1.2K0
修改2023-09-24 19:10:58
举报
文章被收录于专栏:caoayu的分享caoayu的分享

music

最近很少用 deepin 在线或者使用客户段听音乐了,喜欢下载到本地听那些熟悉的歌曲。

很多歌不是这个平台没版权就是那个要付费。也是顾虑到网易云9级用户的面子,不经常去其他平台听歌,在 GitHub 上有个项目,项目地址:https://github.com/nondanee/UnblockNeteaseMusic。可以只使用网易云的客户端听大部分平台的音乐,对于没有版权的歌曲会使用其他平台的 api 来播放。用着总算有个解决方案了。但是在 linux 客户端上,网易云程序没有设置代理的功能,而linux 上又要弄证书什么的,一个客户端就懒的折腾了,主要是折腾了几天没有很好的解决方案,就一直搁置了。

也是经常使用 you-get 的缘故,会经常把电影或视频下载下来,同时也支持很多国内视频与音乐平台,you-get 项目地址:https://github.com/soimort/you-get

you-get 使用起来也比较简单,将链接放进去就好了,但是国内如果不使用代理,速度十分的慢。关于代理的使用

代码语言:javascript
复制
you-get -x 127.0.0.1:7890 'https://www.youtube.com/watch?v=jNQXAC9IVRw'

对于视频来说每次找到一个视频,复制链接,下载。还算可以接受,但是对于音乐,只有短短的几分钟,每次要下新的歌曲都要进行打开浏览器搜索,复制链接。干脆自己写一个程序。

由于是打算做命令行程序,就是用 Go 来写吧,一个小程序,就不使用 go mod 来做了,直接一个 main 搞定。此项目地址:https://github.com/ayuayue/kugou

本来打算通过命令行来查询歌曲,返回歌曲的链接,然后配合 you-get 来进行下载,这样就多了一步,类似于使用管道符的方式。

又打算直接通过 go 来调用 you-get 来下载,但是这样前提需要安装 you-get 并且代理不好在程序中配置,只好配置临时或全局的终端代理。

最后打算直接在程序中完成歌曲的搜索,歌词及歌曲下载。这样就不依赖于外部的东西。

对于歌曲下载api 的获取,使用 you-get 是通过 -d 参数,开启调试。会显示出请求的地址以及音乐的地址,由此可以的到歌曲详情的 api

Api

  1. 查询歌曲 http://msearchcdn.kugou.com/api/v3/search/song eg: http://msearchcdn.kugou.com/api/v3/search/song?keyword=花海 参数 值类型 keyword 字符串
  2. 歌曲详情 https://www.kugou.com/yy/index.php?r=play/getdata eg: https://www.kugou.com/yy/index.php?r=play/getdata?hash=xxxx&album_id=xxx&mid=123 参数 值类型 hash 字符串 album_id 字符串 mid 123

有了这两个 API 剩下的就简单了。

开始编码

代码语言:javascript
复制
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
)

type Req struct {
	Status  int    `json:"status"`
	Error   string `json:"error"`
	Data    Data   `json:"data"`
	Errcode int    `json:"errcode"`
}
type Data struct {
	Info []Info `json:"info"`
}
type Info struct {
	Hash       string `json:"hash"`
	AlbumID    string `json:"album_id"`
	SingerName string `josn:"singername"`
	SongName   string `json:"songname"`
}
type Song struct {
	Status  int      `json:"status"`
	ErrCode int      `json:"err_code"`
	Data    SongData `json:"data"`
}
type SongData struct {
	AudioName string `json:"audio_name"`
	Lyrics    string `json:"lyrics"`
	PlayURL   string `json:"play_url"`
}

var SearchApi = "http://msearchcdn.kugou.com/api/v3/search/song"
var SongApi = "https://www.kugou.com/yy/index.php?r=play"

func query() Req {
	var name string
	flag.StringVar(&name, "name", "", "歌曲名")
	flag.Parse()
	//fmt.Println(name)
	client, err := http.NewRequest(http.MethodGet, SearchApi, nil)

	if err != nil {
		panic("请求失败")
	}
	params := make(url.Values)
	params.Add("keyword", name)
	client.URL.RawQuery = params.Encode()
	//fmt.Println(client)
	req, err := http.DefaultClient.Do(client)

	defer func() {
		req.Body.Close()
	}()
	if req.StatusCode != 200 {
		panic("返回错误响应")
	}
	body, _ := ioutil.ReadAll(req.Body)
	r := Req{}
	json.Unmarshal(body, &r)
	//fmt.Printf("%#v",r)
	return r
}

func (r *Req) List() {
	if r.Status != 1 {
		panic(r.Error)
	}
	songs := r.Data.Info
	for k, song := range songs {
		fmt.Println(k+1, song.SongName, "--", song.SingerName)
	}
}
func (r *Req) GetLink(num int) []string {
	songApi := "https://www.kugou.com/song"
	songs := r.Data.Info
	hash := songs[num-1].Hash
	album_id := songs[num-1].AlbumID
	fmt.Printf("在线播放链接:%s/#hash=%s&album_id=%s\n", songApi, hash, album_id)
	return []string{
		hash, album_id,
	}
}
func (s *Song) Download() {
	if s.Status != 1 {
		panic("获取歌曲信息失败")
	}
	lyrics := s.Data.Lyrics
	fmt.Println("开始下载歌词")
	lrcFileName := fmt.Sprintf("%s.lrc", s.Data.AudioName)
	songName := fmt.Sprintf("%s.mp3", s.Data.AudioName)
	lf, err := os.Create(lrcFileName)
	if err != nil {
		panic(err)
	}
	defer func() { _ = lf.Close() }()
	_, err = lf.Write([]byte(lyrics))
	if err != nil {
		panic(err)
	}
	fmt.Println("下载歌词完成")
	fmt.Println("开始下载歌曲")
	req, err := http.Get(s.Data.PlayURL)
	if err != nil {
		panic("请求失败")
	}
	defer func() {
		req.Body.Close()
	}()
	if req.StatusCode != 200 {
		panic("返回错误响应")
	}
	sf, err := os.Create(songName)
	if err != nil {
		panic(err)
	}
	defer func() { _ = sf.Close() }()
	_, err = io.Copy(sf, req.Body)
	if err != nil {
		panic(err)
	}
}
func main() {
	var num int
	req := query()
	req.List()
	fmt.Println("请输入要选择的歌曲链接的序号:")
	fmt.Scanln(&num)
	params := req.GetLink(num)
	song := GetSong(params)
	song.Download()
}
func GetSong(params []string) Song {
	url := fmt.Sprintf("%s/getdata&hash=%s&album_id=%s&mid=123", SongApi, params[0], params[1])
	req, err := http.Get(url)
	if err != nil {
		panic("请求失败")
	}
	defer func() {
		req.Body.Close()
	}()
	if req.StatusCode != 200 {
		panic("返回错误响应")
	}
	body, _ := ioutil.ReadAll(req.Body)
	song := Song{}
	json.Unmarshal(body, &song)
	return song
}

编译(我本地是 linux 环境)

代码语言:javascript
复制
# linux
go build -o path ./main.go #path 路径
# windows 
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o path main.go
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-02-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • music
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档