Xây dựng một trang web tải nhạc từ youtube bằng Python Flask và BeautifulSoup

Sản phẩm sau khi làm

http://coffeetube.herokuapp.com/

Yêu cầu

Nói chung thì giờ download nhạc từ youtube thì nó có vô số cách rồi. Nhưng tự mình làm một trang web của riêng mình để download thì cảm giác nó vẫn ... cool ngầu hơn nhỉ?

Mục tiêu của mình là xây dựng một trang download nhạc từ youtube có khả năng như sau:

  • Có khả năng tìm kiếm.
  • Trả về một list các clip sau khi tìm kiếm - phải có ảnh thumbnail.
  • Lười nên mình còn muốn nó có gợi ý để mình không cần phải gõ hết chữ ra mới tìm được.

Thư viện cần dùng

flask
requests
youtube_dl
bs4

Hosting

Heroku
Đây là một trang hosting cho nhiều loại ngôn ngữ, mình nghĩ có khá nhiều bài viết về trang này rồi. :smile:

Hành động

Tạo trang chủ

Đầu tiên mình tạo ra một trang html đơn giản gồm một form tìm kiếm (phần trang trí là mình lượm nhặt khá ngu).

Để form tìm kiếm có thể suggestion được, mình dùng 1 free api key trên google và sử dụng script này:

$(document).ready(function(){
$("#youtube").autocomplete({
source: function(request, response){
/* Google Developer ID (optional) */
var apiKey = 'AI39si7ZLU83bKtKd4MrdzqcjTVI3DK9FvwJR6a4kB_SW_Dbuskit-mEYqskkSsFLxN5DiG1OBzdHzYfW0zXWjxirQKyxJfdkg';
/* Search keyword */
var query = request.term;
/* youtube sorgusu */
$.ajax({
url: "http://suggestqueries.google.com/complete/search?hl=en&ds=yt&client=youtube&hjson=t&cp=1&q="+query+"&key="+apiKey+"&format=5&alt=json&callback=?",
dataType: 'jsonp',
success: function(data, textStatus, request) {
response( $.map( data[1], function(item) {
return {
label: item[0],
value: item[0]
}
}));
}
});
},
/* You can use transaction is selected here to */
select: function( event, ui ) {
$.youtubeAPI(ui.item.label);
}
});
$('button#submit').click(function(){
var value = $('input#youtube').val();
$.youtubeAPI(value);
});
$.youtubeAPI = function(kelime){
var sonuc = $('#sonuc');
sonuc.html('Arama gerçeklestiriliyor...');
$.ajax({
type: 'GET',
url: 'http://gdata.youtube.com/feeds/api/videos?q=' + kelime + '&max-results=15&v=2&alt=jsonc',
dataType: 'jsonp',
success: function( veri ){
if( veri.data.items ){
sonuc.empty();
$.each( veri.data.items, function(i, data) {
sonuc.append('<div class="youtube">\
<img src="' + data.thumbnail.sqDefault + '" alt="" />\
<h3><a href="javascript:void(0)" onclick="$.youtubePlay(\'' + data.id + '\', \'' + data.content[5] + '\')">' + data.title + '</a></h3>\
<p>' + data.description + '</p>\
</div>\
<div class="youtubeOynat" id="' + data.id + '"></div>');
});
}
else {
sonuc.html('<div class="hata"><strong>' + kelime + '</strong> ile ilgili hiç video bulunamadi!</div>');
}
}
});
}
$.youtubePlay = function(yid, frame){
$('.youtubeOynat').slideUp().empty();
$('#'+yid).slideDown().html('<iframe src="'+ frame +'&autoplay=1" style="width: 100%; box-sizing: border-box; height: 300px" />');
}
});

Trong route index ở file app.py, mình return về template index.html.

@app.route('/', methods=['GET'])
def main():
return render_template('index.html',year = year)

alt text

Xử lí dữ liệu đã search

