# IT碎片笔记 **Repository Path**: skyqi/it-fragment-notes ## Basic Information - **Project Name**: IT碎片笔记 - **Description**: 记录it开发碎片笔记 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-11-24 - **Last Updated**: 2022-11-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## PYTHON ### 基础版 #### * 写.md时遇到# ``` (1)利用HTML语法,用“#”表示“#”,即输入“#C#” ; (2)利用“\”,输入“#C\#”(要注意在“\”和“#”后面有一个空格,否则输出效果为“C\”)。 ``` #### * 利用特殊字符编码输出特殊符号 ``` print(' ',chr(9477)*27,' ') print(chr(9479),' '*4,'天道不一定酬勤,深度思考比勤奋工作更重要!',' '*4,chr(9479)) print(' ',chr(9477)*27,' ') ``` ### *pandas* 是基于NumPy 的一种工具 #### * 数据分析_pandas_导入数据 ``` -- coding: utf-8 -- @Time : 2020/8/23 0:46 @公众号 :Python自动化办公社区 @File : 18数据分析pandas_导入数据.py @Software: PyCharm @Description: pip install pandas import pandas as pd 一维数据 one_d = pd.Series(['a','b','c','d']) print(one_d) 二维数据 two_d = pd.DataFrame({ '学号': ['A2', 'A3'], '姓名': ['刘二', '张三'], '语文': ['68', '68'], }) print(two_d) ``` #### * 数据分析_pandas_数据透视表 ``` # -*- coding: utf-8 -*- # @Time : 2020/8/23 1:23 # @File : 19_数据分析_pandas_数据透视表.py # @Software: PyCharm # @Description: # pip install numpy import pandas as pd import numpy as np r_file = pd.ExcelFile('student.xls') data = r_file.parse('Sheet1') # print(data) # index代表行的名称,columns代表列的名称 # aggfunc=np.sum 求和 # margins=True 总计 # 求各省的分数和 pt_s = pd.pivot_table(data, index=['省份'], aggfunc=np.sum, margins=True) # aggfunc=np.sum 求和,默认是平均值 # print(pt_s) # 全部显示行和列 # pt_s.set_option('display.max_rows', None) # pt_s.set_option('display.max_columns', None) # 求各省的个数 pt_n = pd.pivot_table(data, index=['省份'], aggfunc=np.size, margins=True) # aggfunc=np.sum 求和,默认是平均值 print(pt_n) # # print(pt_s.iat[0, 0]) # print(pt_n.iat[0, 0]) ``` #### * 分块下载,特点速度快 > 1. from __future__ import annotations > 2. \# 用于显示进度条 > 3. from tqdm import tqdm > 4. \# 用于发起网络请求 > 5. import requests > 6. \# 用于多线程操作 > 7. import multitasking > 8. import signal > 9. import asyncio > 10. import time > 11. \# 导入 retry 库以方便进行下载出错重试 > 12. from retry import retry > 13. > 14. signal.signal(signal.SIGINT, multitasking.killall) > 15. > 16. \# 请求头 > 17. headers = { > 18. 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE' > 19. } > 20. \# 定义 1 MB 多少为 B > 21. MB = 1024 ** 2 > 22. > 23. *def* split(start: int, end: int, step: int) -> list[tuple[int, int]]: > 24. \# 分多块 > 25. parts = [(start, *min*(start + step, end)) > 26. ​ for start in *range*(0, end, step)] > 27. return parts > 28. > 29. *def* get_file_size(url: str, raise_error: bool = *False*) -> int: > 30. ''' > 31. 获取文件大小 > 32. Parameters > 33. \---------- > 34. url : 文件直链 > 35. raise_error : 如果无法获取文件大小,是否引发错误 > 36. Return > 37. \------ > 38. 文件大小(B为单位) > 39. 如果不支持则会报错 > 40. ''' > 41. response = requests.head(url) > 42. file_size = response.headers.get('Content-Length') > 43. if file_size is *None*: > 44. ​ if raise_error is *True*: > 45. ​ raise ValueError('该文件不支持多线程分段下载!') > 46. ​ return file_size > 47. return int(file_size) > 48. > 49. > 50. *def* download(url: str, file_name: str, retry_times: int = 3, each_size=16 * MB) -> *None*: > 51. \# time.sleep(3) > 52. ''' > 53. 根据文件直链和文件名下载文件 > 54. Parameters > 55. \---------- > 56. url : 文件直链 > 57. file_name : 文件名 > 58. retry_times: 可选的,每次连接失败重试次数 > 59. Return > 60. \------ > 61. None > 62. ''' > 63. f = *open*(file_name, 'wb') > 64. file_size = get_file_size(url) > 65. > 66. @retry(tries=retry_times) > 67. @multitasking.task > 68. *def* start_download(start: int, end: int) -> *None*: > 69. ​ ''' > 70. ​ 根据文件起止位置下载文件 > 71. ​ Parameters > 72. ​ \---------- > 73. ​ start : 开始位置 > 74. ​ end : 结束位置 > 75. ​ ''' > 76. ​ _headers = headers.copy() > 77. ​ \# 分段下载的核心 > 78. ​ _headers['Range'] = *f*'bytes={start}-{end}' > 79. ​ \# 发起请求并获取响应(流式) > 80. ​ response = session.get(url, headers=_headers, stream=*True*) > 81. ​ \# 每次读取的流式响应大小 > 82. ​ chunk_size = 128 > 83. ​ \# 暂存已获取的响应,后续循环写入 > 84. ​ chunks = [] > 85. ​ for chunk in response.iter_content(chunk_size=chunk_size): > 86. ​ \# 暂存获取的响应 > 87. ​ chunks.append(chunk) > 88. ​ \# 更新进度条 > 89. ​ bar.update(chunk_size) > 90. ​ \# print(chunk) > 91. ​ f.seek(start) > 92. ​ for chunk in chunks: > 93. ​ f.write(chunk) > 94. ​ f.flush() > 95. ​ \# 释放已写入的资源 > 96. > 97. ​ del chunks > 98. > 99. session = requests.Session() > 100. \# 分块文件如果比文件大,就取文件大小为分块大小 > 101. each_size = *min*(each_size, file_size) > 102. > 103. \# 分块 > 104. parts = split(0, file_size, each_size) > 105. *print*(*f*'文件名:{file_name},分块数:{*len*(parts)}') > 106. \# 创建进度条 > 107. bar = tqdm(total=file_size, desc=*f*'下载文件:{file_name}') > 108. n = 0 > 109. for part in parts: > 110. ​ start, end = part > 111. ​ start_download(start, end) > 112. ​ n = n+1 > 113. ​ \# print(f'次数:{n/len(parts)*100}%') > 114. \# 等待全部线程结束 > 115. multitasking.wait_for_tasks() > 116. f.flush() > 117. f.close() > 118. > 119. bar.close() > 120. > 121. > 122. if "__main__" == __name__: > 123. url = 'http://www.90ts.com/softdownload/xiguaweb.exe' > 124. file_name = 'xiguaweb.2021.exe' > 125. \# 开始下载文件 > 126. download(url, file_name) #### * matplotlib_画折线图、柱状图、饼图 ``` # -*- coding: utf-8 -*- # @Time : 2020/8/23 1:25 # @File : 20_matplotlib_画折线图、柱状图、饼图.py # @Software: PyCharm # @Description: # pip install matplotlib import matplotlib.pyplot as mplt # 支持中文 mplt.rcParams['font.sans-serif'] = ['SimHei'] date = ['2020/7/21','2020/7/22','2020/7/23',] yue = [10,70,30] min = [40,50,60] # 折线图 # mplt.plot(date,yue,color='red',label='广东') # mplt.plot(date,min,color='blue',label='福建') # mplt.title('降雨量') # mplt.xlabel('日期') # mplt.ylabel('降雨量') # mplt.legend() # mplt.show() # 柱状图 # mplt.bar(date,yue,color='red',label='广东') # mplt.bar(date,min,color='black',label='广东') # mplt.legend() # mplt.show() # 水平柱状图 # mplt.barh(date,yue,color='red',label='广东') # mplt.legend() # mplt.show() # 饼图 data = [1,2] province = ['广东','福建'] colors = ['red','blue'] mplt.pie(x=data,labels=province,colors=colors) mplt.legend() mplt.show() ``` #### * 数据可视化_pandas_matlpotlib_excel数据分析 ``` # -*- coding: utf-8 -*- # @Time : 2020/8/23 1:51 # @File : 21_数据可视化_pandas_matlpotlib_excel数据分析.py # @Software: PyCharm # @Description: import pandas as pd import numpy as np import matplotlib.pyplot as mplt r_file = pd.ExcelFile('student.xls') data = r_file.parse('Sheet1') # 求各省的个数 pt_n = pd.pivot_table(data, index=['省份'], aggfunc=np.size) # aggfunc=np.sum 求和,默认是平均值 mplt.rcParams['font.sans-serif'] = ['SimHei'] pt_n.plot(kind='bar') # 修改 # index的倾斜角度 mplt.xticks(rotation=45) mplt.title('各省数量') mplt.xlabel('省份') mplt.ylabel('个数') mplt.legend() mplt.show() ``` ### * 一键抓出PPT中的所有文字 ``` #提取所有文本字符 from pptx import Presentation data = [] prs = Presentation('data\制造业必修课.pptx') for slide in prs.slides: #遍历每页PPT for shape in slide.shapes: #遍历PPT中的每个形状 if shape.has_text_frame: #判断该是否包含文本,保证有文本才提取 for paragraph in shape.text_frame.paragraphs: #按文本框中的段落提取 data.append(paragraph.text) #提取一个段落的文本,就存到列表data中 #写入文本文件 TxtFile = open('data\制造业必修课.txt', 'w',encoding='utf-8') for i in data: TxtFile.write(i+'\n') #写入并换行,以保证正确分段 TxtFile.close() #保存 #写入word文件 import docx doc=docx.Document()#创建一个word文件对象 for i in data: doc.add_paragraph(i) #增加一个段落,并将列表中的一个字符串写入word文件 doc.save('data\制造业必修课.docx')#保存 ``` ### * 快速提取一串字符中的中文 ``` #!/usr/bin/env python # coding: utf-8 # 有时候,我们需要从一长串字符串中提取中文,比如如下这样的: # 我们可以看到,中文的长度参差不齐,在字符串中的位置也不固定。因此无论是用Excel自带的`left`,`right`,`mid` 函数,还是使用分列都无能为力。下面介绍通过Python的正则表达式,一键轻松提取中文。 # In[2]: from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = "all" # In[3]: #提取数据,以便后续处理 from openpyxl import load_workbook data=[] wb = load_workbook('data/data.xlsx') ws = wb.active for row in range(2,ws.max_row+1): #从第二行开始遍历excel文件所有行 info = ws['A' + str(row)].value data.append(info) data[:5] len(data) # 以上,我们先打开包含待处理的Excel文档,然后将待处理的字符串全部提取,存入列表`data`。然后通过`data[:5]`查看一下前5条数据,确保跟源文件相符。并通过`len(data)`查看数据的条数,也是与原文件是相符的。 # In[5]: #获取中文 import re #re是正则表达式模块 chinese_list=[] for i in data: chinese = re.findall('[\u4e00-\u9fa5]',i) #汉字的范围为"\u4e00-\u9fa5" chinese_list.append(''.join(chinese)) chinese_list[0] # In[6]: chinese # 正则表达式(regular expressions),也可以叫规则表达式,就是通过设定一些规则,从杂乱无章的字符串中捞取我们想要的数据,比如电话号码,邮件地址,邮政编码等。以上,先导入`re`模块,正则表达式的所有函数都在这个模块里面。然后新建一个列表`chinese_list`,以便存储抓取好的数据。这里,我们使用`findall()`在汉字的范围`\u4e00-\u9fa5`内抓取一个字符串中的所有汉字,这个方法返回的一组字符串中会包含被查找字符串中的所有匹配。也就是说只要是汉字,会逐个全部抓出,并将汉字以单个的形式存入列表,比如上面的`['集', '成', '天', '线']`。但是我们希望这四个字是连在一起的,所以在放入`chinese_list`列表之前,先用`join`方法将这几个字连接在一起了。`join`前面的引号内指定用什么符号连接,这里什么符号都没使用,即代表直接连接。下面我们展示一下用“&”符号连接一下,看看效果,其结果是`'集&成&天&线'`。 # In[7]: "&".join(chinese) # 连接好汉字后,我们将其写入原Excel表格第2列中,以便于第一列对应,代码如下: # In[5]: for row in range(2,ws.max_row+1): ws['B' + str(row)].value = chinese_list[row-2] wb.save('data/中文.xlsx') # 最后看看结果吧: # ![](images\result.png) ``` ### * 音乐播放器 ##### * demo.py ``` import requests import os # 文本处理 三种方法 # CSS 选择器 Xpath 处理结构化数据 re正则表达式 处理非结构化数据 from lxml import etree from urllib.request import urlretrieve url = 'http://www.htqyy.com/' # 获取页面源代码 def get_page(url): response = requests.get(url) html = response.text # print(html) return html # 打包成一个可以用xpath语法处理的对象 def parse_text(text): html = etree.HTML(text) return html # 针对首页写首页的解析语法 def html_index(html): # // 选取所有的节点 urls = html.xpath('//ul[@class="tagList clearfix"]/li/a/@href') # print(urls) all_url = [] for i in urls: # 完整的URL new_url = url + i all_url.append(new_url) return all_url # print(all_url) # 解析列表页面 def parse_list_page(list_html): # 提取音乐编号 music_num = list_html.xpath('//span[@class="title"]/a/@sid') # 提取音乐名字 music_name = list_html.xpath('//span[@class="title"]/a/@title') # print(music_name) music_url = [] for num in music_num: url = 'http://f2.htqyy.com/play7/%s/mp3/5'%num # print(url) music_url.append(url) music_dict = dict(zip(music_name,music_url)) # print(music_dict) return music_dict def down_music(name,down_url): try: urlretrieve(down_url,'./music/%s.mp3'%name) except: print("下载出错") def main(): text = get_page(url) html = parse_text(text) all_url = html_index(html) # print(html) for i in all_url: list_page = get_page(i) list_html = parse_text(list_page) music_dict = parse_list_page(list_html) for name in music_dict: # print(name) # print(music_dict[name]) print("正在下载:%s"%name) down_url = music_dict[name] down_music(name,down_url) # 如果程序在当前文件运行,就执行下面的代码 if __name__ == '__main__': main() ``` ##### * index.py ``` import requests import urllib import json word = '雨蝶' res1 = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w='+word) jm1 = json.loads(res1.text.strip('callback()[]')) jm1 = jm1['MNIST_data']['song']['list'] mids = [] songmids = [] srcs = [] songnames = [] singers = [] for j in jm1: try: mids.append(j['media_mid']) songmids.append(j['songmid']) songnames.append(j['songname']) singers.append(j['singer'][0]['name']) except: print('wrong') for n in range(0,len(mids)): res2 = requests.get('https://c.y.qq.com/base/fcgi-bin/fcg_music_express_mobile3.fcg?&jsonpCallback=MusicJsonCallback&cid=205361747&songmid='+songmids[n]+'&filename=C400'+mids[n]+'.m4a&guid=6612300644') jm2 = json.loads(res2.text) vkey = jm2['MNIST_data']['items'][0]['vkey'] srcs.append('http://dl.stream.qqmusic.qq.com/C400'+mids[n]+'.m4a?vkey='+vkey+'&guid=6612300644&uin=0&fromtag=66') print('For '+word+' Start download...') x = len(srcs) for m in range(0,x): print(str(m)+'***** '+songnames[m]+' - '+singers[m]+'.m4a *****'+' Downloading...') try: urllib.request.urlretrieve(srcs[m],'d:/music/'+songnames[m]+' - '+singers[m]+'.m4a') except: x = x - 1 print('Download wrong~') print('For ['+word+'] Download complete '+str(x)+'files !') ``` ##### * music.py ``` import os import pygame from tkinter import * import tkinter.filedialog from mutagen.id3 import ID3 root = Tk() root.geometry("400x400") listofsongs = [] realnames = [] v = StringVar() songlabel = Label(root, textvariable=v, width=35) index = 0 def nextsong(event): global index if index < len(listofsongs) - 1: index += 1 else: index = 0 pygame.mixer.music.load(listofsongs[index]) pygame.mixer.music.play() updatelabel() def previoussong(event): global index if index > 0 : index -= 1 else: index = len(listofsongs) - 1 pygame.mixer.music.load(listofsongs[index]) pygame.mixer.music.play() updatelabel() def stopsong(event): pygame.mixer.music.stop() v.set("") def updatelabel(): global index v.set(realnames[index]) def directorychooser(): directory = tkinter.filedialog.askdirectory() os.chdir(directory) for files in os.listdir(directory): if files.endswith('.mp3'): realdir = os.path.realpath(files) audio = ID3(realdir) realnames.append(audio['TIT2'].text[0]) listofsongs.append(files) # print(files) pygame.mixer.init() pygame.mixer.music.load(listofsongs[0]) pygame.mixer.music.play() directorychooser() label = Label(root, text="Music Player") label.pack() listbox = Listbox(root) listbox.pack() # List of songs realnames.reverse() for item in realnames: listbox.insert(0, item) realnames.reverse() nextbutton = tkinter.Button(root, text='Next Song') nextbutton.pack() previousbutton = tkinter.Button(root, text="Previous Song") previousbutton.pack() stopbutton = tkinter.Button(root, text="Stop Music") stopbutton.pack() nextbutton.bind("", nextsong) previousbutton.bind("", previoussong) stopbutton.bind('', stopsong) songlabel.pack() root.mainloop() ``` ##### * MusicPlayer.py ``` ''' Function: 音乐播放器 Author: Charles ''' import os import sys import time import random import configparser from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtMultimedia import * '''音乐播放器''' class musicPlayer(QWidget): def __init__(self): super().__init__() self.__initialize() '''初始化''' def __initialize(self): self.setWindowTitle('音乐播放器v0.1.0') self.setWindowIcon(QIcon('icon.ico')) self.songs_list = [] self.song_formats = ['mp3', 'm4a', 'flac', 'wav', 'ogg'] self.settingfilename = 'setting.ini' self.player = QMediaPlayer() self.cur_path = os.path.abspath(os.path.dirname(__file__)) self.cur_playing_song = '' self.is_switching = False self.is_pause = True # 界面元素 # --播放时间 self.label1 = QLabel('00:00') self.label1.setStyle(QStyleFactory.create('Fusion')) self.label2 = QLabel('00:00') self.label2.setStyle(QStyleFactory.create('Fusion')) # --滑动条 self.slider = QSlider(Qt.Horizontal, self) self.slider.sliderMoved[int].connect(lambda: self.player.setPosition(self.slider.value())) self.slider.setStyle(QStyleFactory.create('Fusion')) # --播放按钮 self.play_button = QPushButton('播放', self) self.play_button.clicked.connect(self.playMusic) self.play_button.setStyle(QStyleFactory.create('Fusion')) # --上一首按钮 self.preview_button = QPushButton('上一首', self) self.preview_button.clicked.connect(self.previewMusic) self.preview_button.setStyle(QStyleFactory.create('Fusion')) # --下一首按钮 self.next_button = QPushButton('下一首', self) self.next_button.clicked.connect(self.nextMusic) self.next_button.setStyle(QStyleFactory.create('Fusion')) # --打开文件夹按钮 self.open_button = QPushButton('打开文件夹', self) self.open_button.setStyle(QStyleFactory.create('Fusion')) self.open_button.clicked.connect(self.openDir) # --显示音乐列表 self.qlist = QListWidget() self.qlist.itemDoubleClicked.connect(self.doubleClicked) self.qlist.setStyle(QStyleFactory.create('windows')) # --如果有初始化setting, 导入setting self.loadSetting() # --播放模式 self.cmb = QComboBox() self.cmb.setStyle(QStyleFactory.create('Fusion')) self.cmb.addItem('顺序播放') self.cmb.addItem('单曲循环') self.cmb.addItem('随机播放') # --计时器 self.timer = QTimer(self) self.timer.start(1000) self.timer.timeout.connect(self.playByMode) # 界面布局 self.grid = QGridLayout() self.setLayout(self.grid) self.grid.addWidget(self.qlist, 0, 0, 5, 10) self.grid.addWidget(self.label1, 0, 11, 1, 1) self.grid.addWidget(self.slider, 0, 12, 1, 1) self.grid.addWidget(self.label2, 0, 13, 1, 1) self.grid.addWidget(self.play_button, 0, 14, 1, 1) self.grid.addWidget(self.next_button, 1, 11, 1, 2) self.grid.addWidget(self.preview_button, 2, 11, 1, 2) self.grid.addWidget(self.cmb, 3, 11, 1, 2) self.grid.addWidget(self.open_button, 4, 11, 1, 2) '''根据播放模式播放音乐''' def playByMode(self): if (not self.is_pause) and (not self.is_switching): self.slider.setMinimum(0) self.slider.setMaximum(self.player.duration()) self.slider.setValue(self.slider.value() + 1000) self.label1.setText(time.strftime('%M:%S', time.localtime(self.player.position()/1000))) self.label2.setText(time.strftime('%M:%S', time.localtime(self.player.duration()/1000))) # 顺序播放 if (self.cmb.currentIndex() == 0) and (not self.is_pause) and (not self.is_switching): if self.qlist.count() == 0: return if self.player.position() == self.player.duration(): self.nextMusic() # 单曲循环 elif (self.cmb.currentIndex() == 1) and (not self.is_pause) and (not self.is_switching): if self.qlist.count() == 0: return if self.player.position() == self.player.duration(): self.is_switching = True self.setCurPlaying() self.slider.setValue(0) self.playMusic() self.is_switching = False # 随机播放 elif (self.cmb.currentIndex() == 2) and (not self.is_pause) and (not self.is_switching): if self.qlist.count() == 0: return if self.player.position() == self.player.duration(): self.is_switching = True self.qlist.setCurrentRow(random.randint(0, self.qlist.count()-1)) self.setCurPlaying() self.slider.setValue(0) self.playMusic() self.is_switching = False '''打开文件夹''' def openDir(self): self.cur_path = QFileDialog.getExistingDirectory(self, "选取文件夹", self.cur_path) if self.cur_path: self.showMusicList() self.cur_playing_song = '' self.setCurPlaying() self.label1.setText('00:00') self.label2.setText('00:00') self.slider.setSliderPosition(0) self.is_pause = True self.play_button.setText('播放') '''导入setting''' def loadSetting(self): if os.path.isfile(self.settingfilename): config = configparser.ConfigParser() config.read(self.settingfilename) self.cur_path = config.get('MusicPlayer', 'PATH') self.showMusicList() '''更新setting''' def updateSetting(self): config = configparser.ConfigParser() config.read(self.settingfilename) if not os.path.isfile(self.settingfilename): config.add_section('MusicPlayer') config.set('MusicPlayer', 'PATH', self.cur_path) config.write(open(self.settingfilename, 'w')) '''显示文件夹中所有音乐''' def showMusicList(self): self.qlist.clear() self.updateSetting() for song in os.listdir(self.cur_path): if song.split('.')[-1] in self.song_formats: self.songs_list.append([song, os.path.join(self.cur_path, song).replace('\\', '/')]) self.qlist.addItem(song) self.qlist.setCurrentRow(0) if self.songs_list: self.cur_playing_song = self.songs_list[self.qlist.currentRow()][-1] '''双击播放音乐''' def doubleClicked(self): self.slider.setValue(0) self.is_switching = True self.setCurPlaying() self.playMusic() self.is_switching = False '''设置当前播放的音乐''' def setCurPlaying(self): self.cur_playing_song = self.songs_list[self.qlist.currentRow()][-1] self.player.setMedia(QMediaContent(QUrl(self.cur_playing_song))) '''提示''' def Tips(self, message): QMessageBox.about(self, "提示", message) '''播放音乐''' def playMusic(self): if self.qlist.count() == 0: self.Tips('当前路径内无可播放的音乐文件') return if not self.player.isAudioAvailable(): self.setCurPlaying() if self.is_pause or self.is_switching: self.player.play() self.is_pause = False self.play_button.setText('暂停') elif (not self.is_pause) and (not self.is_switching): self.player.pause() self.is_pause = True self.play_button.setText('播放') '''上一首''' def previewMusic(self): self.slider.setValue(0) if self.qlist.count() == 0: self.Tips('当前路径内无可播放的音乐文件') return pre_row = self.qlist.currentRow()-1 if self.qlist.currentRow() != 0 else self.qlist.count() - 1 self.qlist.setCurrentRow(pre_row) self.is_switching = True self.setCurPlaying() self.playMusic() self.is_switching = False '''下一首''' def nextMusic(self): self.slider.setValue(0) if self.qlist.count() == 0: self.Tips('当前路径内无可播放的音乐文件') return next_row = self.qlist.currentRow()+1 if self.qlist.currentRow() != self.qlist.count()-1 else 0 self.qlist.setCurrentRow(next_row) self.is_switching = True self.setCurPlaying() self.playMusic() self.is_switching = False '''run''' if __name__ == '__main__': app = QApplication(sys.argv) gui = musicPlayer() gui.show() sys.exit(app.exec_()) ``` ### * 爬取网易云音乐评论 ##### * get_comments.py ``` import requests # 网页请求 from bs4 import BeautifulSoup as Bs #提取数据 import re #字符串匹配 def get_song_comments(song_url, post_headers, post_data, song_name): res = requests.post(song_url, headers=post_headers, data=post_data) with open(song_name, "w", encoding="utf-8") as f: for index, item in enumerate(res.json()["hotComments"]): print("用户{}\t{}\n{}".format(index+1, item["user"]["nickname"], item["content"])) print() f.writelines("用户{}\t{}\n{}\n\n".format(index+1, item["user"]["nickname"], item["content"])) if item["beReplied"]: for sub_item in item["beReplied"]: print("用户{}\t{}\n{}".format("楼中楼:", sub_item["user"]["nickname"], sub_item["content"])) print() f.writelines("用户{}\t{}\n{}\n\n".format("楼中楼:", sub_item["user"]["nickname"], sub_item["content"])) def get_songs(playlist_url): """ :param playlist_url: 歌单url :return: [(song_name, song_id),] """ res = requests.get(playlist_url) soup = Bs(res.text, "html.parser") result = soup.find("ul", class_="f-hide") link_tags = result.find_all("a") songs = [(item.text, re.findall(r"\d+", item["href"])[0]) for item in link_tags] return songs if __name__ == '__main__': # 获取歌单 play_list_id = "2768164485" play_list_url = "https://music.163.com/playlist?id={}".format(play_list_id) play_list_songs = get_songs(play_list_url) host = "music.163.com" origin = "https://www.music.163.com" user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) " \ "AppleWebKit/537.36(KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36" params = "PGHaWMKZLSr/OwkYYCqVviQrjx5khzcfxPmmJtuA+CDl0PQRXKbpArS3G" \ "Ep+wbDWYpboVs9Nu/Vc8IxTFtKQHeTimWD2GZb6UCIynnjHhtFwAz7vmPV" \ "LCyGOjx2d9BRvVK2RBs2HYkyL+2ZZXrxya/TpnZwMopAkHwapnlRnPJadvCIiInpdsNayVgf7Zm7x" encSecKey = "4a15a9438e2f4736d62f8981a00f1f95b7867ed08a1a917d0e1b" \ "ddc6298de38ed5fff7c0fe8ac81d6f62b882592b8b61aba56f0dbdf199144" \ "5516f3c9b9c514fa45d2c1e5ea79b6f9c77e3d3e1abd54a1b1aa7eee2e6eaadefbc70eb10357b" \ "5cae77a541f39f8f74c9b55653b52b6a955835c8c4bf31bebd7af42c6b02ee5e6f" data = { "params": params, "encSecKey": encSecKey } i, j = 0, 0 for song in play_list_songs: song_id = song[1] url = "https://music.163.com/weapi/v1/resource/comments/R_SO_4_{}?csrf_token=".format(song_id) referer = "https://music.163.com/song?id={}".format(song_id) headers = { "Connection": "keep-alive", "Host": host, "Origin": origin, "referer": referer, "User-Agent": user_agent } print("{}的热门评论:".format(song[0])) get_song_comments(url, headers, data, song[0]) print("*"*200) ``` ## 给视频增加背景语音 ### 一,视频mp4文件附加上背景音乐 ```python import moviepy.editor as mpe from moviepy.editor import CompositeAudioClip, VideoFileClip, AudioFileClip #合成背景音乐到mp4 soundfile = '../docs/temp/~bgmusic.mp3' # videofile = "../docs/temp/~composevideosound.mp4" videofile = "../docs/temp/~works.mp4" #不能无声的mp3文件,否则报AttributeError: 'NoneType' object has no attribute 'end' 错误 outfile = "../docs/temp/~bgmusic2sound_a.mp4" video = VideoFileClip(videofile) my_clip = mpe.VideoFileClip(videofile) audio_background = mpe.AudioFileClip(soundfile) # audio_background = mpe.AudioFileClip(soundfile).fx(afx.volumex, 0.1).fx(afx.audio_fadein, 0.1).fx(afx.audio_fadeout, 0.1) videos = video.set_audio(CompositeAudioClip([my_clip.audio,audio_background])) # 音频文件 videos.write_videofile(outfile, audio_codec='aac') # 保存合成视频,注意加上参数audio_codec='aac',否则音频无声音 print('add bgmusic OK!!!') ``` ##### 报错: ```python Traceback (most recent call last): File "E:\python_project\myflask\testpy\addbgmuisc.py", line 19, in videos = video.set_audio(CompositeAudioClip([my_clip.audio,audio_background])) # 音频文件 File "E:\python_project\myflask\venv3.10\lib\site-packages\moviepy\audio\AudioClip.py", line 286, in __init__ ends = [c.end for c in self.clips] File "E:\python_project\myflask\venv3.10\lib\site-packages\moviepy\audio\AudioClip.py", line 286, in ends = [c.end for c in self.clips] AttributeError: 'NoneType' object has no attribute 'end' ``` ##### 解决:videofile = "../docs/temp/~works.mp4" #不能无声的mp3文件,否则报AttributeError错误 ##### 运行的结果: ![image-20221123172710337](typora_img/README/image-20221123172710337.png) 成功生成了~bgmusic2sound_a.mp4