備注:今年1月份寫的文章,以後準備長期駐紮在這兒,就貼過來了。
1.12号晚上總算徹底的考完了所有的科目,昨天可以睡一個安穩的懶覺了。從床上爬起來之後,随便從書架上拿了一本書,竟然是《備戰大學德語四級考試·詞彙篇》,不覺想起當初“戰績輝煌”的德語課。翻開書,看了幾個單詞後,發現都忘記了該怎麼發音,是以想把每個單詞的發音放到P3裡,等睡不着的時候可以聽一聽~。
是以,具體需求就是:根據一個文本檔案,該檔案中提供了一個單詞清單,格式為每個單詞占一行。需要根據這個清單,從某個網站上把對應單詞的發音的mp3檔案儲存在本地磁盤上,而且mp3檔案儲存為相應的單詞的名稱。
大緻就是這些,想想還缺點什麼,恩,多線程---典型的多線程應用環境啊。确定一下實作環境,看來Python是首選了。因為快,當然是說開發速度快了~
再試幾個單詞後,基本就可以确定每個單詞對應的查詢頁面的URL位址格式為:
<a href="http://media.dwds.de/dwds/media/sound/dwdswb_aussprache_dev/+%E5%8D%95%E8%AF%8D%E5%AF%B9%E5%BA%94%E7%9A%84%E5%93%88%E5%B8%8C%E5%80%BC.mp3">http://media.dwds.de/dwds/media/sound/dwdswb_aussprache_dev/+單詞對應的哈希值.mp3</a>
不知道這裡為什麼要用哈希值,可以肯定的是不是用來提高檢索速度的,因為單詞本身就可以作為唯一的鍵,而且單詞的最大長度應該也不會超過一個固定的上限值(比如:40?)。也許使用哈希值是為了防止用程式自動下載下傳發音檔案,減少對伺服器的沖擊吧,我猜。剛看到這個32位的串,我想大家第一反應應該都是猜它是不是單詞對應的md5值(比如QQ登入的時候,就對針對密碼進行三次md5加密),很不幸的,這個串不是(這個,可以使用Python在互動式模式下做一個簡單的驗證)。不過這個并不影響下載下傳這個mp3檔案,恩,就是先打開頁面,然後從頁面上找到mp3的URL,然後再下載下傳。
好了,整理一下思路,簡單的說,下載下傳一個單詞對應的mp3的流程如下:
Step1:從檔案中讀取一個單詞
Step2:構造一個單詞查詢頁面的URL,将此URL對應的html源代碼儲存到content中
Step3:使用正規表達式在content中搜尋對應mp3檔案的URL
Step4:讀取mp3資料,在本地建立一個檔案,把資料儲存進去
Step5:如果沒有結束,跳轉到Step1
恩,挺簡單的流程。還需要增添的設施就是多線程,測試表明,平均每下載下傳一個單詞将近4秒鐘,不能在一個線程在通路網絡或者儲存檔案的時候讓CPU空閑啊。是以,在運作程式的時候需要傳入兩個參數,一個就是需要開啟的線程的數量,另外一個就是儲存單詞清單的檔案名。不過,等我改天有時間了,實作一個線程池,這樣就省事了,把任務扔到池子裡就行了。否則在程式中還要考慮加鎖解鎖這種瑣碎的事情,因為儲存單詞清單的隊列是共享資源。這些分析清楚了,差不多就可以寫代碼了。把代碼貼到這兒,僅供參考:
#!/usr/bin/python
#Author:lichao
#Date:01-13-2012
#Description:Download the .mp3 sound files that correspoding to the words in the given file.
import threading
import time
import fileinput
import re
import urllib2
import sys
class DownloadWorker(threading.Thread):
global mutext
def __init__(self,wordsList,workerIndex):
threading.Thread.__init__(self)
self.queue=wordsList
self.index=workerIndex
def run(self):
print('worker%d start to work' % (self.index))
mutex.acquire()
self.word=self.queue.front()
mutex.release()
while self.word!="0":
url = "http://www.dwds.de/?qu="+self.word
urlContent = urllib2.urlopen(url).read()
urlList = re.findall('http://media.dwds.de/dwds/media/sound/dwdswb_aussprache_dev/.*\.mp3', urlContent)
try:
soundData = urllib2.urlopen(urlList[0]).read()
saveName=self.word+".mp3"
output = open(saveName,'wb')
output.write(soundData)
output.close()
print('%s:OK --Post by worker%d' % (self.word,self.index) )
except:
print('%s:FAILED --Post by worker%d' % (self.word,self.index) )
finally:
mutex.acquire()
self.word=self.queue.front()
mutex.release()
print('worker%d eixt' % self.index)
class WordsList():
def __init__(self,filePath):
self.t=[]
for line in fileinput.input(filePath):
if(len(line)>1 and line[len(line)-1]=='\n'):
line=line[0:len(line)-1]
self.t.append(line)
else:
self.t.append('0')
def front(self):
if(self.t[0]!='0'):
return self.t.pop(0)
else:
return self.t[0]
def main():
global mutex
mutex=threading.Lock()
workerNumber=int(sys.argv[1])
filePath=sys.argv[2]
wordsList=WordsList(filePath)
workerPool=[]
for i in range(0,workerNumber):
worker=DownloadWorker(wordsList,i)
workerPool.append(worker)
workerPool[i].start()
if __name__ == "__main__":
main()
下面兩張截圖是運作效果圖,其中圖1是運作效果圖。是的,有些單詞的mp3下載下傳過程中出錯了,這是由于某些單詞的發音太簡單了,這些單詞級别估計是1級,估計是網站的設計者覺得這種簡單的單詞沒有必要制作一個mp3檔案放在上面。一般來說,稍難一點的單詞的發音都能下載下傳到的。圖2是下載下傳後的截圖,以後可以用來催眠了。
<a target="_blank" href="http://blog.51cto.com/attachment/201202/163741917.png"></a>
圖1:下載下傳器運作效果
<a target="_blank" href="http://blog.51cto.com/attachment/201202/163749193.png"></a>
本文轉自hipercomer 51CTO部落格,原文連結:http://blog.51cto.com/hipercomer/789423