1. 程式人生 > >python爬取20000個單詞音訊

python爬取20000個單詞音訊

雖然單詞現在隨處可見,但是對於鍛鍊技術來說是一個好方法,這篇部落格將從找目標到程式碼完整的記錄此過程。

真實需求:
下載了20000個單詞,結果只有單詞沒有音訊,這怎麼行呢?
作為一名喜歡自動化的童鞋來說,才不會再去網上找音訊,所以乾脆寫個程式吧。

步驟

1、找一個查單詞的網站,找到單詞發音的地址
2、使用python下載儲存

接下來就一步步來

1、網站與地址

經過多次查詢,發現以前有前輩寫過的,但是那是個外國網站,而且實在難得操作,所以乾脆找個國內的,然後發現幾乎都不能直接找到地址,是通過js觸發的,於是在js程式碼裡找到地址:
1、此網站
http://www.chadanci.com/


2、找到頁面發音的a標籤:

<a onmouseover="asplay('and', 0)" onclick="asplay('and', 0)" class="play_word" href="javascript:;" title="真人發音"></a>

3、找到對應此函式的js程式碼:
在source裡找到:http://www.chadanci.com/images/js/_xml_content.js
裡面的方法:

function play_sentence(liju){
    $.ajax({
        type: "GET",
        url: "/e/extend/s/file.php?type=sentence"
, data: "q="+encodeURIComponent(liju), success: function(url){ var asound = getFlashObject("asound"); if(asound){ asound.SetVariable("f",url); asound.GotoFrame(1); } } }); }

4、構造查詢地址:

http://www.chadanci
.com/e/extend/s/file.php?type=0&world=and

很清楚就出來了:0是英式發音,1是美式,word是單詞

5、但是查詢這個頁面返回的是音訊mp3的地址,可以直接進行下載。

2、使用python下載儲存

因為是GET連結,可能伺服器沒有過多在意爬蟲,所以也不搞代理和分散式了。

最開始想法非常簡單:
1、讀取單詞文字
2、構造連結進行下載
3、寫入文字

def download(word):
    url = "http://www.chadanci.com//e/extend/s/file.php?type=0&world="+word

    req = urllib2.Request(url)
    req.add_header("User-Agent",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36")

    res_data = urllib2.urlopen(req)
    mp3_url = res_data.read()
    #print mp3_url
    if mp3_url is None:
        return
    try:
        f = urllib2.urlopen(mp3_url) 
        with open("mp3/"+word+".mp3", "wb") as fword:
            fword.write(f.read()) 
    except:
        print "error1"

def process(file_name):
    done = [] #儲存已下載單詞
    #進度處理
    with open(file_name) as f:
        words = f.readlines()
        num = len(words)
        i = 0
        width = num/100 #用來控制進度
        p = '#'
        while i<num:
            word = words[i].strip('\n')
            # print word
            try:
                if word not in done:
                    download(word)
                    #加入已下載列表
                    done.append(word)
            except:
                print "error2"
            i+=1
            if i%width==0:
                p+='#'
            #原地重新整理進度
            sys.stdout.write(str((i*1.0/num)*100)+"% :"+p+"->"+"\r")
            sys.stdout.flush()

if __name__=='__main__':
    process('word.txt')

結果:
發現到某個單詞會卡住,然後整個就卡了,後來發現作出如下改正:

1、設定延時:

res_data = urllib2.urlopen(req,timeout=3)

2、採用多執行緒處理

3、改進程式碼

也許一次沒有下載完,所以考慮將已下載的單詞寫入檔案。

#!/usr/bin/env python
# coding=utf-8
import urllib2
import threading
import sys

#執行緒類
class MyThread(threading.Thread):
    def __init__(self,target,args):
        super(MyThread,self).__init__()
        self.target = target
        self.args = args

    def run(self):
        self.target(self.args)

def download(word):
    url = "http://www.chadanci.com//e/extend/s/file.php?type=0&world="+word

    req = urllib2.Request(url)
    req.add_header("User-Agent",
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36")

    #延時
    res_data = urllib2.urlopen(req,timeout=3)
    mp3_url = res_data.read()
    #print mp3_url
    if mp3_url is None:
        return
    try:
        f = urllib2.urlopen(mp3_url) 
        with open("mp3/"+word+".mp3", "wb") as fword:
            fword.write(f.read()) 
        with open("done_word.txt","ab") as done:
            done.write(word+"\n")
    except:
        print "error1"

def process(file_name):
    #從檔案把已下載單詞加入列表裡
    done = []

    #繼續下載
    with open(file_name) as f:
        words = f.readlines()
        num = len(words)
        i = 0
        width = num/100
        p = '#'
        while i<num:
            word = words[i].strip('\n')
            # print word
            try:
                if word not in done:
                    download(word)
                    #加入已下載列表
                    done.append(word)
            except:
                print "error2"
            i+=1
            if i%width==0:
                p+='#'
            sys.stdout.write(str((i*1.0/num)*100)+"% :"+p+"->"+"\r")
            sys.stdout.flush()

def main():
    t1 = MyThread(process,'word.txt')
    t1.start()
    t1.join()

if __name__=='__main__':
    main()

結果,雖然沒有卡頓,但這速度不敢恭維,半個小時才下了6000多個單詞。

1

4、總結

使用到的技術:
1、urllib2爬取網頁
2、檔案處理
3、系統輸出,進度重新整理
4、多執行緒