分享

看Python小白如何在十天内学会独立爬取QQ无损音乐

 豆宝有虫吃 2019-08-09

所以这里将创建3个文件夹,分别用于存放这三种音乐文件。

新建一个名为download_qqMusic_by_songname.py的模块文件,在其中添加如下代码▼:

1import os
2
3# 创建歌曲下载目录,3个品质音乐文件分开存放
4DOWNLOAD_DIRS = ['D:/qqMusic/单曲/' + x for x in ['HQ', 'SQ', 'VQ']]
5for download_dir in DOWNLOAD_DIRS:
6 if not os.path.exists(download_dir):
7 os.makedirs(download_dir)

代码注解>>

Line1:导入内置os模块。

Line4:变量DOWNLOAD_DIRS存储3个目录路径名,因其在后面多处(包括函数内部)会用到,所以应声明为“公共变量”,而Python中一般使用全大写字母来命名公共变量。

后面是一个列表推导式,关于它的具体用法一会再提。

这里变量DOWNLOAD_DIRS得到的值是:

1['D:/qqMusic/单曲/HQ', 'D:/qqMusic/单曲/SQ', 'D:/qqMusic/单曲/VQ']

Line5~7:使用一个for循环语句来自动创建文件夹

<Tips>: 如不明白,可回顾《Day4》中 4.6.2 文件夹操作 小节的内容。

如果执行上面的代码,便会在D:盘目录下自动生成3个文件夹(如下图▼):

看Python小白如何在十天内学会独立爬取QQ无损音乐

▲<上图>QQ音乐_代码编写_创建下载目录

下面再看看什么是 列表推导式

6.2 列表推导式

列表推导式亦称“列表解析”,是一种能按照一定规则从序列中生成新列表的方法。

而这个「规则」可以是运算调用方法嵌套函数等等复杂表达式,还可使用if语句对结果进行过滤。

它是Python语法中既简单方便,且非常有特色的用法,因为它最终只有一行表达式,无论其内部复杂程度如何。

同时,你也可简单理解它为for循环语句的衍生用法。

基本用法:

1# range(5)是由0~4整数组成的list,对其每个元素计算2次幂后生成一个新的list
2>>> [x**2 for x in range(5)]
3[0, 1, 4, 9, 16]
4
5# 对其每个元素乘以2并加1后生成一个新的list
6>>> [x*2+1 for x in range(5)]
7[1, 3, 5, 7, 9]

这里的x是约定俗成的变量名,当然你也可换成其他字符。

改变元素数据类型:

1# range(5)中元素为数字,生成新list中元素类型变为字符串
2>>> ['a'+str(x) for x in range(5)]
3['a0', 'a1', 'a2', 'a3', 'a4']
4
5# range(5)中元素为数字,生成新list中元素类型变为列表
6>>> [[x, x*-3] for x in range(5)]
7[[0, 0], [1, -3], [2, -6], [3, -9], [4, -12]]

对元素调用方法:

1# 删除原list中元素头尾的空格
2>>> food = [' 米饭 ', ' 面条', ' 面 包 ', '汉堡 ']
3>>> [x.strip() for x in food]
4['米饭', '面条', '面 包', '汉堡']

strip()是字符串方法,用于移除字符串头尾空格或换行符,但中间的不删除。

用if子句过滤:

1# 从0~9中筛选偶数,组成新列表
2>>> [x for x in range(10) if x%2 == 0] # 后面条件判断也可以写成“if not x%2”
3[0, 2, 4, 6, 8]
4
5# 筛选列表lst中小于5的元素,其值加上10后组成新列表
6>>> lst = [8, 2, 5, 1, 7, 12, 3, 20]
7>>> [x + 10 for x in lst if x < 5]
8[12, 11, 13]

上面的if子句均用在for语句之后,用于过滤筛选满足条件的元素,新列表元素个数可能减少

而将if...else形式子句放在for语句之前,还能实现根据条件对元素重新赋值,而新列表元素个数不变。如:

1# 能被3整除的元素取原值,否则取相反数
2>>> [x if x%3 == 0 else -x for x in range(10)]
3[0, -1, -2, 3, -4, -5, 6, -7, -8, 9]

多个for子句:

列表解析中可包含多个for子句,相当于多层普通的for循环语句块,循环顺序从前至后。例:

1>>> lst1 = [2, -5, 8]
2>>> lst2 = [-1, 4, 0.6]
3# 下面的先读取lst1第一个元素,再依次读取lst2中三个元素;然后循环去读取lst1第二个元素,再依次读取lst2中三个元素。。。
4>>> [x + y for x in lst1 for y in lst2]
5[1, 6, 2.6, -6, -1, -4.4, 7, 12, 8.6]
6# 假如lst1与lst2变换位置后,结果则截然不同
7>>> [x + y for x in lst2 for y in lst1]
8[1, -6, 7, 6, -1, 12, 2.6, -4.4, 8.6]

再比如三个for子句:

1>>> lst1 = ['X1', 'X2']; lst2 = ['Y1', 'Y2']; lst3 = ['Z1', 'Z2']
2>>> [x + y + z for x in lst1 for y in lst2 for z in lst3]
3['X1Y1Z1', 'X1Y1Z2', 'X1Y2Z1', 'X1Y2Z2', 'X2Y1Z1', 'X2Y1Z2', 'X2Y2Z1', 'X2Y2Z2']

当然,上面的也等价于这样写:

1>>> lst = []
2>>> for x in lst1:
3... for y in lst2:
4... for z in lst3:
5... lst.append(x + y +z)
6...
7>>> lst
8['X1Y1Z1', 'X1Y1Z2', 'X1Y2Z1', 'X1Y2Z2', 'X2Y1Z1', 'X2Y1Z2', 'X2Y2Z1', 'X2Y2Z2']

很显然,使用列表推导式的写法更简洁、易阅读,一行代码全部搞定!

嵌套列表解析:

这个很容易与上面的“多个for子句”搞混淆,实际上嵌套列表解析相当于在一个列表推导式的前部分结果位置处又嵌入一个列表推导式。

仍以上前一个例子进行对比说明:

1>>> lst1 = [2, -5, 8]; lst2 = [-1, 4, 0.6]
2>>> [[x + y for x in lst1] for y in lst2] # 嵌套列表解析
3[[1, -6, 7], [6, -1, 12], [2.6, -4.4, 8.6]] # 结果1
4# 上前一个例子的结果如下
5>>> [x + y for x in lst1 for y in lst2] # 多个for子句的列表解析
6[1, 6, 2.6, -6, -1, -4.4, 7, 12, 8.6] # 结果2

可以看出,“结果1”是一个嵌套列表,有3个元素(每个元素又是一个包含3个元素的列表);而“结果2”是一个普通列表,有9个元素。

且在循环运算顺序上,“结果1”是从后往前,即先外层后内层;而“结果2”是从前往后

利用“嵌套列表解析”的特性,我们一行代码即可轻松对一个矩阵进行转置。如:

1# 使用“嵌套列表解析”将3X4的矩阵列表转置成4X3的矩阵列表
2>>> matrix = [[11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34]]
3>>> [[x[i] for x in matrix] for i in range(4)]
4[[11, 21, 31], [12, 22, 32], [13, 23, 33], [14, 24, 34]]

否则,可能需下面繁琐的多行代码才能实现:

1# 使用“普通for语句”将3X4的矩阵列表转置成4X3的矩阵列表
2>>> matrix = [[11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34]]
3>>> transposed = []
4>>> for i in range(4):
5... transposed_temp = []
6... for x in matrix:
7... transposed_temp.append(x[i])
8... transposed.append(transposed_temp)
9...
10>>> transposed
11[[11, 21, 31], [12, 22, 32], [13, 23, 33], [14, 24, 34]]

关于“列表推导式”,实际上还能组合、衍生出更高级的用法,只要你敢想。

比如还能有“字典推导式”

