一、前言


前文说过我的设计师小伙伴的设计需求,他想做一个披头士乐队历年专辑的瀑布图。

通过搜索,发现网易云音乐上有比较全的历年专辑信息加配图,图片质量还可以,虽然有大有小。

我的例子怎么都是爬取图片?(谁让你总是跟设计师小伙伴一起玩耍。。。)看来图片对于设计师来说还是有着很深的情节,那就看他用这些图片能做出什么样的作品啦,期待一下,后续会展示一下他的作品。

其实爬取网易云音乐跟之前爬取的网站稍稍有点不同,当然,爬虫写的多了就觉得套路都是固定的,见招拆招而已。

二、运行环境


我的运行环境如下:

  • 系统版本

    Windows10。

  • Python版本

    Python3.5,推荐使用Anaconda 这个科学计算版本,主要是因为它自带一个包管理工具,可以解决有些包安装错误的问题。去Anaconda官网,选择Python3.5版本,然后下载安装。

  • IDE

    我使用的是PyCharm,是专门为Python开发的IDE。这是JetBrians的产品,点我下载

三、实战


上面提到过,网易云音乐的网页跟普通的网页相比主要有两点不同:

  • 网页是 js 动态加载的
  • 使用了iframe框架

所以,

首先,网页请求不能使用requests库,需要使用Selenium + PhatomJS。

其次,使用Selenium + PhatomJS后,还需要针对 iframe 做特定处理。

废话不多说,看实际操作步骤:

首先打开网页 http://music.163.com

在右上角的搜索框中输入“The Beatles”,然后会有一个下拉选项,选择歌手 The Beatles (红框中的内容)。

然后看到如下页面,选择红框中的“所有专辑”,点击。

这样就会看见所有的专辑列表,以及下方的翻页按钮。

我们需要的就是所有专辑的图片、专辑名和专辑出版时间。看到这就可以构想一下爬虫的爬取逻辑了。定位到该页面,然后获取页码,然后挨个请求页面来爬取页面中的内容。

点击一下翻页按钮看看url 有没有什么规律。

点击第二页后,看到上面的地址栏!!!看到这个地址栏我都懒得翻页了。。。

limit 参数是限制一个页面加载专辑的个数

offset 参数是前面过滤多少个专辑,现在是一页12个专辑,所以第二页是offset=12,第三页offset=24,以此类推。。。

一共9页,一页12个,也不到120个。So... ... 改一下url 就不用翻页了!!

limit 参数等于120,offset 参数 等于0,就搞定了! 输入下面的url,看看是不是所有的专辑都加载出来了。

http://music.163.com/#/artist/album?id=101988&limit=120&offset=0

下面就开始爬虫代码了。

这里我们会用到上一篇博文中写好的几个工具方法:

    def save_img(self, url, file_name): ##保存图片
print('开始请求图片地址,过程会有点长...')
img = self.request(url)
print('开始保存图片')
f = open(file_name, 'ab')
f.write(img.content)
print(file_name,'图片保存成功!')
f.close() def request(self, url): #封装的requests 请求
r = requests.get(url) # 像目标url地址发送get请求,返回一个response对象。有没有headers参数都可以。
return r def mkdir(self, path): ##这个函数创建文件夹
path = path.strip()
isExists = os.path.exists(path)
if not isExists:
print('创建名字叫做', path, '的文件夹')
os.makedirs(path)
print('创建成功!')
return True
else:
print(path, '文件夹已经存在了,不再创建')
return False def get_files(self, path): #获取文件夹中的文件名称列表
pic_names = os.listdir(path)
return pic_names

OK, 开始我们的爬虫逻辑部分:

这里值得注意的是,该页面使用frame 框架,使用Selenium + PhantomJS 后并不会加载iframe 框架中的网页内容。iframe 框架相当于在页面中又加载了一个页面,需要使用Selenium 的 switch_to.frame() 方法加载(官网给的方法是switch_to_frame(),但是IDE提醒使用前面的方法替代该方法)。

看下面的网页结构,iframe的id是“g_iframe”:

加载 iframe 框架中的内容:
```
driver = webdriver.PhantomJS()
driver.get(self.init_url)
driver.switch_to.frame("g_iframe")
html = driver.page_source
```

然后找到所有的封面元素:

根据上图的网页结构可以看出,所有的专辑信息都在ul 标签里面,每一个专辑在一个li 标签里。li 标签中包含了图片url、专辑名字、以及专辑时间。

抓取其中的内容就好了。

all_li = BeautifulSoup(html, 'lxml').find(id='m-song-module').find_all('li')

for li in all_li:
album_img = li.find('img')['src']
album_name = li.find('p', class_='dec')['title']
album_date = li.find('span', class_='s-fc3').get_text()

这里获取到的图片url 依然是有图片宽高参数的,所以要过滤宽高参数:

http://p4.music.126.net/pLA1GX0KtU-vU4ZA6Cr-OQ==/1401877340532770.jpg?param=120y120

把问号后面的参数过滤掉:

