Baidu音乐歌曲爬虫:

1、分析Baidu音乐歌曲下载接口,组装参数

2、判断是否需要登录

  a、使用cookie

  b、使用selenium

3、歌曲信息页面分析

4、数据表设计

歌曲类型表

歌曲表

表都无所谓,自己设计就行。

-------------------------------

# -*- coding: utf-8 -*-
'''
***
_author_= "fengshaungzi"
_time_='2018-4-10'
_python_version_ = 'python2.7'
_script_type_ = 'spider'
url = 'http://music.baidu.com/tag/类型?start=0&size=20&third_type=0'
***
'''
from os import path
from bs4 import BeautifulSoup
import urllib,urllib2,requests,cookielib
import sys,time,datetime
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import pymysql,shutil
import sys,os
reload(sys)
sys.setdefaultencoding('utf-8')
d = path.dirname(__file__) class BadiuMusicSpider():
def __init__(self):
pass
def login(self,cursor,type_id,type_q):
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome()
driver.maximize_window()
driver.get("http://i.baidu.com/welcome/")
time.sleep(5)
driver.find_element_by_xpath('/html/body/header/div/div/a[2]').click()
time.sleep(2)
driver.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__userName"]').clear()
driver.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__userName"]').send_keys('用户')
time.sleep(2)
driver.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__password"]').clear()
driver.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__password"]').send_keys('密码')
##如果有验证码
time.sleep(3)
try:
driver.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__verifyCodeChange"]').click()
input = raw_input(u'请输入验证码:')
code = driver.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__verifyCode"]')
code.clear()
code.send_keys(input)
except:
print u'没有验证码。'
driver.find_element_by_xpath('//*[@id="TANGRAM__PSP_10__submit"]').submit()
time.sleep(2)
self.parse_html(driver,cursor,type_id,type_q)
def parse_html(self,driver,cursor,type_id,type_q,page=1,): #response = urllib2.urlopen(url).read()
#response = opener.open(urllib2.Request(url, headers=headers))
#response = response.read()
#response = requests.get(url, headers=headers, cookies=cookies).content
#response = opener.open(urllib2.Request(url, headers=headers))
#response = response.read() start = (page-1)*20
print u'---开始获取第{0}页的数据----'.format(page)
url = 'http://music.baidu.com/tag/{0}?start={1}&size=20&third_type=0'.format(type_q,start)
driver.get(url)
time.sleep(2)
response = driver.page_source
obj = BeautifulSoup(response, 'html.parser')
##获取歌曲m_url
span_list = obj.find_all('span',{"class":"song-title"})
## 判断下是否有下一页
try:
driver.find_element_by_class_name('page-navigator-next')
next_page = 1
except:
next_page = 0
#try:
for v in span_list:
list = []
try:
m_url = v.find('a')['href']
except:
continue
###获取song_id
song_id = m_url.replace('/song/', '')
##组装下url头部
m_url = 'http://music.baidu.com{0}'.format(m_url)
###开始获取歌曲信息
data = self.save_music_info(m_url,type_id)
### 判断data['check']==0,说明歌曲已经存在跳出这次循环
if data.has_key('check'):
print u'---该歌曲已经存在---'
continue
singer_path = u"G:\\www\\music2\\"+data['singer']
###歌曲信息获取完毕开始下载歌曲 需要song_id
music_lrc = self.save_music_lrc(driver,song_id,singer_path)
if music_lrc.has_key('words') and music_lrc['words'] =='暂无':
data['words'] =''
else:
print u"歌词:"+music_lrc['lrc_name']
data['words'] = u'music2/LRC/'+music_lrc['lrc_name']
data['filepath'] = u'music2/{0}/{1}.mp3'.format(data['singer'],data['name'])
## 设置id的值
cursor.execute('select id from network_music order by cast(id as SIGNED INTEGER) desc limit 0,1')
old_id = cursor.fetchone()
if old_id:
id_n = str(int(old_id[0]) + 1)
else:
id_n = str(1)
# 进入数据库
list = [(id_n,data['name'],data['singer'],data['album'],data['publishtime'],data['publishcompany'],data['composer'],data['lyrics'], \
data['filesize'],data['filetime'],data['userhead'],data['types'],data['status'],data['words'],data['filepath'])]
#xprint list
self.save_db(cursor,list)
'''
except:
## 记入log
try:
datetime_now = datetime.datetime.now()
datetime_str = '{0}-{1}-{2} {3}:{4}:{5}'.format(datetime_now.year,datetime_now.month,datetime_now.day,datetime_now.hour,datetime_now.minute,datetime_now.second)
effect_row = cursor.executemany("insert into music_log(page,datetime)values(%s,%s)",[(page,datetime_str)])
## 提交,不然无法保存新建或者修改的数据
conn.commit()
except:
print 'Add log fault!'
'''
page = page + 1
#input = raw_input('输入任意值继续执行:')
if next_page==1:
print u'------开始获取下一页的数据----'
self.parse_html(driver,cursor,type_id,type_q,page=page)
else:
print u"-----爬虫程序即将结束-----"
cursor.close()
conn.close() def save_music_info(self,m_url,type_id):
data = {}
music_info_response = urllib2.urlopen(m_url).read()
music_info_obj = BeautifulSoup(music_info_response, 'html.parser')
##获取歌曲信息 name singer alnum pubdate pic tag company
name = music_info_obj.find('span',{"class":"name"}).text.strip()
name = name.replace('"','')
name = name.replace("'",'')
singer = music_info_obj.find('span',{"class":"artist"}).find('a').text.strip()
singer = singer.replace('"', '')
singer = singer.replace("'", '')
if os.path.exists("G:\\www\\music2\\"+singer) == False:
os.mkdir("G:\\www\\music2\\"+singer)
else:
print u'歌手文件夹已经存在!'
album = music_info_obj.find('p',{"class":"album"}).find('a').text.strip()
##发布时间需要处理; 排除空白的情况
if music_info_obj.find('p',{"class":"publish"}).text.strip() ==u'发行时间:':
publishtime = '未知'
else:
publishtime = music_info_obj.find('p',{"class":"publish"}).text.strip()
publishtime = publishtime.replace(u'发行时间:','')
##发行公司需要处理;排除空白的情况
if music_info_obj.find('p',{"class":"company"}).text.strip() ==u'发行公司:':
publishcompany = '未知'
else:
publishcompany = music_info_obj.find('p',{"class":"company"}).text.strip()
publishcompany = publishcompany.replace(u'发行公司:','') ###获取图片
pic_url = music_info_obj.find('img',{"class":"music-song-ing"})['src']
if pic_url:
pic_path = self.save_pic(pic_url)
data['name'] = name
print u"歌名:"+name
data['singer'] = singer
print u"歌手:" + singer
data['album'] = album
data['publishtime'] =publishtime
data['publishcompany'] = publishcompany
data['composer'] = ''
data['lyrics'] = ''
data['filesize'] = ''
data['filetime'] = 0
data['userhead'] = pic_path if pic_path else ''
data['types'] = ','+str(type_id)+','
data['status'] = 0
## 判断数据库是否重复
#print 'select id,TYPES from network_music where NAME="{0}" and SINGER="{1}"'.format(name,singer)
cursor.execute('select id,TYPES from network_music where NAME="{0}" and SINGER="{1}"'.format(name,singer))
result_types = cursor.fetchall()
if result_types:
if str(type_id) in result_types[0][1]:
pass
else:
types = result_types[0][1] + str(type_id)+','
cursor.execute("UPDATE network_music SET TYPES='{0}' WHERE id ={1}".format(types, result_types[0][0]))
## 提交,不然无法保存新建或者修改的数据
conn.commit()
data['check'] = 0
return data def save_music_lrc(self, driver,song_id,singer_path):
music_lrc = {}
m_api = 'http://music.baidu.com/data/music/file?link=&song_id={0}'.format(song_id)
driver.get(m_api)
time.sleep(3)
### 找到最新的文件
path_d = u'C:\\Users\\hz\\Downloads'
file_lists = os.listdir(path_d)
try:
file_lists.sort(key=lambda fn: os.path.getmtime(path_d + "\\" + fn))
filename = file_lists[-1]
if filename:
#print filename
#print singer_path
### 移动到
shutil.move(u'C:\\Users\\hz\\Downloads\\'+filename,singer_path)
except:
#os.remove(my_file)
print u"移动失败,文件名字问题,手动修改"
##跳转到页面
driver.get('http://music.baidu.com/song/{0}'.format(song_id))
time.sleep(2)
try:
l_api = driver.find_element_by_xpath('//*[@id="lyricCont"]').get_attribute('data-lrclink')
driver.get(l_api)
time.sleep(2)
try:
music_lrc['lrc_name'] = self.get_lrc_path()
except:
print u'获取歌词文件名错误'
except:
music_lrc['words'] = '暂无'
print u'没有歌词'
return music_lrc def save_db(self,cursor,list):
print list
try:
effect_row = cursor.executemany("insert into network_music(ID,NAME,SINGER,ALBUM,PUBLISHTIME,PUBLISHCOMPANY,COMPOSER,LYRICS, \
FILESIZE,FILETIME,USERHEAD,TYPES,STATUS,WORDS,FILEPATH)values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ", list)
## 提交,不然无法保存新建或者修改的数据
conn.commit()
except:
print 'Add this db fault!' def save_pic(self, pic_url, save_path=''):
##组装成接口
pic_list = ['.jpg@','.png@','.jpeg@','.JPG@','.PNG@','.JPEG@']
for v in pic_list:
#print pic_url
if v in pic_url:
check = 1
else:
endname = '.errorpic'
if 'check' in vars() and check == 1:
endname = v.replace('@', '')
#print endname,pic_url
save_path = path.join(d, 'music2/USERHEAD/')
###名字暂用时间戳
picName = int(time.time())
savepic = save_path + str(picName) + endname
try:
urllib.urlretrieve(pic_url, savepic)
return 'music2/USERHEAD/' + str(picName) + endname
except:
return 'no' def get_lrc_path(self):
path_d = u'C:\\Users\\hz\\Downloads'
file_lists = os.listdir(path_d)
file_lists.sort(key=lambda fn: os.path.getmtime(path_d + "\\" + fn))
lrc_name = file_lists[-1]
'''
if lrc_name:
shutil.move(u'C:\\Users\\hz\\Downloads\\' + lrc_name, u'G:\\www\\music2\\LRC\\')
'''
return lrc_name ''' def auto_down1(self, url, filename):
try:
urllib.urlretrieve(url, filename)
except urllib.ContentTooShortError:
print 'Network conditions is not good.Reloading.'
auto_down(url, filename) def auto_down2(self, url, filename):
##加载cookies
raw_cookies = "PSTM=1523331116; BIDUPSID=6598753517A81D738FD546C2D96EDAC5; BAIDUID=E5EE59A93C8788A953248CD76BEBD48D:FG=1; H_PS_PSSID=1425_18194_21127_26182_20928; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; PHPSESSID=bae76nl31pln7r47vi3i1o9jh7; Hm_lvt_4010fd5075fcfe46a16ec4cb65e02f04=1523420559,1523420572; PSINO=2; Hm_lpvt_4010fd5075fcfe46a16ec4cb65e02f04=1523425208"
cookies = {}
for line in raw_cookies.split(';'):
key, value = line.split('=', 1) # 1代表只分一次,得到两个数据
cookies[key] = value
r = requests.get(url, stream=True,cookies = cookies )
f = open(filename, "wb")
for chunk in r.iter_content(chunk_size=512):
if chunk:
f.write(chunk)
f.close() def auto_down3(self, url, filename):
cookie = cookielib.MozillaCookieJar()
cookie.load('c.txt', ignore_expires=True, ignore_discard=True)
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
urllib2.install_opener(opener)
music = urllib2.urlopen(url).read()
f = open(filename,'wb')
f.write(music)
f.close()
''' if __name__ == "__main__":
print r'Starting....'
for i in range(5):
sys.stdout.write('>'*i + '\n')
sys.stdout.flush()
time.sleep(0.5)
conn = pymysql.Connection(host="localhost", user="root", passwd="root", db='test1', charset="UTF8")
# 创建指针
cursor = conn.cursor()
type = raw_input(r'请输入歌曲的类型: ').strip()
## 加入数据库
## 先判断值是否存在
result = cursor.execute("select id from network_type where RESOURCETYPE='m' and TYPENAME='{0}'".format(type))
if result == 0:
print u'-----该类型不存在添加至数据库-------'
effect_row = cursor.executemany("insert into network_type(PID,RESOURCETYPE,TYPENAME)values(%s,%s,%s)", [(-1,'m',type)])
type_id = int(cursor.lastrowid)
else:
print u'-----该类型存在不需要添加至数据库-------'
type_val= cursor.fetchall()
type_id = type_val[0][0]
## 提交,不然无法保存新建或者修改的数据
conn.commit()
type_q = urllib2.quote(type)
# 实例
bmSpider = BadiuMusicSpider()
bmSpider.login(cursor,type_id,type_q)