1# 用字典方式写出数字1~9各自的平方和
2>>> {x: x**2 for x in range(1, 10)}
3{1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

但作为编程者,首要目的应是实现功能,其次是让代码简单易懂,而并非要代码多么炫酷。

所以,我们更应结合自身需要选择适合的方法来达到目的。

现在再回头看6.1小节中Line4的代码▼,是不是就明白了呢?

1DOWNLOAD_DIRS = ['D:/qqMusic/单曲/' + x for x in ['HQ', 'SQ', 'VQ']]

6.3 读取歌单文件

这里的“歌单文件”即上一章中提到的《SongsList.txt》,是一个普通的文本文档,用于存储我们希望搜索并下载的歌曲名称

类似这样▼:

看Python小白如何在十天内学会独立爬取QQ无损音乐

▲<上图>QQ音乐_代码编写_SongsList.txt

每一行都是自行添加的一首歌曲名称/关键词,现在我们要用Python从中读取关键词,并返回一个列表

这里,定义一个名为get_keywords()的函数来实现以上功能。代码如下▼:

 1# 定义函数,从SongsList.txt中读取需下载歌曲关键词
2import sys
3
4def get_keywords():
5 fn = './SongsList.txt' # 在.py根目录下创建.txt文件,关键词以回车为分隔标识符
6 if os.path.exists(fn):
7 with open(fn, 'r') as f: # 以“只读”模块打开文件
8 keywords = [x.strip() for x in f if x.strip()]
9 else:
10 print('<Error>: SongsList.txt文件不存在!')
11 sys.exit()
12 return keywords # 返回对象为字符串的列表

代码注解>>

Line5:变量fn用于存储歌单文档的文件名,./表示在当前目录下。(你也可更换)

Line6 & Line9:对fn文件作个判断,如果存在则读取数据;否则打印提示“不存在”,并退出程序。

Line8:变量keywords用于存放经读取并处理后的“关键词”。后面的“列表推导式”实现提取关键词并返回成列表的功能。

值得注意的是两个strip()的使用,左边的是对每行的“关键词”删除前后空格&换行;而右边的是判断每一行是否为空。

假如不加这两个strip()会有什么影响呢?以上图《SongsList.txt》为例:

1# 原代码
2>>> keywords = [x.strip() for x in f if x.strip()]
3>>> keywords
4['你的酒馆对我打了烊', '海阔天空', '银河里最像的', '来自天堂的魔鬼', '等你下课']
5
6# 删除右边的'strip()'
7>>> keywords = [x.strip() for x in f]
8>>> keywords
9['你的酒馆对我打了烊', '', '海阔天空', '银河里最像的', '来自天堂的魔鬼', '', '等你下课', '', '']
10
11# 删除左边的'strip()'
12>>> keywords = [x for x in f if x.strip()]
13>>> keywords
14['你的酒馆对我打了烊', '海阔天空', '银河里最像的', '来自天堂的魔鬼', '等你下课']
15
16# 同时删除左/右两个'strip()'
17>>> keywords = [x for x in f]
18>>> keywords
19['你的酒馆对我打了烊',
20 '',
21 '海阔天空',
22 '银河里最像的',
23 '来自天堂的魔鬼',
24 '',
25 '等你下课',
26 '',
27 '']

Line11:sys.exit()是退出应用程序,需要import sys模块,见Line2

Line12:最后return keywords函数返回keywords,是一个由“关键词”组成的列表。

6.4 回顾小结

本章主要完成了2个步骤,即“创建下载目录”“读取歌单文件”的代码编写,并引出了”列表推导式“的概念。

所涉及内容并不多,但“列表推导式”确实是Python非常好用的特性之一,大家可多理解、多试验、多应用

6.5 重点笔记

6.5.1 列表推导式

关于「列表推导式」及「字典推导式」的概念请参见6.2小节。

6.5.2 strip()方法

strip()方法用于移除字符串头尾指定的字符(默认为空白符,包括空格符、换行符 、制表符 、回车符 )或字符序列,但中间的不删除。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多