文章目录
一、项目介绍二、所需技术三、网页分析3.1 分析一级页面响应内容3.2 分析二级页面响应内容3.3 分析三级页面响应内容3.4 分析四级页面响应内容四、分析小结五、代码实现六、爬取结果六、总结一、项目介绍
整个项目的是爬取网易云音乐的歌曲的歌词,可以做成歌词本,或其他用途,做到了人性化选择,可以选择网易云音乐所有的音乐种类与音乐人,按照不同的需求拼接url获取内容。但是整个项目我个人认为有些复杂,通过分析网易云音乐网站的源代码发现,里面有很多坑,具体我会在下面展开,提醒大家,我也会用到一些新的方法,并且需要分析的内容也比较多,多提一嘴,我写的这些教程面向有编程基础的读者,因为有些内容我没有详细讲解,篇幅也不够,如果有新入门的朋友,可以私信我,我会提供技术支持,好技术一起分享。
二、所需技术
import urllib.requestimport urllib.parseimport lxml import etree (xpath用于获取内容)from selenium import webdriver (这是浏览器的自动化库,可以控制浏览器)import re (正则表达式,用于提取内容)import requests (用于正常的解析内容)import os (保存数据时会用到)import json (用于txt和json格式的转换)chromedriver.exe (这是一个工具,配合selenium使用,注意要下载对应浏览器的对应版本)三、网页分析
3.1 分析一级页面响应内容
还是老规矩我们来看网站首页能反馈给我们什么内容,我们可以看到,我们应该从首页进入歌手界面,所以需要获取到他的href,这样我们才能拼接url,跳转到歌手界面,但是这里是第一个坑,可见下图,红色是我们需要获取的内容,但是,这些内容都在蓝色的iframe标签中,因为当时(半年前)我还没学前端,所以我在这里踩了第一个坑,根本获取不到内容,解析的html什么都没有,要知道,iframe就是为了无法解析浏览器,所以我们这里就用到的selenium自动化控制浏览器,使用控制软件,打开浏览器,这样就能自动获取到我们想要的内容,也就是href,虽然这样需要打开浏览器,但是我们可以设置关闭,所以并无大碍。
3.2 分析二级页面响应内容
我们在上面已经获取到了二级页面的相关href,我们就已经来到了二级页面,二级页面我们需要获取到每个歌手的分类,我们就能进入到具体的歌手界面,所以我们还需要获取到每个分类的id,获取到之后就能拼接每个歌手具体的url,同样还是包在iframe标签中,所以还需要selenium自动化测试,会在下面的代码中展示。看下图,我们找到了对应分类的url,这里需要说明,我们后续为了让用户更好的体验能够选择,所以我们需要用到正则获取到大分类的id,这样我们就能来到分类页面,这样我们就来到了三级页面。
3.3 分析三级页面响应内容
来到三级页面之后,我们可以看到这个分类的所有歌手都展示出来了,这就到了小分类,根据这个大分类中的首字母进行小分类,我们还是需要获取到href,可见包裹在li标签中,这样我们就可以使用xpath提取,同样我们还是会使用字典进行保存,通过用户输入内容进行拼接url,在这里我们就能进入下级页面。
3.4 分析四级页面响应内容
来到四级页面后,红框就是我们最终根据用户输入拼接的url,而蓝色部分为我们需要爬取的内容,我们可以看到,都保存在tr中,方便我们使用xpath提取,当然,还需要selenium自动化测试,具体方法我都在下面的代码中标明。
四、分析小结
通过上述分析,我们可以发现,整体技术并不太过复杂,主要是比较麻烦,推荐各位使用selenium,如果有更好的方法,欢迎私信我,这是我半年前写的代码,还是比较青涩,其实就是发送请求,获取响应数据,解析内容,保存数据,短短几个字虽然能概括,但是其中需要大家付出很多努力。
五、代码实现
import urllib.requestimport urllib.parsefrom lxml import etreefrom selenium import webdriverimport reimport requestsimport osimport jsonclass WangYiYunYinYue:# 初始化方法def __init__(self):# 歌手页url,待拼接self.info_url = "/#"# 具体歌手内部页url,待拼接self.start_url = "/#/discover/artist/cat?"# 具体歌曲url,待拼接self.prot_url = "/#/artist?"# 请求头self.headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36"}def dafenlei(self,dafenlei_name):# 使用字典键值对的方式,根据用户输入内容进行拼接urlitem = {'华语男歌手' : 1001, '华语女歌手' : 1002, '华语组合/乐队' : 1003, '欧美男歌手' : 2001, '欧美女歌手' : 2002, '欧美组合/乐队' : , '日本男歌手' : 6001, '日本女歌手' : 6002,'日本组合/乐队' : 6003, '韩国男歌手' : 7001, '韩国女歌手' : 7002, '韩国组合/乐队' : 7003, '其他男歌手' : 4001, '其他女歌手' : 4002, '其他组合/乐队' : 4003,}return item[dafenlei_name]def geshoufenlei(self,geshou):# 使用字典键值对的方式,根据用户输入内容进行拼接urlitem = {'热门' : -1, 'A' : 65, 'B' : 66, 'C' : 67, 'D' : 68, 'E' : 69, 'F' : 70, 'G' : 71, 'H' : 72, 'I' : 73, 'J' : 74, 'K' : 75, 'L' : 76, 'M' : 77, 'N' : 78,'O': 79,'P' : 80, 'Q' : 81, 'R' : 82, 'S' : 83, 'T' : 84, 'U' : 85, 'V' : 86, 'W' : 87, 'X' : 88, 'Y' : 89, 'Z' : 90, '其他' : 0, }return item[geshou]# 根据上面的用户输入内容,拼接urldef get_url(self,fenlei_id,geshou_initial):data = {"id" : fenlei_id,"initial" : geshou_initial}# 解码data_final = urllib.parse.urlencode(data)return self.start_url + data_finaldef get_gesou_info(self,html):# 使用xpath获取内容geshou_html = etree.HTML(html)geshou = geshou_html.xpath("//ul[@class='m-cvrlst m-cvrlst-5 f-cb']/li")for list in geshou:item= {}item["歌手名称:"] = list.xpath("./a/text()") + list.xpath("./div/a/text()") + list.xpath("./p/a/text()")href = list.xpath("./a[1]/@href") + list.xpath("./div/a/@href")# 获取二级页面urlself.get_erji_info(href)# 整个项目的请求方法,可以获得响应内容def parse_url(self,url):response = requests.get(url=url,headers=self.headers)return response.content.decode()# 根据get_gesou_info中获取到的二级页面url,使用正则表达式提取待拼接的内容,继续发送请求# 这里使用selenium控制浏览器def get_erji_info(self,href):src = href[0]id = re.findall(r"\d*\d",src,re.S)[0]data = {"id" : id,}finaldata = urllib.parse.urlencode(data)url = self.prot_url + finaldatadriver = webdriver.Chrome()driver.get(url)driver.switch_to.frame(driver.find_element_by_name("contentFrame"))html = driver.page_sourceinfo_html = etree.HTML(html)next_href_list = info_html.xpath("//table[@class='m-table m-table-1 m-table-4']/tbody")# 获取到三级页面的urlfor next_href in next_href_list:next_url = next_href.xpath("./tr/td[2]/div/div/div/span/a/@href")self.make_sanji_url(next_url)# 解析三级页面的响应def make_sanji_url(self,next_url):for src in next_url:url = self.info_url + srcself.get_sanji_info(url)# 继续获取内容,这才是核心,提取到歌词def get_sanji_info(self,url):driver_html = webdriver.Chrome()driver_html.get(url)driver_html.switch_to.frame(driver_html.find_element_by_name("contentFrame"))html = driver_html.page_sourceinfo_html = etree.HTML(html)all = {}all["歌曲名称:"] = info_html.xpath("//div[@class='cnt']/div[@class='hd']/div//text()")all["歌手:"] = info_html.xpath("//div[@class='cnt']/p/span/a/text()")all["所属专辑:"] = info_html.xpath("//div[@class='cnt']/p/a/text()")all["歌词:"] = info_html.xpath("//div[@class='cnt']/div[@id='lyric-content']//text()")self.save(all)# 保存方法def save(self,all):name = all["歌手:"][0]if not os.path.exists(name):os.mkdir(name)filename = name + ".txt"filepath = name + "/" + filenamewith open(filepath,"a",encoding="utf-8") as tf:tf.write(json.dumps(all,ensure_ascii=False,indent=2))tf.write("\n")# 主方法def run(self):dafenlei_name = input("请输入歌手分类:")fenlei_id = self.dafenlei(dafenlei_name)geshou = input("请输入歌手首字母/热门/其他:")geshou_initial = self.geshoufenlei(geshou)url = self.get_url(fenlei_id,geshou_initial)driver = webdriver.Chrome()driver.get(url)driver.switch_to.frame(driver.find_element_by_name("contentFrame"))html = driver.page_sourceself.get_gesou_info(html)driver.quit()if __name__ == '__main__':wangyiyunyinyue = WangYiYunYinYue()# 调用方法wangyiyunyinyue.run()
六、爬取结果
简单四个示例,您想爬取多少都可以
六、总结
总体来说,爬取一些大公司难度还是有的,可见上图,代码完美运行,能获取到所有的歌词信息,方便我们使用。这类的我不在解析,后面会带来分布式爬取,验证码破解等进阶内容。