本文原创发布于微信公众号「极客猴」,欢迎关注第一时间获取更多原创分享

在使用 Ajax 技术加载数据的网站中, JavaScript 发起的 HTTP 请求通常需要带上参数,而且参数的值都是经过加密的。如果我们想利用网站的 REST API 来爬取数据,就必须知道其使用的加密方式。破解过程需要抓包,阅读并分析网站的 js 代码。这整个过程可能会花费一天甚至更长的时间。

问:那么是否有办法绕过这机制,直接获取网站数据? 答:有的。使用 Selenium 库模拟浏览器行为来抓取网站数据,达到事半功倍的效果。

本文内容是利用 Selenium 爬取网易云音乐中的歌曲 《Five Hundred Miles》 的所有评论,然后存储到 Mongo 数据库。

0 前期准备

本文中所用到的工具比较多,所以我将其列举出来。

  • Selenium

Selenium 是一个 Web 应用程序自动化测试的工具。它能够模拟浏览器进行网页加载。所以使用其来帮助我们解决 JavaScript 渲染问题。

接下来就是安装 selenium, 使用 pip 安装是最方便的。

pip install selenium
  • Chrome 浏览器

在爬取数据过程中, 需要启动浏览器来显示页面。因此,电脑中需要一款浏览器。这里推荐使用 Chrome 浏览器。推荐使用 59 版本以上的 Chrome,当然能使用最新版本那最好不过,目前最新版本是 68。

  • Webdriver

Webdriver 是浏览器驱动。selenium 通过 Webdriver 来操作浏览器。因为我们使用的浏览器是 Chrome,所以需要下载 Chrome 浏览器对应的驱动。

下载地址:chromedriver.chromium.org/downloads

webdriver 下载解压完成之后,将其放到 Python 目录下的 Script 文件夹中。

  • MongoDB

网易云音乐的评论数据总数都很大,十几万条数据比比皆是,甚至还有上百万条数据。所以需要将数据存储到数据库中,我选用的是 MongoDB。

  • pymongo

pymongo 是 Python 操作 MongoDB 的库。同样使用 pip 进行安装。

pip install pymongo

1 爬取思路

1)使用 Selenium 驱动 Chrome 浏览器打开需要爬取的页面。 2)获取页面中 最新评论 标签后面的评论总数,计算出一共有多少个分页, 方便统计。利用总评论数除以 20(每个页面显示 20 条评论),然后对结果进行向上取整。 3)爬取第一页面的评论的数据,然后存储到数据库中。 4)利用 Selenium 模拟点击下一页按钮,再继续爬取该页面的评论数据,并存储到数据库中。 5)一直循环点击,直到所有分页的数据都被爬取完成。

2 代码实现

我们要爬取的歌曲是 《Five Hundred Miles》,先找到其 url 地址,然后调用爬取函数。

if __name__ == '__main__':url = 'http://music.163.com/#/song?id=27759600'  # Five Hundred Milesstart_spider(url)

使用 selenium 启动 Chrome 浏览器。

from selenium import webdriverdef start_spider(url):""" 启动 Chrome 浏览器访问页面 """"""# 从 Chrome 59 版本, 支持 Headless 模式(无界面模式), 即不会弹出浏览器chrome_options = webdriver.ChromeOptions()chrome_options.add_argument('--headless')brower = webdriver.Chrome(chrome_options=chrome_options)"""brower = webdriver.Chrome()brower.get(url)# 等待 5 秒, 让评论数据加载完成time.sleep(5)# 页面嵌套一层 iframe, 必须切换到 iframe, 才能定位的到 iframe 里面的元素iframe = brower.find_element_by_class_name('g-iframe')brower.switch_to.frame(iframe)# 获取【最新评论】总数new_comments = brower.find_elements(By.XPATH, "//h3[@class='u-hd4']")[1]

根据评论总数计算出总分页数。

# start_spider(url)
max_page = get_max_page(new_comments.text)def get_max_page(new_comments):""" 根据评论总数, 计算出总分页数 """print('=== ' + new_comments + ' ===')max_page = new_comments.split('(')[1].split(')')[0]# 每页显示 20 条最新评论offset = 20max_page = ceil(int(max_page) / offset)print('一共有', max_page, '个分页')return max_page

