Tải nhạc hot trong tháng của zing – bản viết bằng Python.

Cách đây một thời gian tớ có viết một shell script để tiện cho việc tải các bài nhạc hot trong tháng của mp3.zing.vn (chẹp, lại không đâu quảng cáo không công nữa :-ss). Ngay sau đó đã nhận được ý kiến phản hồi của cậu em Cường aka. @theghostnt về việc phải cài thêm lynx khi sử dụng script, và một điều tuyệt vời hơn nữa là cậu đó đã viết lại script đó với sử dụng là wget (mặc định trong hầu hết các distro) và đăng script đó tại blog của mình cùng  một bản khác của script với việc thêm vào lựa chọn tải những bài love song trên zing. Phải nói rằng, với ai đó muốn và đang học shell script thì đó là hai ví dụ cho những dòng code đẹp🙂.
Như một số bạn đã đọc các bài gần đây của tớ thì có lẽ cũng biết rằng tớ bắt đầu học sử dụng Python trong thời gian vừa qua và phải nói rằng đây là một ngôn ngữ khá ấn tượng vì những hỗ trợ và khả năng của nó. Do đó, hôm nay rảnh rỗi tớ ngồi chuyển cái ý tưởng trong script của tớ viết theo ngôn ngữ Python (hiện tại thường là mặc định trong các distro) để tránh xung đột giữa sử dụng wget, lynx cũng như để sử dụng thống nhất các câu lệnh mà không phụ thuộc vào sed, awk etc…

Nội dung của script như sau:

#!/usr/bin/env python

"""
Copyleft Le Anh Tuan <tuantub@googlemail.com>
"""

from urllib2 import urlopen
import urllib2
import re
import sys
import string
from datetime import datetime
import os

def httpDownloader(out_file, req=None, url=None):
    if req: 
        net_stream = urlopen(req)
    elif url:
        net_stream = urlopen(url)
    else:
        return 0
    file_len = int(net_stream.info().getheaders('content-length')[0])
    if os.path.isfile(out_file):
        if os.path.getsize(out_file) == file_len:
            print "%s exists!" % out_file
            return 0
        else:
            print "%s exists but was not fully downloaded!" % out_file
    print "Downloading %s..." % out_file
    out_stream = open (out_file, 'wb')
    try:
        while True:
            bs = 512*8
            block = net_stream.read(bs)
            if not block:
                break
            out_stream.write(block)
    except:
        out_stream.close()
        net_stream.close()
        return 0
    out_stream.close()
    net_stream.close()
    return 1




#########################
#Main program
#########################


if __name__ == '__main__':

    #Destination directory, where folder will be placed
    #dest_dir = "~/Music"
    dest_dir = "/media/Data/Music"

    #url
    url = "http://mp3.zing.vn/mp3/nghe-album/album-hot/nhac-viet.html"

    #fake the mozilla headers
    hdrs = {'User-Agent' : 'Mozilla/5.0 (X11; U; Linux i686; en-US)AppleWebKit/533.2\
            (KHTML, like Gecko) Chrome/5.0.342.7 Safari/533.2'}

    #get the current month
    dt = datetime.today()
    month = dt.month

    dest_dir = os.path.expanduser(dest_dir)
    sub_dir = string.join(["Thang", str(month)], '')

    #absolute path to destination directory 
    if dest_dir[-1] == '/':
        abs_dir = string.join([dest_dir, sub_dir, '/'], '') 
    else:
        abs_dir = string.join([dest_dir, '/', sub_dir, '/'], '')

    if not os.path.isdir(abs_dir):
        try:
            os.mkdir(abs_dir)
        except:
            print "Error, Can not create the directory %s" % abs_dir
            sys.exit()

    #make request
    req = urllib2.Request(url, headers=hdrs)

    #create streamreader
    fpage = urlopen(req)

    #regex
    fline = re.compile(r'http://.*dl\.mp3.*\.mp3\"')
    _rem = re.compile(r'\?filename=|\"')
    
    
    links_list = []
    try: 
        while True: 
            lnk = fpage.readline()
            if not lnk:
                break
            else:
                rlink = fline.search(lnk) 
                if rlink:
                    link_and_name = _rem.sub(' ', rlink.group())
                    splitted = link_and_name.split()
                    links_list.append([splitted[0], splitted[1]])
    finally:
        fpage.close()



    count = 0
    try:
        for [link, file_name] in links_list:
            link_req = urllib2.Request(link, headers=hdrs)
            out_file = string.join([abs_dir, file_name], '')
            count = count + httpDownloader(out_file, req=link_req)
    except KeyboardInterrupt:
        print "User pressed Ctrl-C! Quitting..."
        sys.exit(1)
    except :
        print "Something was wrong with links, please check the links!"
        
                                       
                                       
    print "=========================================================="
    print "%d file(s) have/s been downloaded to %s" % (count, abs_dir)
    print "=========================================================="