end_pos = album_img.index('?')  #找到问号的位置
album_img_url = album_img[:end_pos] #截取问号之前的内容

图片命名逻辑:专辑时间 + 专辑名。

专辑名可能有一些特殊字符,需要替换掉!

photo_name = album_date + ' - ' + album_name.replace('/','').replace(':',',') + '.jpg'

再使用上一篇博文例子中的去重逻辑,修改后的爬虫逻辑部分如下:

    def spider(self):
print("Start!")
driver = webdriver.PhantomJS()
driver.get(self.init_url)
driver.switch_to.frame("g_iframe")
html = driver.page_source self.mkdir(self.folder_path) # 创建文件夹
print('开始切换文件夹')
os.chdir(self.folder_path) # 切换路径至上面创建的文件夹 file_names = self.get_files(self.folder_path) # 获取文件夹中的所有文件名,类型是list all_li = BeautifulSoup(html, 'lxml').find(id='m-song-module').find_all('li')
# print(type(all_li)) for li in all_li:
album_img = li.find('img')['src']
album_name = li.find('p', class_='dec')['title']
album_date = li.find('span', class_='s-fc3').get_text()
end_pos = album_img.index('?')
album_img_url = album_img[:end_pos] photo_name = album_date + ' - ' + album_name.replace('/','').replace(':',',') + '.jpg'
print(album_img_url, photo_name) if photo_name in file_names:
print('图片已经存在,不再重新下载')
else:
self.save_img(album_img_url, photo_name)

其实相对于上篇博文的例子,这个爬虫的逻辑部分还是挺简洁的。

最后上一个完整的代码: 也可以从GitHub下载

from selenium import webdriver
from bs4 import BeautifulSoup
import requests
import os class AlbumCover(): def __init__(self):
self.init_url = "http://music.163.com/#/artist/album?id=101988&limit=120&offset=0" #请求网址
self.folder_path = "C:\D\TheBeatles" #想要存放的文件目录 def save_img(self, url, file_name): ##保存图片
print('开始请求图片地址,过程会有点长...')
img = self.request(url)
print('开始保存图片')
f = open(file_name, 'ab')
f.write(img.content)
print(file_name, '图片保存成功!')
f.close() def request(self, url): # 封装的requests 请求
r = requests.get(url) # 像目标url地址发送get请求,返回一个response对象。有没有headers参数都可以。
return r def mkdir(self, path): ##这个函数创建文件夹
path = path.strip()
isExists = os.path.exists(path)
if not isExists:
print('创建名字叫做', path, '的文件夹')
os.makedirs(path)
print('创建成功!')
return True
else:
print(path, '文件夹已经存在了,不再创建')
return False def get_files(self, path): # 获取文件夹中的文件名称列表
pic_names = os.listdir(path)
return pic_names def spider(self):
print("Start!")
driver = webdriver.PhantomJS()
driver.get(self.init_url)
driver.switch_to.frame("g_iframe")
html = driver.page_source self.mkdir(self.folder_path) # 创建文件夹
print('开始切换文件夹')
os.chdir(self.folder_path) # 切换路径至上面创建的文件夹 file_names = self.get_files(self.folder_path) # 获取文件夹中的所有文件名,类型是list all_li = BeautifulSoup(html, 'lxml').find(id='m-song-module').find_all('li')
# print(type(all_li)) for li in all_li:
album_img = li.find('img')['src']
album_name = li.find('p', class_='dec')['title']
album_date = li.find('span', class_='s-fc3').get_text()
end_pos = album_img.index('?')
album_img_url = album_img[:end_pos] photo_name = album_date + ' - ' + album_name.replace('/', '').replace(':', ',') + '.jpg'
print(album_img_url, photo_name) if photo_name in file_names:
print('图片已经存在,不再重新下载')
else:
self.save_img(album_img_url, photo_name) album_cover = AlbumCover()
album_cover.spider()

执行结果:

看看文件夹里面什么样:

历年的专辑封面已经到手啦,还有专辑的名称和发行日期。

四、后语


这个实战很好的运用了咱们之前讲解的知识:

  • 使用Selenium + PhatomJS 抓取动态页面
  • 使用Selenium 的switch_to.frame() 加载 iframe 中的内容
  • 使用requests 库获取图片
  • 使用BeautifulSoup 库解析抓取网页内容。
  • 使用os 库创建文件夹和获取文件夹中的文件名称列表

使用现有的知识编写简单的爬虫是不成问题了。接下来会讲讲爬虫框架,就从现在比较流行的Scrapy 框架讲起吧。

我得找找比较合适的例子,工作中用到的爬虫不太方便贴上来,有合适的实例我会继续更新。

有任何的疑问可以留言,就先酱紫吧。

See you then.