@app.route('/result', methods=['POST','GET'])
def result():
search = request.form['youtube']
try:
query_string = urllib.parse.urlencode({"search_query": search})
page = requests.get("http://www.youtube.com/results?" + query_string)
soup = BeautifulSoup(page.content, 'html.parser')
display = {}
for vid in soup.find_all(class_="yt-lockup-content"):
print(vid)
#print(vid.find("a")["href"])
#print(vid.find("a")["title"])
print(vid.find(class_="yt-lockup-description yt-ui-ellipsis yt-ui-ellipsis-2"))
if vid.find(class_="yt-lockup-description yt-ui-ellipsis yt-ui-ellipsis-2") is not None:
des = vid.find(class_="yt-lockup-description yt-ui-ellipsis yt-ui-ellipsis-2").get_text()
else:
des = " "
link = "https://youtube.com"+vid.find("a")["href"]
thumbnail = "http://img.youtube.com/vi/%s/0.jpg" % vid.find("a")["href"][9:]
display[vid.find("a")["title"]] = [thumbnail,des,link]
except EnvironmentError:
print('NO')
return render_template('result.html', display = display,year = year)

Sau khi nhận được đoạn text từ form search của trang chủ. Mình dán đoạn text đó vào sau youtube.com/results? và sử dụng Beautifulsoup (Một thư viện của python dùng để scrape dữ liệu) để scrape dữ liệu của trang đó.

Sau đó mình lưu lại thumbnail, link, description và tittle của clip đó.

Trang result

Nếu bạn vào file result.html. Bạn sẽ thấy mình dùng một vòng lặp for để tải những dữ liệu mà mình đã lưu từ def result lên.

Trên thực tế, toàn trang đó cũng lại là một cái form rất lớn. Mỗi thumbnail và link là một cái button chứa value là đường link của clip đó. Khi mà người dùng bấm vào ảnh hoặc đường link. Nó sẽ gửi một POST request đến route download.

Xử lí dữ liệu được gửi từ result

@app.route('/download', methods=['POST','GET'])
def download():
url = request.form["song"]
options = {
'format': 'bestaudio/best', # choice of quality
'outtmpl': '%(id)s', # name the file the ID of the video
} # only download single song, not playlist

ydl = youtube_dl.YoutubeDL(options)
song_name = ydl.extract_info(url, download=False)
savepath = make_savepath(song_name['title'].replace(" ", ""))
savepath = re.sub('[^A-Za-z0-9]+', '', savepath)
savepath = make_savepath((savepath))
with ydl:
    result = ydl.extract_info(url, download=True)
    os.rename(result['id'], savepath)
    print("Downloaded and converted %s successfully!" % savepath)
    try:
        return send_file(savepath,savepath, as_attachment=True)
    except Exception as e:
        return str(e)

Nhận được link clip từ trang result. Mình sử dụng thư viện youtubedl để tải mp3 về. dùng Regex để xóa ký tự đặc biệt. Sau đó send_file ngược lại cho người dùng là xong.

Cuối cùng, mình chạy web flask bằng cách:

if __name__ == '__main__':
port = int(os.getenv('PORT', 8000))
print("Starting app on port %d" % port)
app.run(debug=False, port=port, host='0.0.0.0')

Push lên heroku

Mình tạo 2 file Procfile và requirements.

File Procfile bao gồm cách để bạn chạy chương trình. Ở đây mình ghi: web: python app.py

Còn requirements là những thư viện mình cần phải dùng.

Bạn đăng kí một tài khoản heroku. Sau đó link nó với github repository mà bạn đã sử dụng. Để chế độ auto deploy, vậy là xong!

alt text

Github

https://github.com/PhiHuyHoang/youtubedownload

Chúc các bạn thành công. :smile:

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Rice

7 bài viết.
12 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
White
7 4
Trước giờ logic code của mình vẫn luôn dễ dãi như gái làng chơi nên đôi khi nó đã support thêm cho mình cái đức tính càng lúc càng không (thèm) kiê...
Rice viết 2 tháng trước
7 4
White
4 0
Mục tiêu Mình muốn làm một chương trình: Đọc rss (definition and usage of rss :arrow_right: https://en.wikipedia.org/wiki/RSS) Lựa chọn những ...
Rice viết 30 ngày trước
4 0
White
2 0
Hôm nay mình lang thang trên CodeWar và nhặt được mấy bài code khá thú vị. Vì mình quen dùng python nên rất thích làm sao có thể giải trong 1 line ...
Rice viết 28 ngày trước
2 0
Bài viết liên quan
White
2 0
Web crawling là gì? _Web crawling_ là quá trình tự động trích xuất các thông tin từ các trang web và lưu trữ nó dưới một định dạng phù hợp. Chương...
Đinh Văn Cảnh viết 9 tháng trước
2 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
7 bài viết.
12 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!