Sử dụng:
Copy nội dung của đoạn code trên vào một tệp tin nào đó và chmod thực thi cho nó và chạy với /path/to/this/script.
Trước khi chạy nên thay đổi dòng :

dest_dir = "~/Music" 

cho phù hợp với nơi bạn cần lưu các tệp tin nhạc ví dụ thành:

 dest_dir = "/media/Data/Music"

chẳng hạn thì sau này bạn sẽ có các bài hát được lưu lại tại /media/Data/Music/Thang$month với $month là số của tháng (số 12 cho tháng này😉 ).

Đánh giá:
Khi chạy script trên thì tốc độ tải bài hát thi thoảng không bằng chạy với shell script nhưng dù sao đây cũng là một thử nghiệm và trải nghiệm vui với Python.

Thân.

24 phản hồi to “Tải nhạc hot trong tháng của zing – bản viết bằng Python.”

  1. Ghost Says:

    😀 chắc phải học Python thôi.

  2. Rainbowsmile@Vút Bay.net Says:

    Hi, code thật nhức đầu, em chán coding lắm😦

  3. Ly Says:

    happy new year

  4. Jean Christophe André Says:

    Một phiên bản mới… Đẹp hơn một tí…😉


    #!/usr/bin/env python
    # Licence: public domain

    # destination directory, where folder will be placed
    DEST_DIR = "~/Music/Zing"

    # download information
    HOMEPAGE = "http://mp3.zing.vn/mp3/nghe-album/album-hot/nhac-viet.html"
    DOWNLOAD_PATTERN = r'"(http://dl\.mp3.*\?filename=([^/]*\.mp3))"'

    import sys
    import logging
    from datetime import date
    from os import mkdir, utime
    from os.path import expanduser, join, isdir, isfile
    from urllib import urlopen, urlretrieve
    from re import findall
    from calendar import timegm

    logging.basicConfig(level=logging.DEBUG,
    format="%(asctime)s %(levelname)s %(message)s")
    logging.info('Starting.')

    # absolute path to destination directory
    dir = join(expanduser(DEST_DIR), "Thang%02d" % date.today().month)
    if not isdir(dir):
    try:
    mkdir(dir)
    except:
    logging.error("Can't create directory '%s'.", dir)
    sys.exit(1)

    # get the page content
    try:
    f = urlopen(HOMEPAGE)
    page_content = f.read()
    f.close()
    except:
    logging.error("Can't read page '%s'.", HOMEPAGE)
    sys.exit(2)

    # find all file URLs and download them
    count = 0
    for link,filename in findall(DOWNLOAD_PATTERN, page_content):
    filepath = join(dir, filename)
    if isfile(filepath):
    logging.info("'%s' already exists, skipped.", filename)
    continue
    logging.info("Downloading '%s'..." % filename)
    try:
    info = urlretrieve(link, filepath)[1]
    last_modified = info.getdate('Last-Modified')
    if last_modified:
    last_modified = timegm(last_modified)
    utime(filepath, (last_modified, last_modified))
    logging.info("Done.")
    except:
    logging.info("ERROR!")
    count += 1

    print "=" * 78
    if count <= 1:
    logging.info("%d file has been downloaded.", count)
    else:
    logging.info("%d files have been downloaded to '%s'.", count, dir)
    print "=" * 78

    sys.exit(0)

  5. Jean Christophe André Says:

    Mời xem tại đây đọc rõ hơn : http://pastebin.com/f1d4d7163

  6. tuantub Says:

    @Jean Christophe André : python freak🙂
    thanks😉

  7. tquang Says:

    Code rất hay cho cả code 1 và code 2. Nhưng phải cho nó có chức năng kiểm tra dung lượng file để có thể resume thì đã nữa.

    Vì nhiều khi mình tài mà bị rớt mạng thì nó báo là tải rồi, du file đó chỉ mới tải được 250KB/4MB.

    Cảm ơn vì code của bạn!

    • tuantub Says:

      @tquang: tớ cũng vừa mới gặp trường hợp này một vài hôm trước mà bận quá chưa coi lại được, cuối tuần này rảnh tớ sẽ sửa lại code phục vụ việc đó😉

    • tuantub Says:

      @tquang: tớ đã sửa lại đoạn code rồi, bồ thử dùng nha😉

      • Jean Christophe André Says:

        @tuantub: phiên bản mới nằm ở đâu đây ?

  8. tuantub Says:

    @André: phiên bản mới chỉ chỉnh sửa một chút và được sửa lại thẳng vào bài viết😉

  9. tquang Says:

    Ngon rồi, tốt rồi. Mình đã thử và nó nhận diện được, sau đó tại tiếp file bị lỗi để hoàn tất

    C:\Users\tquang\Desktop>zing.py
    ./Thang1/Lam-Sao-Quen-Anh.mp3 exists but was not fully downloaded!
    Downloading ./Thang1/Lam-Sao-Quen-Anh.mp3…

    • tquang Says:

      Ái chà, mình thử code mới thì nhạc tài về không nghe được, bị lỗi như là vấp file.

      Có lẽ quá trình kiểm tra header của code bị gì rồi. Mình dùng lại code cũ của bạn thì tải và nghe được bình thường.

      Cảm ơn bạn

      • tuantub Says:

        Tớ nghe bình thường mà🙂

      • tuantub Says:

        ps:tớ dùng linux, liệu có thể là do bồ dung windoof ko ?

  10. tquang Says:

    Thôi, đúng rồi

    Mình dùng cả 2 thì Windows khi tải = code mới này thì lỗi nghe giật giật

    Nhưng nếu dùng Linux tải thì lại bình thường. Chuyển file mp3 đã tải từ Linux sang Windows cũng bình thường

    Lúc này đây, mình nghĩ có thể là do phiên bản Python khác nhau.

    Trên Linux
    [tquang@server ~]$ python -V
    Python 2.4.3

    Trên Windows
    C:\>python -V
    Python 2.6.4

    Cảm ơn bạn đã hồi âm sớm

    • tuantub Says:

      Tớ nghĩ có thể là do cách tạo kết nối giữa windoof và linux khác nhau thôi, bên linux tớ cũng dùng bản 2.6🙂
      bên windoof thì bồ thử dùng đoạn code sau coi sao :
      http://paste.debian.net/57087/

  11. tquang Says:

    Đã thử và thấy tốt. Cảm ơn bạn

  12. tquang Says:

    Ha ha, hỗm rày theo dõi chủ yếu là code mà quên đi bài luận của bạn ở đầu.

    Sau khi ngồi xem dòng tự sự của bạn, mình thấy bạn cũng giống mình, chỉ có cái khác: một người viết code, một người dùng code.

    Mình cũng chỉ yêu thích 2 ngôn ngữ là Perl và Python mà thôi. Hai thằng này cực kỳ mạnh, nhưng xét về tiêu chuẩn thì Python là nhất vì nó nhẹ hơn Perl trong quá trình ứng dụng.

  13. nXqd Says:

    I do love Python🙂 , gonna learn it one day😛

    Nice script with legend wget🙂

  14. tquang Says:

    Không hiểu sao hết dùng được rồi bạn ơi. Có gì bạn check lại giúp nhé

    • tuantub Says:

      hi, thực ra việc không dùng được tớ đã biết từ cách đây một hai tháng gì đó và đã sửa lại code để dùng, mỗi cái là chưa up lên🙂. Nguyên nhân là bên zing.mp3 đã đưa vào một cơ chế kiểm tra trình duyệt sử dụng và không chấp nhận “trình duyệt” python nên vậy. Tớ đã sử lại code (đã chỉnh lại thẳng trong bài viết) bằng cách fake để đầu kia tưởng đầu này dùng firefox và đã có thể down được.
      Chúc vui.

      • tuantub Says:

        Chú ý: nếu dùng windoof thì bồ chỉ cần thay hàm httpDownloader của script cho windoof là được🙂

  15. tquang Says:

    Lâu lắm rồi mới quay lại trang của bạn, để mình test thử code trên Mac xem sao.

    Năm mới vui vẻ nhé bạn. Trang này mình bookmark cũng từ lúc mới vào, nay kiểm tra lại bookmark thì nhớ …..😀


Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s

%d bloggers like this: