程序是事件驅動的,寫博客是什么驅動的?事件? 時間?no,我承認我很懶,甚至不願意記錄總結。哪是什么驅動的? 對! 問題驅動的。遇到了問題解決了問題突然想起來搬到blog上,讓遇到相同問題的可以參考下。
問題所在
我用的Electronic WeChat,當朋友發送文字、圖片、甚至視頻的時候都可以打開(Audio無法收聽,因為電腦無外設音響/喇叭)。但發來的語音就扯蛋了,只能通過手機聽,甚至不能轉發。
但是發現可以通過開發者工具看到http語音文件的請求地址。
直接復制url在瀏覽器中打開沒有任何響應?難道是Referer與Cookie有判斷。果然!只有在登陸的瀏覽器中可以,不信你可以直接在瀏覽器中打開web微信嘗試操作,Electronic WeChat 只有一個tab。open link in new tab 其實就跳轉到瀏覽器了。然而開發者工具帶了一個騷操作,那就是“Copy Response”
copy response的數據為base64內容:
data:audio/mp3;base64,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GMQRDOF2tPB6RE1/Rbde8RJImt9oTgAiWt6TSrLTLM7Ldf8v5eqP/6GQU5uMJeZwuRMTpbWVhSeBANH8TikLChU64XUsJ//jGMQYDFBWmAAT0gD870v1sFVs0JjC5t7/////k1pYSk3rfDP61f5hhIARHM7unEp7x2EyvOvTADig2/g+U/+nZyygqCpIsP/jGMQhDJBmoAFLEADWEHwG76//IP1spLcaPRu/QtX0TQ95frobSvPn4uSFhn/5NHKBETFhX6sl+GgSKjC/97pY7oc5mFf/3//jGMQpFcLitAGJKABXJU6UVziAjT/8r/vPDqMMEyHYYgj//+1EKLjjzMowagiYOg9zigh/5+z8DoLpPzj//X9BMK+openvh//jGMQNDFrOvMnBEAH//////r/Tv9qJ//l++shF/0QAYjMy8h6EnOc/IMwhllVbE3YK//QwHwCCGdRdhwDQPGTm+0MioRjgwP/jGMQWDhq6yABARJSG8s2f///////////////VKPfUpq2MhjgQo7FsY6jGnTrNdf/k1DAPSB6dwFB9NXZssJ0KFDniNIWYx//jGMQYDREuwABaTkzpIGyXL/UDA1vqN3Txwsc+55Nk8cbn//////0EVf0C5ZnqYFoFFtCAKc/pC5P5qhOGzMuLgjM4vcTH3//jGMQeC7ESvABSkExew717JKRUVOYLc9////3+afrMgR4lVprtKXUA5Kevh+7adj2/z9ioEOKh0DcTyy/i1TrvpxsedLB3U//jGMQqDRjasABr1ij////+s6tf/xK5SvRHAwBUOday1CgIWq3ubxmwPtSGRLNqJIMgMBZV8f4yn1W+XBDR0f//////939v8v/jGMQwDMimsABT3iRoCUtV4/9SxMyVq0x3hTDmf5thsESXN2AXDwqFQqamHwSAyga9tCBgxuoshW5yIuzhPwhJ8QqSSRySev/jGMQ3DGkuxMBqREzURQvmarOE0BMBxOu7HYGloz6gjjtNWToD4STWv5UAJvKZS84qUvQ4iK+JPDs1//3qqvNM3eNqxaEa0P/jGMRADLkm8kBqyk4bWr00AYBhuG8ZuriXM28asXzfxj4cLb/lbIR/Rkt31nPfQI2IFetShLUn0A7gLw6nqRZBphCyLKWRhP/jGMRIDJFGqADDxExUrOusmi6a+lX2M/Ry/N8gp9UIKyJ2p///////9kiq//zCIEZcS951yTEFMXlmySVBiNgbv9ZdKZl+a//jGMRQDMkqsABsRExawHDlJmc50/oIZ87mEEIX1wifKQGdot7z/+vXgNY8L1r20noCowUM5KyUaANkO+9Qbh+NP3QbNn+EK//jGMRXDGkurAB7Bkx5gIUboBCithQEolnjZv//29vRuI9sp8T8A2crtpgmKx4IPS85IGHwTRoxFdCd4honABPCBAgirB7JY//jGMRgDMEavYB6xE04qvwqiurnSomgRoSE8VQQXThK1EKd1XQrINlVFWGY+CQGoNm0JJoZ90tTtt+kbDCD2ptr6zOPY9Cq9//jGMRoC6jutAB6Rkn294qhegNiIIDYliBBhA3QT5kNEZVLVxgOFmNnkyTSwQKgEUsOh0egOkGq2O/v/O////9HGLPFjqzVy//jGMR0DeEauABSTEw1sMkttoFo591tKgcLKt/krLhWPqzNzyFLmtrOVQLP+N4OLR71hJ7hgFO5Yq5MsOfJEf/////1WCs1BP/jGMR3DziSuMhTzCSqF3zw1SojeSSACD9AIBMc561FYSnJro24FyI3/OYwZNOuZADHhFxntVx/Hyz2HwTChV4RAriYYNVgTP/jGMR1D8i6+lhazCqDf/////77W01wQyOTM5b3jSBz6lISgSI0LByez9rfVld6V23zb7Pa7g0aa6ELdiSSvbYO48Udlkld4//jGMRwD2ji0bg6TEgl/d9VuIpCzx3LzQ1DclAh/7zjKJAvMCB/Lh5Q5zY0CbDxGgFgQgtf+SjJl8+gaJjaLMfjgmxBRHh/8//jGMRtDMCetaFMCAF0mb0D5IGaZqscv933P//62fxb/p/2pd4Q//vuAJo+i01ZOAXJ596zqrlTNa7Up9a1f+VOvYus2lVrM//jGMR1FDGisAGLaADa4tttPF7hBgwgAUlaXOBIIQamysiAXzHDCrNDbOOkc8GeZb55PA//7q+IEBlQ59aPIW5ErzTV1aSef//jGMRfEbFqrMnPQACXIo07c0FS//YkSP6qgJNdmAgI/+qMzGRs3S6JJuGqwV////////Qu9SpuW627bW76jACOt7iSOQm3tv/jGMRTEElGsZB5hkw501A2Vhsy6aViGf/S/CeVlNyynpwoTvmTggylCjhcc5bHsRSxocPnC58naLhseO/Hv6tIVHs999V5Y//j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
所以將base64轉換為對應的mp3格式不就可以播放了嗎?.......
base64
Python的base64函數是內置函數,是一種用64個字符來表示任意二進制數據的方法。用記事本打開exe
、jpg
、pdf
這些文件時,我們都會看到一大堆亂碼,因為二進制文件包含很多無法顯示和打印的字符,所以,如果要讓記事本這樣的文本處理軟件能處理二進制數據,就需要一個二進制到字符串的轉換方法。Base64是一種最常見的二進制編碼方法。
廖雪峰老師對base64的介紹
base64對文件的編碼解碼
對文件的編碼就是讀取文件內容,encode為base64,對文件的解碼就是將base64字符串轉換為文件二進制。
- 編碼使用
base64.b64encode()
- 解碼使用
base64.b64decode()
讀取文件我們可以用with open as 也可以直接open,區別是with智能關閉文件,open要手動close文件。參考:https://www.cnblogs.com/gengcx/p/6713646.html
上代碼:
def ToBase64(file, txt): with open(file, 'rb') as fileObj: image_data = fileObj.read() base64_data = base64.b64encode(image_data) fout = open(txt, 'w') fout.write(base64_data.decode()) fout.close() def ToFile(txt, file): with open(txt, 'r') as fileObj: base64_data = fileObj.read() ori_image_data = base64.b64decode(base64_data) fout = open(file, 'wb') fout.write(ori_image_data) fout.close() ToBase64("./desk.jpg",'desk_base64.txt') # 文件轉換為base64 ToFile("./desk_base64.txt",'desk_cp_by_base64.jpg') # base64編碼轉換為二進制文件
pyqt的GUI外衣
想轉換命令行就如上,但是操作不方便,可以給base64的代碼穿一個GUI外衣,使用pyqt方便的不得了!
# -*- coding: UTF8 -*- import io, shutil, sys, os from PyQt5.QtWidgets import * from PyQt5 import QtGui import base64 class MainWidgetUI(QDialog): def __init__(self): super().__init__() self.setFixedSize(250, 200) # PyQT禁止調整窗口大小 self.setWindowTitle('文件base64編碼互轉') self.setWindowIcon(QtGui.QIcon("favicon.ico")) Layout = QVBoxLayout() self.pushButton1 = QPushButton("To base64") self.pushButton2 = QPushButton("To file") Layout.addWidget(self.pushButton1) # addWidget 添加一個掛件 Layout.addSpacing(100) # 添加一個100px的空間距離 且不帶彈性 Layout.addWidget(self.pushButton2) self.setLayout(Layout) # setLayout設置 QVBoxLayout()垂直 與QHBoxLayout() 水平布局, 查看布局請移步CURL-api.py # pushButton1點擊按鈕 self.pushButton1.clicked.connect(self.Tobase64) # pushButton2點擊按鈕 self.pushButton2.clicked.connect(self.Tofile) def Tobase64(self): fileDict = self.selectFile() if fileDict: GlobalToBase64(fileDict['file'], fileDict['filepath'] + "/" + fileDict['shotname'] + ".txt") QMessageBox.information(self, '提示!', "轉換成功", QMessageBox.Yes) def Tofile(self): fileDict = self.selectFile() if fileDict: # 簡單判斷文件是否自帶Mime 文件擴展 data:audio/mp3;base64, fobj = open(fileDict['file']) contents = fobj.read() extensions = contents.split(',')[0].rsplit('/')[1].split(';') if len(extensions) == 2: # ['mp3', 'base64'] 格式為兩個 # 生成臨時文件保存base64 tmpFile = fileDict['filepath'] + "/" + fileDict['shotname'] + ".tmp" tmpFileObj = open(tmpFile, 'w') tmpFileObj.write(contents.split(',')[1]) tmpFileObj.close() GlobalToFile(tmpFile, fileDict['filepath'] + "/" + fileDict['shotname'] + "." + extensions[0]) QMessageBox.information(self, '提示!', "轉換成功", QMessageBox.Yes) os.remove(tmpFile) # 刪除臨時文件 else: # 無mime mine, okPressed = QInputDialog.getText(self, "文件格式類型", "請輸入文件格式類型:", QLineEdit.Normal, "mp3") # 獲取輸入對話框內容 if okPressed and mine: # 選擇確認且輸入文本 GlobalToFile(fileDict['file'], fileDict['filepath'] + "/" + fileDict['shotname'] + "." + mine) QMessageBox.information(self, '提示!', "轉換成功", QMessageBox.Yes) else: return False def selectFile(self): ''' 選擇文件 ''' # getOpenFileName 只能選擇一個 getOpenFileNames 可多個選擇 file = QFileDialog.getOpenFileName(self, "請選擇文件", '', "*.*") if file[0] == '': QMessageBox.warning(self, '錯誤提示!', "請選擇文件", QMessageBox.Yes) else: (filepath, filename) = os.path.split(file[0]) # 獲取文件路徑,文件名 (shotname, extension) = os.path.splitext(filename) # 獲取文件名稱,文件后綴 return {"file": file[0], "filepath": filepath, "shotname": shotname} def GlobalToBase64(file, txt): with open(file, 'rb') as fileObj: image_data = fileObj.read() base64_data = base64.b64encode(image_data) fout = open(txt, 'w') fout.write(base64_data.decode()) fout.close() def GlobalToFile(txt, file): with open(txt, 'r') as fileObj: base64_data = fileObj.read() ori_image_data = base64.b64decode(base64_data) fout = open(file, 'wb') fout.write(ori_image_data) fout.close() if __name__ == "__main__": app = QApplication(sys.argv) main_widget = MainWidgetUI() main_widget.show() sys.exit(app.exec_())
效果:
這樣就可以把微信發送的語音文件保存下來了。猜猜上面那個 “data:audio/mp3;base64,..”說的什么玩意。