Python爬虫小白入门(六)爬取披头士乐队历年专辑封面-网易云音乐的更多相关文章

  1. Python爬虫实战一之爬取糗事百科段子

    大家好,前面入门已经说了那么多基础知识了,下面我们做几个实战项目来挑战一下吧.那么这次为大家带来,Python爬取糗事百科的小段子的例子. 首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把 ...

  2. Python爬虫实战二之爬取百度贴吧帖子

    大家好,上次我们实验了爬取了糗事百科的段子,那么这次我们来尝试一下爬取百度贴吧的帖子.与上一篇不同的是,这次我们需要用到文件的相关操作. 前言 亲爱的们,教程比较旧了,百度贴吧页面可能改版,可能代码不 ...

  3. 转 Python爬虫实战二之爬取百度贴吧帖子

    静觅 » Python爬虫实战二之爬取百度贴吧帖子 大家好,上次我们实验了爬取了糗事百科的段子,那么这次我们来尝试一下爬取百度贴吧的帖子.与上一篇不同的是,这次我们需要用到文件的相关操作. 本篇目标 ...

  4. 转 Python爬虫实战一之爬取糗事百科段子

    静觅 » Python爬虫实战一之爬取糗事百科段子 首先,糗事百科大家都听说过吧?糗友们发的搞笑的段子一抓一大把,这次我们尝试一下用爬虫把他们抓取下来. 友情提示 糗事百科在前一段时间进行了改版,导致 ...

  5. python爬虫学习01--电子书爬取

    python爬虫学习01--电子书爬取 1.获取网页信息 import requests #导入requests库 ''' 获取网页信息 ''' if __name__ == '__main__': ...

  6. python爬虫:了解JS加密爬取网易云音乐

    python爬虫:了解JS加密爬取网易云音乐 前言 大家好,我是"持之以恒_liu",之所以起这个名字,就是希望我自己无论做什么事,只要一开始选择了,那么就要坚持到底,不管结果如何 ...

  7. Python爬虫:为什么你爬取不到网页数据

    前言: 之前小编写了一篇关于爬虫为什么爬取不到数据文章(文章链接为:Python爬虫经常爬不到数据,或许你可以看一下小编的这篇文章), 但是当时小编也是胡乱编写的,其实里面有很多问题的,现在小编重新发 ...

  8. Python爬虫小白入门(四)PhatomJS+Selenium第一篇

    一.前言 在上一篇博文中,我们的爬虫面临着一个问题,在爬取Unsplash网站的时候,由于网站是下拉刷新,并没有分页.所以不能够通过页码获取页面的url来分别发送网络请求.我也尝试了其他方式,比如下拉 ...

  9. Python爬虫实战一之爬取QQ音乐

    一.前言   前段时间尝试爬取了网易云音乐的歌曲,这次打算爬取QQ音乐的歌曲信息.网易云音乐歌曲列表是通过iframe展示的,可以借助Selenium获取到iframe的页面元素, 而QQ音乐采用的是 ...

随机推荐

  1. CSS中选择器优先级顺序实战讲解

    原文:CSS中选择器优先级顺序实战讲解 我们有些程序猿在给一个元素(比如div)应用样式的时候,会有一些疑问,为什么我写在后面的样式不能覆盖前面的样式呢,不是说CSS是层叠样式表吗? 如果你在开发中也 ...

  2. 【【分享】深入浅出WPF全系列教程及源码 】

    因为原书作者的一再要求,在此声明,本书中的部分内容引用了原书名为<深入浅出WPF>的部分内容,假设博文不能满足你现有的学习须要,能够购买正版图书! 本人10月份提出离职,可是交接非常慢,预 ...

  3. Android项目--XML解析

    对于xml文件,一般有两种解析方式: -----pull解析-------- -----Sax解析------- 如果xml文件是本地文件,那么就好说了 AssetManager assetManag ...

  4. WCF、Web API、WCF REST、Web Service

    WCF.Web API.WCF REST.Web Service 区别 Web Service It is based on SOAP and return data in XML form. It ...

  5. JavaScript实例技巧精选(9)—计算器实例1

    >>点击这里下载完整html源码<< 这是截图: 利用Javascript和html实现的一个计算器实例,核心代码如下: <script language="J ...

  6. Hdu 1016 Prime Ring Problem (素数环经典dfs)

    Prime Ring Problem Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  7. [置顶] 如何使用c3p0+spring连接oracle数据库

    1. 首先是jdbc.properties属性文件的编写,便于数据库移植: datasource.driverClassName=oracle.jdbc.driver.OracleDriver dat ...

  8. 对student进行增删改

    drop package TechEd_pkg_Student; CREATE OR REPLACE PACKAGE TechEd_pkg_Student AS FUNCTION F_CREATE(p ...

  9. Linux下监控磁盘空间的四个命令

    无论是运行简单的Linux桌面还是大型Linux服务器,都需要了解可供应用程序使用的空间,并跟踪系统的磁盘使用情况.下面介绍四个核心命令行命令来管理Linux系统上的介质环境. 一.mount命令 m ...

  10. 使用Repository模式构建数据库访问层

    使用Repository模式构建数据库访问层 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程[二]——使用Repository模式构建数据库访问层 系列导航地址http:// ...