天天看點

使用Python批量抓取單詞發音

備注:今年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)&gt;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