接着循环抓取评论数据,首先抓取第 1 页的评论数据。

# start_spider(url)
current = 1
is_first = True
while current <= max_page:print('正在爬取第', current, '页的数据')if current == 1:is_first = Trueelse:is_first = Falsedata_list = get_comments(is_first, brower)def get_comments(is_first, brower):""" 获取评论数据 """items = brower.find_elements(By.XPATH, "//div[@class='cmmts j-flag']/div[@class='itm']")# 首页的数据中包含 15 条精彩评论, 20 条最新评论, 只保留最新评论if is_first:items = items[15: len(items)]data_list = []data = {}for each in items:# 用户 iduserId = each.find_elements_by_xpath("./div[@class='head']/a")[0]userId = userId.get_attribute('href').split('=')[1]# 用户昵称nickname = each.find_elements_by_xpath("./div[@class='cntwrap']/div[1]/div[1]/a")[0]nickname = nickname.text# 评论内容content = each.find_elements_by_xpath("./div[@class='cntwrap']/div[1]/div[1]")[0]content = content.text.split(':')[1]  # 中文冒号# 点赞数like = each.find_elements_by_xpath("./div[@class='cntwrap']/div[@class='rp']/a[1]")[0]like = like.textif like:like = like.strip().split('(')[1].split(')')[0]else:like = '0'# 头像地址avatar = each.find_elements_by_xpath("./div[@class='head']/a/img")[0]avatar = avatar.get_attribute('src')data['userId'] = userIddata['nickname'] = nicknamedata['content'] = contentdata['like'] = likedata['avatar'] = avatarprint(data)data_list.append(data)data = {}return data_list

将第 1 页评论数据存储到 Mongo 数据库中。

# start_spider(url)
save_data_to_mongo(data_list)def save_data_to_mongo(data_list):""" 一次性插入 20 条评论。插入效率高, 降低数据丢失风险"""collection = db_manager[MONGO_COLLECTION]try:if collection.insert_many(data_list):print('成功插入', len(data_list), '条数据')except Exception:print('插入数据出现异常')

模拟点击“下一页”按钮。

# start_spider(url)
time.sleep(1)
go_nextpage(brower)
# 模拟人为浏览
time.sleep(random.randint(8, 12))
current += 1def go_nextpage(brower):""" 模拟人为操作, 点击【下一页】 """next_button = brower.find_elements(By.XPATH, "//div[@class='m-cmmt']/div[3]/div[1]/a")[-1]if next_button.text == '下一页':next_button.click()

最后就一直循环爬取评论。

3 爬取结果

评论总数大概有 23W 条, 我又在代码中增加延时操作。所以爬取所有评论大概需要 69 个小时。目前我只跑了 9 个小时,我贴下暂时爬取的结果。

4 扩展知识

这部分内容跟上述内容联系不大, 属于服务器技术范畴。如果你不感兴趣的话,可以直接跳过。另外,这部分内容是自己的理解。如果有讲错的地方,还请多多指出。

我们访问普通网站的整个过程:

我们访问使用 Ajax 加载数据的网站的整个过程:

附: 程序源码 Github 仓库地址:163MusicCommentsCrawler


本文首发于微信公众号,原文地址是 爬取《Five Hundred Miles》在网易云音乐的所有评论。随时欢迎转载文章, 转载请联系号主开通白名单,尊重作者的原创。本人微信公众号「极客猴」,每周分享 Python 原创干货。涉及网络爬虫、数据分析、web 开发等方向。

爬取《Five Hundred Miles》在网易云音乐的所有评论相关推荐

  1. Python爬虫小白入门(六)爬取披头士乐队历年专辑封面-网易云音乐

    一.前言 前文说过我的设计师小伙伴的设计需求,他想做一个披头士乐队历年专辑的瀑布图. 通过搜索,发现网易云音乐上有比较全的历年专辑信息加配图,图片质量还可以,虽然有大有小. 我的例子怎么都是爬取图片? ...

  2. python爬取音乐专辑时间_Python爬取披头士乐队历年专辑封面-网易云音乐

    运行环境 我的运行环境如下:系统版本 Windows10. Python版本 Python3.5,推荐使用Anaconda 这个科学计算版本,主要是因为它自带一个包管理工具,可以解决有些包安装错误的问 ...

  3. 如何用 Python 爬取网易云音乐的 10w+ 评论?附详细代码解读

    在简单学习了Python爬虫之后,我的下一个目标就是网易云音乐.因为本人平时就是用它听的歌,也喜欢看歌里的评论,所以本文就来爬一爬网易云音乐的评论吧! 正式进入主题 首先是找到目标网页并分析网页结构, ...

  4. 爬虫入门——用python爬取网易云音乐热门歌手评论数

    本文参考Monkey_D_Newdun 的文章 https://blog.csdn.net/Monkey_D_Newdun/article/details/79318629 用爬虫获取网易云音乐热门歌 ...

  5. 用python爬取网易云评论最多的歌_巧用Python爬取网易云音乐歌曲全部评论

    一.首先分析数据的请求方式 网易云音乐歌曲页面的URL形式为https://music.163.com/#/song?id=歌曲id号,这里我用Delacey的Dream it possible 为例 ...

  6. python爬虫网易云音乐最热评论并分析_Python3实现爬虫抓取网易云音乐的热门评论分析(图)...

    这篇文章主要给大家介绍了关于Python3实战之爬虫抓取网易云音乐热评的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧. ...

  7. python爬网易云音乐评论最多的歌_使用Python爬一爬网易云音乐上那些评论火爆的歌曲...

    网易云音乐这款音乐APP本人比较喜欢,用户量也比较大,而网易云音乐之所以用户众多和它的歌曲评论功能密不可分,很多歌曲的评论非常有意思,其中也不乏很多感人的评论.但是,网易云音乐并没有提供热评排行榜和按 ...

  8. 抓取网易云音乐歌曲热门评论生成词云(转)

    非原创作品,转载自:http://blog.csdn.net/marksinoberg/article/details/70809830 前言 网易云音乐一直是我向往的"神坛",听 ...

  9. python爬虫网易云音乐评论最多的歌_使用Python爬一爬网易云音乐上那些评论火爆的歌曲...

    网易云音乐这款音乐APP本人比较喜欢,用户量也比较大,而网易云音乐之所以用户众多和它的歌曲评论功能密不可分,很多歌曲的评论非常有意思,其中也不乏很多感人的评论.但是,网易云音乐并没有提供热评排行榜和按 ...

最新文章

  1. 【周末阅读】2019自动驾驶十大关键词
  2. 测试wifi软件 最大容量,使用VulcanCompact应用层测试仪评估测试WiFi6无线路由器的最大支持设备数及并发连接数...
  3. 2021长安二中高考成绩查询,长安一中、长安二中,2017年高考上线喜报!
  4. Struts2 整合jQuery实现Ajax功能(2)
  5. 百度地图坐标系相关学习总结
  6. Python入门100题 | 第068题
  7. java中一些入门级技巧
  8. 二、“究恒常之宇宙,成一家之学说”
  9. 从比特币脚本引擎到以太坊虚拟机
  10. 英语总结系列(十九):七月英语Baby成长史
  11. Chrome使用、插件、脚本
  12. vue 动态添加组件
  13. 读取cpu温度的api_获取传感器温度-cpu 温度篇
  14. 逆向笔记2--常用的调试软件及插件
  15. Java实现隐藏文件夹
  16. 金融分析与风险管理——期权BSM模型
  17. Oracle中的分析函数over()的详细解析
  18. linux pv修改大小,Linux下扩容系统容量和删除unknown PV
  19. Java后端处理video快进快退播放以及断点续传的原理和代码
  20. 东京工业大学计算机毕业生去向,打开心扉 收获东京工业大学计算机专业offer

热门文章

  1. IIS的安装、配置与测试
  2. 教你如何搭建本地私有云
  3. python tkinter出牌洗牌
  4. (二)uboot移植--从零开始自制linux掌上电脑(F1C200S)<嵌入式项目>
  5. 基于区块链技术,电子商务平台将提高安全性和透明度
  6. 新一代iPad比iPad2热的5大原因
  7. runtime-compiler和runtime-only的区别
  8. oracle 修改字符集 修改为ZHS16GBK
  9. vue:Failed to resolve component:xxx
  10. ENVI遥感影像解译制作土地利用专题图