最近学习了一下爬虫的原理和基本的思路, 并且利用selenium + Python + Chrome 进行了一系列的爬虫.

最开始的想法是, 想每天爬取自己网易云音乐的一些数据, 比如每天听歌量, 之类的.

可以很轻松的利用selenium中的CSS selector 或者 XPath路径找到对应的HTML标签元素, 再通过鼠标等操作, 完成登陆, 进而爬取数据,

但是, 后来发现网易云音乐的登陆有机器人检测, 在监视模式下无法通过selenium直接登陆. 参考了网上的各方意见之后, 找到解决的方法有两种:

1. 通过get/post请求分析, 并修改header来提交表单完成登陆操作;(在requests模块中)

2. 通过模拟鼠标移动来登陆(但听说这种方法现在也会直接被认定为机器人!)

最终这个登陆问题也没有得到解决!!

但是, 这并没有打消我爬虫的积极性. 所以就有了现在的免登陆爬虫:

零、运行环境搭建:

1. 运行环境

我的爬虫是在win7下运行的,用到的爬虫软件有:

ChromeDriver 70.0.3538.67

Python 3.7.0

Selenium 3.14.1

当然, 如果你和我一样, 也是Firefox的忠实粉丝, 我也为你做了测试:

geckodriver-v0.23.0-win64

Firefox 60.0.1

Python 3.7.0

Selenium 3.14.1

这么做的目的主要是因为, 一开始不知道Firefox也有headless模式(无头), 所以专门下载的Chrome.

2. 爬虫部署:

Win7下: 可以使用任务计划程序来定制爬虫; 我使用的是一个叫Ontimer的软件, 可以一键设置和管理所有自定义的计划, 并实现后台静默运行;

Linux下: 我的服务器是CentOS6.9, 比较难搭建运行环境, 如果是CentOS7的操作系统, 可以使用crontab来部署你的爬虫!

一、 取得并分析URL地址:

取得的URL地址如:https://music.163.com/#/user/songs/rank?id=你的网易云音乐ID

上面id=, 可以通过找到你的个人主页来得到(也可以修改id来访问别人的主页)

二、设置请求头:

# 设置Chrome请求头(无头模式):
options = webdriver.ChromeOptions()
options.add_argument('--headless')options.add_argument('lang=zh_CN.UTF-8') # 设置中文
options.add_argument('disable-infobars') #隐藏"Chrome正在受到自动软件的控制"
options.add_argument('--disable-gpu') #谷歌文档提到需要加上这个属性来规避bug# 更换头部
user_agent = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) " +"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36")
options.add_argument('user-agent=%s'%user_agent)

这个是Chrome浏览器请求头设置的代码, 如果你用的是Firefox浏览器:

# 设置Chrome请求头(无头模式):
options = webdriver.FirefoxOptions()
options.add_argument('-headless')options.add_argument('lang=zh_CN.UTF-8') # 设置中文
options.add_argument('disable-infobars') #隐藏"Chrome正在受到自动软件的控制"
options.add_argument('--disable-gpu') #谷歌文档提到需要加上这个属性来规避bug# 更换头部
user_agent = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) " +"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36")
options.add_argument('user-agent=%s'%user_agent)

基本和Chrome一致.

如果很不幸, 你用的是PhantomJS或者其他的浏览器驱动, 我这里并没有配置header的代码;

(其实我是有PhantomJS配置的代码的, 但是由于听说PhantomJS要停止维护了, 所以在这里就不写了! 有需要的朋友请自行百度)

三、配置并请求链接:

        browser = webdriver.Chrome(chrome_options=options)browser.get("https://music.163.com/#/user/songs/rank?id=" + user_id)

在这里, 我通过一个str类型的变量user_id来实现了访问网易云音乐不同用户的页面;

三'、预处理:

        browser.switch_to.frame("g_iframe")

认真读过网易云音乐页面源代码之后, 发现, 其实他的页面是一个嵌入到body中的一个叫g_iframe的框架构成的;

其实这也是我放弃requests 转而用selenium的最主要原因, 因为貌似requests只能在单个页面中寻找元素, 而无法处理iframe框架.

四、寻找对应元素的xpath:

xpath在类似于Chrome或者Firefox这种主流的浏览器里非常简单:

按下F12, 找到对应的元素, 右键源代码, 复制xpath即可!

这里以

歌曲名为例: /html/body/div[3]/div/div[2]/div/div[1]/ul/li[1]/div[2]/div[1]/div/span/a/b

五、处理对应元素:

        xpath_musicname_left = "/html/body/div[3]/div/div[2]/div/div[1]/ul/li["xpath_musicname_right = "]/div[2]/div[1]/div/span/a/b"for i in range(1, 101):  # 歌曲名处理:try: # 排行榜内部不到一百首歌, 退出xpath_musicname = xpath_musicname_left + str(i) + xpath_musicname_righteach_info["name"] = (browser.find_element_by_xpath(xpath_musicname))# 正则表达式,去掉歌名中的逗号, 并将"name"处理为str类型!:each_info["name"] = re.sub(",", "", each_info["name"].text)except:break

通过查看多个元素的xpath可以找到规律, 将其分为'左边'和'右边', 从而插入相应的数量信息即可确定对应的xpath;

再通过查看selenium的手册, 找到driver.find_element_by_xpath()函数, 可以返回一个Web类型的变量(.text为对应的字符串)

六、处理数据:

最后, 可以保存相应的数据, 不论是JSON, .csv, 还是.txt类型都是可以的!!!!

我为了方便处理数据, 最终选择了将数据保存为.txt格式.

源代码:

Chrome:

#!/usr/bin/python
#-*- coding: utf-8 -*-
import re
import sys
import datetime
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.action_chains import ActionChainsdef scrap_music(user_id):try:# 打开网页: browser = webdriver.Chrome(chrome_options=options)browser.get("https://music.163.com/#/user/songs/rank?id=" + user_id)# selenium预处理: (转换到iframe内部)browser.switch_to.frame("g_iframe")xpath_musicname_left = "/html/body/div[3]/div/div[2]/div/div[1]/ul/li["xpath_musicname_right = "]/div[2]/div[1]/div/span/a/b"xpath_artist_left = "/html/body/div[3]/div/div[2]/div/div[1]/ul/li["xpath_artist_right = "]/div[2]/div[1]/div/span/span/span"xpath_artist_text_left = ""xpath_artist_text_right = ""xpath_playtimes_left = "/html/body/div[3]/div/div[2]/div/div[1]/ul/li["xpath_playtimes_right = "]/div[3]/span"# 用列表类型来整合toplist, each_info存放每一个的表单toplist = list()each_info = dict()# 时间戳处理:year = datetime.datetime.now().strftime("%Y")month = datetime.datetime.now().strftime("%m")day = datetime.datetime.now().strftime("%d")hour = datetime.datetime.now().strftime("%H")now_time = month + u"/" + day + u":" + hour + u"h"for i in range(1, 101):  # 歌曲名处理:try: # 排行榜内部不到一百首歌, 退出xpath_musicname = xpath_musicname_left + str(i) + xpath_musicname_righteach_info["name"] = (browser.find_element_by_xpath(xpath_musicname))# 正则表达式,去掉歌名中的逗号, 并将"name"处理为str类型!:each_info["name"] = re.sub(",", "", each_info["name"].text)except:break# 歌唱家处理:try: # 第一个try 用来判断是否为100首歌, 若通过, 说明有歌, 这个try 用来判断歌手是链接形式还是文本形式给出!xpath_artist = xpath_artist_left + str(i) + xpath_artist_righteach_info["artist"] = (browser.find_element_by_xpath(xpath_artist).get_attribute("title"))except:break# 播放次数(百分比)处理: (由于未登录, 所以采用默认排名末位的歌曲仅播放一次, 并通过第一与末尾元素的比例来判定播放次数)xpath_playtimes = xpath_playtimes_left + str(i) + xpath_playtimes_righteach_info["playtime_percent"] = (browser.find_element_by_xpath(xpath_playtimes).get_attribute("style"))# 正则表达式将非数字的字符全部转化为空字符, 完成数字的提取:each_info["playtime_percent"] = int(re.sub("\D", "", each_info["playtime_percent"]))# 排行榜序列索引each_info["index"] = i# 处理时间戳  each_info["time"] = now_time# 加入处理后的数据到列表toplist中:toplist.append(each_info)each_info = dict()# 播放次数(真实数据)处理: (由于未登录, 所以采用默认排名末位的歌曲仅播放一次, 并通过第一与末尾元素的比例来判定播放次数)# 处理首个和末尾单元的播放次数:toplist[-1]["playtimes"] = 1if toplist[-1]["playtime_percent"] == 0: # 如果网页上最后一名的长度为0, 则第一位的播放量应当大于100, 选取为101(预测)toplist[0]["playtimes"] = 101else:toplist[0]["playtimes"] = (toplist[0]["playtime_percent"] / toplist[-1]["playtime_percent"]) * toplist[-1]["playtimes"]# 处理所有其他的次数:for i in toplist:if i["playtime_percent"] == toplist[-1]["playtime_percent"]:i["playtimes"] = 1else:i["playtimes"] = int((i["playtime_percent"] / 100.0) * toplist[0]["playtimes"])# 注: 以上计算方法仅仅是预测, 所以会有一定的误差!    # 输出到文件中:# 打开文件追加a模式filename = user_id + ".txt"fileout = open(filename, "a+", encoding='utf-8')#写入数据:for i in toplist:fileout.writelines(i["name"] + "," + i["artist"] + "," + str(i["playtimes"]) + "," + i["time"] + "\n")    finally:# 关闭文件和窗口:fileout.close()browser.close()#-----------------------------------------  程序开始处 -------------------------------------------## 设置Chrome请求头(无头模式):
options = webdriver.ChromeOptions()
options.add_argument('--headless')options.add_argument('lang=zh_CN.UTF-8') # 设置中文
options.add_argument('disable-infobars') #隐藏"Chrome正在受到自动软件的控制"
options.add_argument('--disable-gpu') #谷歌文档提到需要加上这个属性来规避bug# 更换头部
user_agent = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) " +"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36")
options.add_argument('user-agent=%s'%user_agent)usr_id = []
for each_id in usr_id:scrap_music(str(each_id))
# 退出程序:
#    sys.exit(0)

Firefox:

#!/usr/bin/python
#-*- coding: utf-8 -*-
import re
import sys
import datetime
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.action_chains import ActionChainsdef scrap_music(user_id):try:# 打开网页: browser = webdriver.Firefox(firefox_options=options)browser.get("https://music.163.com/#/user/songs/rank?id=" + user_id)# selenium预处理: (转换到iframe内部)browser.switch_to.frame("g_iframe")xpath_musicname_left = "/html/body/div[3]/div/div[2]/div/div[1]/ul/li["xpath_musicname_right = "]/div[2]/div[1]/div/span/a/b"xpath_artist_left = "/html/body/div[3]/div/div[2]/div/div[1]/ul/li["xpath_artist_right = "]/div[2]/div[1]/div/span/span/span"xpath_artist_text_left = ""xpath_artist_text_right = ""xpath_playtimes_left = "/html/body/div[3]/div/div[2]/div/div[1]/ul/li["xpath_playtimes_right = "]/div[3]/span"# 用列表类型来整合toplist, each_info存放每一个的表单toplist = list()each_info = dict()# 时间戳处理:year = datetime.datetime.now().strftime("%Y")month = datetime.datetime.now().strftime("%m")day = datetime.datetime.now().strftime("%d")hour = datetime.datetime.now().strftime("%H")now_time = month + u"/" + day + u":" + hour + u"h"for i in range(1, 101):  # 歌曲名处理:try: # 排行榜内部不到一百首歌, 退出xpath_musicname = xpath_musicname_left + str(i) + xpath_musicname_righteach_info["name"] = (browser.find_element_by_xpath(xpath_musicname))# 正则表达式,去掉歌名中的逗号, 并将"name"处理为str类型!:each_info["name"] = re.sub(",", "", each_info["name"].text)except:break# 歌唱家处理:try: # 第一个try 用来判断是否为100首歌, 若通过, 说明有歌, 这个try 用来判断歌手是链接形式还是文本形式给出!xpath_artist = xpath_artist_left + str(i) + xpath_artist_righteach_info["artist"] = (browser.find_element_by_xpath(xpath_artist).get_attribute("title"))except:break# 播放次数(百分比)处理: (由于未登录, 所以采用默认排名末位的歌曲仅播放一次, 并通过第一与末尾元素的比例来判定播放次数)xpath_playtimes = xpath_playtimes_left + str(i) + xpath_playtimes_righteach_info["playtime_percent"] = (browser.find_element_by_xpath(xpath_playtimes).get_attribute("style"))# 正则表达式将非数字的字符全部转化为空字符, 完成数字的提取:each_info["playtime_percent"] = int(re.sub("\D", "", each_info["playtime_percent"]))# 排行榜序列索引each_info["index"] = i# 处理时间戳  each_info["time"] = now_time# 加入处理后的数据到列表toplist中:toplist.append(each_info)each_info = dict()# 播放次数(真实数据)处理: (由于未登录, 所以采用默认排名末位的歌曲仅播放一次, 并通过第一与末尾元素的比例来判定播放次数)# 处理首个和末尾单元的播放次数:toplist[-1]["playtimes"] = 1if toplist[-1]["playtime_percent"] == 0: # 如果网页上最后一名的长度为0, 则第一位的播放量应当大于100, 选取为101(预测)toplist[0]["playtimes"] = 101else:toplist[0]["playtimes"] = (toplist[0]["playtime_percent"] / toplist[-1]["playtime_percent"]) * toplist[-1]["playtimes"]# 处理所有其他的次数:for i in toplist:if i["playtime_percent"] == toplist[-1]["playtime_percent"]:i["playtimes"] = 1else:i["playtimes"] = int((i["playtime_percent"] / 100.0) * toplist[0]["playtimes"])# 注: 以上计算方法仅仅是预测, 所以会有一定的误差!    # 输出到文件中:# 打开文件追加a模式filename = user_id + ".txt"fileout = open(filename, "a+", encoding='utf-8')#写入数据:for i in toplist:fileout.writelines(i["name"] + "," + i["artist"] + "," + str(i["playtimes"]) + "," + i["time"] + "\n")    finally:# 关闭文件和窗口:fileout.close()browser.close()#-----------------------------------------  程序开始处 -------------------------------------------## 设置Chrome请求头(无头模式):
options = webdriver.FirefoxOptions()
options.add_argument('-headless')options.add_argument('lang=zh_CN.UTF-8') # 设置中文
options.add_argument('disable-infobars') #隐藏"Chrome正在受到自动软件的控制"
options.add_argument('--disable-gpu') #谷歌文档提到需要加上这个属性来规避bug# 更换头部
user_agent = ("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) " +"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36")
options.add_argument('user-agent=%s'%user_agent)usr_id = []
for each_id in usr_id:scrap_music(str(each_id))
# 退出程序:
#    sys.exit(0)

    注:

需要注意的是, 在处理并计算网易云音乐播放次数的时候, 如果没有登陆, 则播放的次数是不会被显示的!!!

而, 可以观察到: 其实每一个播放的歌曲后面都有一定的阴影面积, 通过计算, 可以发现, 这些都是和第一位播放量的比例.

所以不妨认为播放排行榜中的最后一首歌的播放次数为1次, 从而推测出(注意: 这里也仅仅是推测!!!)第一位播放量;

所以对于想要精确播放量的朋友, 现在可以关闭这个网页了, 因为精确的数据是本爬虫算法无法获取的.(笑)

但是经过本人测试, 对于一般的用户而言, 基本上相差很小!!(至少对于我数据可视化来说, 这些数据造成的误差可以忽略了!)

大概就是这样吧, 本人也是最近才开始学习爬虫, 有什么错误的地方也请大家批评指正, 也欢迎大家一起交流!

网易云音乐听歌量爬虫(免登陆版)相关推荐

  1. 听歌识曲java_Android自定义View之继承扩展(仿网易云音乐听歌识曲)

    前言 上篇文章说到了自定义View的组合实战,链接:Android自定义View之组合实战(以支付宝页面为例) ,感兴趣的同学可以看看.今天要分享的是一个模仿网易云音乐听歌识曲界面的自定义View,实 ...

  2. Chrome插件:网易云音乐听歌识曲

    大家好,我是若川.持续组织了8个月源码共读活动,感兴趣的可以 点此加我微信ruochuan12 参与,每周大家一起学习200行左右的源码,共同进步.同时极力推荐订阅我写的<学习源码整体架构系列& ...

  3. Axure教程(中级):网易云音乐听歌识曲效果模仿

    本教程给大家分享一下模仿[网易云音乐]APP的听歌识曲界面效果 做法如下,如有雷同,纯属默契: 一.页面布局 从左侧元件库拉入一个[椭圆形],尺寸为100*100,填充色为红色,再复制4个作为声波圆圈 ...

  4. 非常使用的网易云打卡系统, 网易云音乐打卡,网易云音乐听歌300首, 网易云打卡一键听300首歌

    非常实用的网易云音乐打卡,网易云音乐一键打卡300首歌曲 定时完成网易云音乐打卡,也可托管完成. 一键打卡及可完成听歌任务 升级速度杠杠的! 注意事项: 1.仅支持网易云手机号码登录的用户 2.如果是 ...

  5. 腾讯云函数 python_利用腾讯云函数进行网易云音乐听歌打卡

    腾讯云函数官网 1.找到腾讯云函数控制台,并新建函数(地区任选,这里以广州为例) 2.新建空白函数,函数名称随意填写,运行环境选择Python3.6 为什么不用PHP,因为PHP要执行的全部任务全部通 ...

  6. 自定义View之网易云音乐听歌识曲水波纹动画

    先上效果图 点击中间的按钮后,像外发散水波纹,再次点击水波纹消失. 实现原理 当点击按钮后,我们隔一段时间执行一个RippleCircleView的动画,动画包括扩大和透明度,通过PropertyVa ...

  7. Python3---站在大佬肩膀写爬虫-爬取网易云音乐热歌榜歌曲热评(精彩评论)

    和我一起加入CSDN----程序猿和攻城狮的社区 网易云音乐是我比较喜欢的一个音乐平台,对于特别热爱听歌的人来说,网易云音乐精准的音乐定位和独特歌曲推荐,让人使用起来很舒服.所谓:自古评论出人才,精彩 ...

  8. python爬虫爬取音乐_利用python爬虫实现爬取网易云音乐热歌榜

    利用python爬虫实现爬取网易云音乐热歌榜 发布时间:2020-11-09 16:12:28 来源:亿速云 阅读:102 作者:Leah 本篇文章给大家分享的是有关利用python爬虫实现爬取网易云 ...

  9. python爬取网易云音乐飙升榜音乐_Python爬虫实战,30行代码轻松爬取网易云音乐热歌榜...

    在开始讲解思路之前,我们首先了解下网络状态码,为什么要看这个呢?以后你会回来感谢我的,嘻嘻! 一般网络状态有以下几种: 200(成功) 服务器成功处理了请求.一般来说,这意味着服务器提供所请求的页面, ...

最新文章

  1. python软件是免费的吗-python软件都是免费的吗
  2. 配置apache虚拟host
  3. audio标签不展示_设计标签式PPT:排版简洁明了,强烈信息秩序感,你想试试吗?...
  4. SAP Spartacus 的页面设计思路
  5. python文字游戏 生成数字菜单_python自学日记5——文字游戏
  6. 28 岁裸辞转行程序员,一年的心路历程大曝光
  7. squid代理简单应用
  8. MariaDB基本操作--(创建用户)(转)
  9. Android端直播系统开发入门
  10. C# winform 开发总结 -- 【持续更新】
  11. YDOOK:Maxwell 电磁场仿真 最新版的 Maxwell 软件 使用什么软件进行电磁场仿真
  12. 编程算法题:101个数字,[1,100]中有一个是重复的,找出这个重复的数字。
  13. maxscript rollout
  14. MySQL数据库如何改名
  15. 数学建模,8月学习感想
  16. NanoPi-K2 控制GPIO
  17. 使用Linkage Mapper制作环境连接图
  18. 移动测试基础 Android 应用测试总结
  19. 双色球号码生成和验证
  20. 计算机操作员证书等级有哪些,还有多少不知道职业资格证书分为几个等级的 赶快脑补一下吧...

热门文章

  1. python语言如何使用隧道爬虫ip
  2. 【USB笔记】接口描述符Interface Descriptor
  3. Android遥控配置
  4. 看不懂掐死我系列之支持向量机(SVM)从原理到python代码实现
  5. FPGA NCOip核的使用及仿真(quartusii 13.1+modelsimse 10.5)
  6. 人生思维与职业的转变
  7. 如何获得邻居家WiFi密码(实用)
  8. SSD安装Windows 7/10的坑
  9. Android常见内存泄漏
  10. 云里黑白第四回——我想进安全模式更新后进不了系统