----代码的逻辑

第一步:登录百度,使用selenium(本来我打算用selenium登录之后导出cookie,再通过加载cookie,但是遇到了些问题,再加上工作原因就没有用这个,下次我有空再试,验证码方面,没有设置,遇到验证码关了重启,只要登录成功了,可以爬很久了。)

第二步:输入歌曲类型,默认从第一页开始抓取,接下来就是各种循环,入库啥的,还有文件移动。

总的来说还是比较简单的一个爬虫,不足之处大佬轻喷。

Baidu音乐爬虫的更多相关文章

  1. 公众号开发之wx-tools+springboot应用实战-音乐爬虫推送[JAVA]

    springboot+wx-tools实践!音乐爬虫推送公众号DEMOGitHub地址:wx-tools 最终DEMO源码地址: music_collector 先理一下大概的开发步骤: 1. 创建一 ...

  2. 关于网易云音乐爬虫的api接口?

    抓包能力有限,分析了一下网易云音乐的一些api接口,但是关于它很多post请求都是加了密,没有弄太明白.之前在知乎看到过一个豆瓣工程师写的教程,但是被投诉删掉了,请问有网友fork了的吗?因为我觉得他 ...

  3. QQ音乐爬虫

    #今日目标 **QQ音乐爬虫** 今天要爬取的是QQ音乐任意歌手的所有音乐歌词,因为笔者是周杰伦的忠实粉丝,所以专门写了个爬虫来爬取他的音乐的歌词,因为他的音乐在咪咕音乐可以听,所以便没有去爬取. 好 ...

  4. Python Scrapy的QQ音乐爬虫 音乐下载、爬取歌曲信息、歌词、精彩评论

    QQ音乐爬虫(with scrapy)/QQ Music Spider UPDATE 2019.12.23 已实现对QQ音乐文件的下载,出于版权考虑,不对此部分代码进行公开.此项目仅作为学习交流使用, ...

  5. Scrapy加Redis加IP代理池实现音乐爬虫

    音乐爬虫 关注公众号"轻松学编程"了解更多. 目的:爬取歌名,歌手,歌词,歌曲url. 一.创建爬虫项目 创建一个文件夹,进入文件夹,打开cmd窗口,输入: scrapy star ...

  6. 爬虫综合大作业——网易云音乐爬虫 & 数据可视化分析

    作业要求来自于https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3075 爬虫综合大作业 选择一个热点或者你感兴趣的主题. 选择爬取的对象 ...

  7. 【音乐爬虫】Python爬虫-selenium+browsermob-proxy 解决动态网页 js渲染问题

    1.一般的python爬虫很简单,直接请求对应网址,解析返回的数据即可,但是有很多网站的数据的js动态渲染的,你直接请求是得不到对应的数据的 这时就需要其它手段来处理了. 2.以一个例子来说明,整个过 ...

  8. 【Python3爬虫】网易云音乐爬虫

    此次的目标是爬取网易云音乐上指定歌曲所有评论并生成词云 具体步骤: 一:实现JS加密 找到这个ajax接口没什么难度,问题在于传递的数据,是通过js加密得到的,因此需要查看js代码. 通过断掉调试可以 ...

  9. music-api-next:一款支持网易、xiami和QQ音乐的JS爬虫库

    音乐,无界 让音乐无界 如果你苦于挑选一个全方位.多平台.简便易用的音乐爬虫库,music-api-next是不二选择. 特性: 支持网易.虾米和QQ三大主流音乐平台 支持音乐关键词搜索 支持音乐链接 ...

随机推荐

  1. C#编程语言之委托与事件(一)—— C/C++函数指针和C#委托初步

    相信正在学习C#的人都有学习过C或C++的经验,本文要讲的第一个要点是C#中的委托(delegate,有些资料也叫代表).什么是委托,很多人都能自然而然地想到C/C++中的函数指针,事实上很多书和资料 ...

  2. BLESS学习笔记

    BLESS全称:Bloom-filter-based Error Correction Solution for High-throughput Sequencing Reads,即基于布隆过滤器的高 ...

  3. Win调整和小技巧

    推荐win下一些个人爱用的工具软件(以及使用心得)和一些系统调整方法,让win下不尽人意的设置发生小小变化,让整天摸着电脑的ITer们的生活更有乐趣. 本人酷爱收集一些好用的软件,若各位也对某个或某些 ...

  4. vue计算属性详解——小白速会

    一.什么是计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的.在模板中放入太多的逻辑会让模板过重且难以维护.例如: <div id="example"> ...

  5. 冲刺NO.11

    Alpha冲刺第十一天 站立式会议 项目进展 项目进入尾声,主要测设工作完成过半,项目总结也开始进行. 问题困难 项目的困难现阶段主要是测试过程中存在一些"盲点"很难发现或者发现后 ...

  6. Linux下硬盘分区

    1  fdisk -l查看硬盘及分区信息 我的系统(Archlinux)下的命令效果如下: 由上面的图片可以得知该系统只挂载了1个硬盘,命名为sda,其有2个主分区,sda1和sda2,至于为什么这么 ...

  7. verilog学习笔记(4)_有限状态机

    有限状态机: 有限状态机是由寄存器组和组合逻辑构成的硬件时序电路: - 其状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态: - 究竟转 ...

  8. Flask jinja2 全局函数,宏

    内置全局函数 dict()函数,方便生成字典型变量 {% set user = dict(name='Mike',age=15) %} <p>{{ user | tojson | safe ...

  9. cord-in-a-box 2.0 安装指南

    [TOC] 这篇文章简要介绍了 Ciab2.0 的安装. 包括硬件, 软件环境的选择, Ciab2.0的实际部署架构, 安装过程等. 下面就先对 Ciab2.0 部署环境做简要介绍. 1. 概述 这一 ...

  10. 再一次, 不要使用(include/require)_once

    本文地址: http://www.laruence.com/2012/09/12/2765.html 最近关于apc.include_once_override的去留, 我们做了几次讨论, 这个APC ...