20201324 2020-2021-2 《Python程式設計》實驗四報告
20201324 2020-2021-2 《Python程式設計》實驗四報告
課程:《Python程式設計》
班級: 2013
姓名: 徐源
學號:20201324
實驗教師:王志強
實驗日期:2021年6月23日
必修/選修: 公選課
(一)實驗內容
- 涉及知識:利用Python進行爬蟲和資料處理
- 具體操作:從QQ音樂爬取周杰倫的熱門歌單,並用python一鍵為爬取到的每一首歌曲生成海報
- 實驗要求
- (1)程式能執行,功能豐富。(需求提交原始碼,並建議錄製程式執行的視訊)10分
- (2)綜合實踐報告,要體現實驗分析、設計、實現過程、結果等資訊,格式規範,邏輯清晰,結構合理。10分。
- (3)在實踐報告中,需要對全課進行總結,並寫課程感想體會、意見和建議等。5分
下圖為我用自己的程式生成的歌曲海報之一
(二)實驗過程及結果
功能的實現分兩步走,先爬蟲得到歌單和歌曲資訊,再利用這些資訊生成海報
1.爬取歌單
開啟頁面->F12->Network->XHR
找到client_search,點開,依次點選data->song->list->0,找到歌單上第一首歌的name:七里香
說明這一部分有我們想要的資料,Headers->Request URL,編寫程式碼
程式碼如下
import requests res_music = requests.get('https://c.y.qq.com/soso/fcgi-bin/client_search_cp?ct=24&qqmusic_ver=1298&new_json=1&remoteplace=txt.yqq.song&searchid=60997426243444153&t=0&aggr=1&cr=1&catZhida=1&lossless=0&flag_qc=0&p=1&n=20&w=%E5%91%A8%E6%9D%B0%E4%BC%A6&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0') json_music = res_music.json()
2.挑揀所需資料
分析知data是XHR的一個鍵,其對應的值也是一個字典;song是該字典的一個鍵,鍵song對應的值又是一個字典;list又是這個字典的一個值,其對應的值是一個列表,列表中的每一個元素都是一個字典,在每個字典裡,鍵name的值即歌曲名,所以通過巢狀來獲取歌曲名
程式碼如下
list_music = json_music['data']['song']['list'] # list_music是一個列表,又嵌套了字典 for music in list_music: # 以name為鍵,查詢歌曲名 print(music['name']) # 查詢專輯名 print('所屬專輯:'+music['album']['name']) # 查詢播放時長 print('播放時長:'+str(music['interval'])+'秒') # 查詢播放連結 print('播放連結:https://y.qq.com/n/yqq/song/'+music['mid']+'.html') # 查詢釋出時間 print('釋出時間:'+str(music['time_public'])) print('\n\n')
執行結果
3.生成海報
OpenCV不能顯示中文字元,且難以控制文字位置。因此我對比效能後在OpenCV和PIL中選擇了後者。
安裝庫:pip install Pillow
呼叫庫函式:from PIL import Image, ImageDraw, ImageFont
(1)準備海報底板
對照QQ音樂頁面顯示的歌名,手動搜尋圖片作為海報底板,記得要將圖片命名為歌曲名,並儲存為png格式。這樣程式執行時就知道"歌曲名.png"就是我們為《歌曲名》準備的底板,從而實現一鍵批量處理
img = title+".png" # 圖片底板
new_img = "final_"+title+".png" # 生成的海報
為方便演示,我將程式碼修改為for music in list_music[0:3]:
,僅為爬取到的前三首歌製作海報
(2)調節字型格式、大小、顏色
setFont = ImageFont.truetype('C:/Windows/Fonts/STXINWEI.TTF', 20)
兩個引數分別為字型在電腦中的路徑和字型大小;
顏色用CSS顏色或直接color = "black"均可
(3)寫入內容
我使用了兩種方式寫入:
① 單獨寫入一行字元
draw.text(x,y), information, font=setFont, fill="#000000", direction=None)
在底板上座標(x,y)處開始寫
information是要寫入的內容,必須是字元型
② 將列表中的元素一行一行地打印出來
summary_y = 0
summary_line = 50
summary = ['所屬專輯:'+'《' + music['album']['name'] + '》', '歌曲時長:'+str(music['interval'])+'秒','歌手:周杰倫','釋出時間:'+str(music['time_public'])]
for num, one in enumerate(summary):
y = summary_start_y - num * summary_line
summary_num = num + 1
draw.text((summary_x, height - y), u'%s. %s' % (summary_num, one), color, font)
這樣可以自動換行和標號,行距一致,方便快捷,強烈推薦!
(4)生成海報
image.save(new_img, 'png')
做完一定要save一下,否則你會發現程式不報錯,debug也沒有問題,但就是沒有你想要的海報(不要問我是怎麼知道的/(ㄒoㄒ)/~~)
程式碼如下(關鍵程式碼的功能已註釋)
# 圖片名稱
img = title+".png" # 圖片模板
new_img = "final_"+title+".png" # 生成的圖片
# 設定字型樣式
font_type = "C:/Windows/Fonts/STXINWEI.TTF"
font_medium_type = "C:/Windows/Fonts/STKAITI.TTF"
header_font = ImageFont.truetype(font_type, 55)
title_font = ImageFont.truetype(font_type, 45)
font = ImageFont.truetype(font_medium_type, 20)
# ImageFont.truetype第一個引數為字型,第二個為字型大小
color = "#000000"
# 開啟圖片
image = Image.open(img)
draw = ImageDraw.Draw(image)
width, height = image.size
# 獲取原影象的寬和高,並保持最終海報的大小與之一致
# 寫入header
header_x = 40
header_y = 650
# 數字越小,字在圖片上的位置越偏下
draw.text((header_x, height - header_y), u'%s' % header, color, header_font)
# 寫入標題
title_x = header_x
title_y = header_y - 80
draw.text((title_x, height - title_y), u'%s' % title, color, title_font)
# 寫入歌曲資訊
summary_x = title_x
summary_start_y = title_y - 150
# title後面減的越多,字越偏下
summary_y = 0
summary_line = 50
information = '歌曲資訊'
setFont = ImageFont.truetype('C:/windows/fonts/STXINGKA.TTF', 25)
draw.text((summary_x, height - summary_start_y-40), information, font=setFont, fill="#000000", direction=None)
for num, one in enumerate(summary):
y = summary_start_y - num * summary_line
summary_num = num + 1
draw.text((summary_x, height - y), u'%s. %s' % (summary_num, one), color, font)
# 寫入連結
write_x = summary_x
write_y = title_y - 400
write_line = 40
information = '播放連結:'
setFont = ImageFont.truetype('C:/windows/fonts/STXINGKA.TTF', 25)
draw.text((write_x, height - write_y), information, font=setFont, fill="#000000", direction=None)
draw.text((write_x, height - write_y + write_line), writes, font=font, fill="#0000ff", direction=None)
# 生成圖片
image.save(new_img, 'png')
執行結果
(三)實驗過程中遇到的問題和解決過程
- 問題1:設定字型時報錯
OSError: cannot open resource
- 問題1解決方案:百度,發現之前寫的路徑不完整,必須寫成"C:/Windows/Fonts/xxx.TTF"的形式
- 問題2:在往底板寫入文字時,部分欄位的長度會超出圖片大小,導致無返顯示在底板上
- 問題2解決方案:
- 在挑選大小合適的圖片作為底板
- 調整寫入字元的座標。網上的資料有限,我直接人工排查。逐個修改程式中的座標值,執行程式,記錄欄位的座標,找出規律。最終將字元座標修改為合適的值
(四)參考資料
(五)佐證材料
碼雲連結:https://gitee.com/xu-yuan-20201324/python_use/blob/main/Socket_test/crawler_homework.py
操作視訊已錄製併發送至指定郵箱
(六) 其他(課程總結、感想、建議)
我之所以報名python程式設計課是因為優秀學長學姐的強烈推薦。大一菜狗,網上選課時緊張到手一直在抖,系統一開放,我第一時間狂點python,搶到的那一刻當場開心到不能自已。
這門課帶給了我什麼?——它真的讓我吃了很多苦,這學期我一直嚴格按照王老師“今日事,今日畢”的理念要求自己,作業一定要當天晚上就做,做不完就熬夜繼續做。我的天賦和基礎委實都很一般,以至於這學期90%以上的作業都是半夜提交的。做實驗三時,因為第一次接觸密碼方面的知識,操作不規範,外加以前的種種問題相繼暴露,我的電腦不幸經歷了一波猛烈的故障o(TヘTo),導致這學期所有的python檔案、之前做過的作業和實驗報告、精心整理的課堂筆記,統統從本地清零了,碼雲倉庫也被清空了。真的算得上是我遇到的最大的打擊,那天我對自己說:“想哭就哭吧”,但發了很久的呆,最後還是程式從頭重編,實驗報告從零重寫,然後,就這麼過去了。
如果能重新做一次選擇,我想,我還是會義無反顧。python程式設計課不僅提高了我的程式設計能力,加深了我對c語言等專業課內容的認識,也給了我一個機會,讓我在探索新世界的過程中不斷磨礪與成長。遇到問題時,學會問百度,學會總結經驗,這是一種能力。如今的我,可以冷靜地拆解問題、建立思路、動手實現,能靜得下心來分析以前看一眼就覺得頭大的網路開原始碼,能在碰壁時心態平和地從新來過,這些能力放在任何領域都是寶貴的財富。
如果說有什麼小建議的話,希望老師把函式、檔案處理、爬蟲等部分,結合具體例子,講得再詳細些吧。感覺前面簡單的知識講得很細,到了後面較難的部分反而不如前面細緻了,也可能是我的理解能力跟不上了,嘿嘿嘿。這些部分的資源也請老師提前放到雲班課上吧,課程剛開始時時間比較充足,後面可能沒時間看了,不想浪費好資源。
最後,真誠感謝王老師一學期的精心指導,真的收穫滿滿!