改进后的多线程百度 top 500 mp3抓取程序

148 views
Skip to first unread message

havea...@126.com

unread,
Jun 6, 2006, 1:51:11 AM6/6/06
to python.cn
#哈哈,我都不用flashget了,我这个程序就可以工作得很好,拿来抓歌很不错的
#这本版本主要修改了上一次的一些Bug,而且增加了多线程下载功能
#
上个版本获取地址是通过字符串分析,这次改为用正则
# 有什么值得再改进的地方,大家一定多提意见


#-*- coding: GB2312 -*-

#百度歌曲MP3 top 500批量下载

import urllib, re,sys,os,os.path,getopt
threadNum = 45 #线程数
toDownNum=75 #要下载的mp3的数目,不要超过500哦
savePath = "mp3-2"
if (not os.path.exists(savePath)):
os.makedirs(savePath)

url = "http://list.mp3.baidu.com/topso/mp3topsong.html"
def getUrlData(url):
num = 0
while (num<3):
num = num+1
try :
f = urllib.urlopen( url )
data = f.readlines()
f.close()
return data
except:
pass
return []

data = getUrlData(url)
pattern = re.compile( r'class="border"><a href="(.*)"' )
target = [];
i=0;
for line in data:
items = pattern.findall( line )
for item in items:
item=item.replace("lm=-1","lm=0")
target.append( item )
i+=1
if i>toDownNum: break;


print len( target )," mp3 to down "

mp3Pattern = re.compile( r' (http\:\/\/.*?\.mp3) ' )
titlePattern = re.compile( r'<title>.*?_(.*?)\s+</title>' )

import threading
lock = threading.Lock()
def getMp3():
while True:
t = ""
lock.acquire()
if ( len( target )>0 ):
t = target[0]
target.remove( t )
else :
return
lock.release()
tempUrl = t
data = getUrlData(tempUrl)
mp3Target = []
title = "";
for line in data:
if ( line.find( "title" )!=-1 ):
m = titlePattern.search( line )
if ( m ):
title = m.group( 1 )
break
for line in data:
if ( len( mp3Target )>10 ):
break
if ( line.find( ".mp3 " )!=-1 ):
items = mp3Pattern.findall( line )
for item in items:
mp3Target.append( item )
filename = savePath+"/"+title+".mp3"
for t in mp3Target:
try :
print "try to get "+title+".mp3,url=",t
ret = urllib.urlretrieve( t, filename )
size = os.path.getsize(filename)
if (size>1024*1024):
print "done:"+title+".mp3 from url: "+t
break
except :
print "fail to get "+title+".mp3 with url: "+t
pass

for num in range(threadNum):
thread = threading.Thread( None, getMp3 )
thread.start()
print "start thread ",num

Ericzhao82

unread,
Jun 6, 2006, 4:19:38 AM6/6/06
to pyth...@googlegroups.com
支持下。

可是前几天闹得纷纷扬扬的封杀迅雷事件,让我好奇使用了下迅雷,竟然发现他的一个插件"迅雷听听"很是不错,直接抓取百度的各种MP3分类,什么新歌100、歌曲500…………

现在公司M$系统下载,几乎不用FlashGet了。

--
…………………………………………
               Ericzhao

Email:   Ericz...@gmail.com
MSN:    Ericz...@hotmail.com

AKUAN

unread,
Jun 6, 2006, 1:12:36 PM6/6/06
to pyth...@googlegroups.com
不错,支持你..
其实以后能用到的小工具都应该用python做.....


 
   items = pattern.findall ( line )
               m = titlePattern.search ( line )

Cauchy Song

unread,
Jun 7, 2006, 5:03:35 AM6/7/06
to pyth...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

#-*- coding: UTF-8 -*-

# 百度歌曲MP3 top 500批量下载
#
# cauch...@gmail.com:
# 修改下载完成的判断方法,淘汰简单的认为大于1M就是下载完成的算法(原始
# 算法容易得到不完整下载的歌曲)
# 为了区分正在下载与已经完成的文件,对正在下载的文件增加"tmp"扩展名。
# 对于已经完成的歌曲,不再重复下载。
# 至于断点续传,就免了吧,歌曲重新下载的代价不大,实现续传的代价就大多了。
#
# havea...@126.com
# 原始版本。

import urllib, re, threading, os, os.path, getopt

threadNum = 12 #线程数(即同时下载歌曲数量)
savePath = "mp3_baidu"
url = "http://list.mp3.baidu.com/topso/mp3topsong.html"

lock = threading.Lock()
mp3Pattern = re.compile(r' (http\:\/\/.*?\.mp3) ')
titlePattern = re.compile(r'<title>.*?_(.*?)\s+</title>')

def getUrlData(url):
num = 0
while (num < 3):
num = num + 1
try:
f = urllib.urlopen(url)
data = f.readlines()
f.close()
return data
except:
pass
return []

def getMp3():
while True :

lock.acquire()
if (len(target) > 0):
tempUrl = target[0]
target.remove(tempUrl)
else:
return
lock.release()

data = getUrlData(tempUrl)
mp3Target = []
title = "";

# 取得歌曲的标题
for line in data:
if (line.find("title")!=-1 ):


m = titlePattern.search(line)
if (m):
title = m.group(1)
break

# 对于每首歌,最多尝试12个下载地址
for line in data:
if (len(mp3Target) > 12):
break
if (line.find(".mp3 ") != -1):
items = mp3Pattern.findall(line)
for item in items:
mp3Target.append(item)

fileName = savePath + "/" + title + ".mp3"

for t in mp3Target:
try:
print "try to get " + title + ".mp3, url =", t

# 已经完成,不再下载
if (os.path.exists(fileName)):
break;

# 删除不完全的下载文件
if (os.path.exists(fileName + ".tmp")):
os.remove(fileName + ".tmp")

(downloadName, headers) = urllib.urlretrieve(t, fileName + ".tmp")

mp3Length = long(headers["content-length"])
size = os.path.getsize(downloadName)

# 因为返回的多媒体文件类型千奇百怪,所以只能用至少为1M来判断
# 返回的是mp3文件,不是诸如出错信息等其它内容
if ((mp3Length > 1024 * 1024) and (size >= mp3Length)):
print "done: " + title + ".mp3 from url:" + t
os.rename(downloadName, fileName)
break

except Exception, e:
print e


print "fail to get "+title+".mp3 with url:" + t
pass

data = getUrlData(url)
target = []
pattern = re.compile(r'class="border"><a href="(.*)"')

for line in data:
items = pattern.findall(line)
for item in items:

item = item.replace("lm=-1", "lm=0") # ???
target.append(item)
pass

print len(target), " mp3 to download"

if (not os.path.exists(savePath)):
os.makedirs(savePath)

for num in range(threadNum):
thread = threading.Thread(None, getMp3)
thread.start()

print "start ", threadNum, " thread for download"
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (MingW32)

iD8DBQFEhpZL90pbDJCgbHoRAnLBAJ9XfTA764RRf2BwQYCKagAxjbB6AgCdECtd
hlBhD1CcjmzvdLhjg68P6p0=
=EYXH
-----END PGP SIGNATURE-----

havea...@126.com

unread,
Jun 7, 2006, 7:22:49 AM6/7/06
to python.cn
不错,修改后的版本比我原来的那个好用很多

hoxide Ma

unread,
Jun 7, 2006, 8:20:43 AM6/7/06
to pyth...@googlegroups.com
可以用队列Queue来代替你的target, 这样简化很多

havea...@126.com

unread,
Jun 7, 2006, 10:21:51 AM6/7/06
to python.cn

hoxide Ma 写道:

> 可以用队列Queue来代替你的target, 这样简化很多

不好意思,我是刚刚才学线程,有点班门弄斧的味道,
您能不能写一段关于用队列Queue的小示范代码让我研究一下呢

ghostwwl

unread,
Jun 7, 2006, 11:34:58 PM6/7/06
to python.cn
我觉得你这个里面有几点可以改进,我就不说多线程方面的了,
首先你可以考虑下加入日志功能,把已经下载的,和出错的
不能下的作记录
然后考虑下载链接的死链接问题,最好把要下的歌曲re的findall后
保存到一个任务列表
现在的时候,一任务列表为主,可以选择自己喜欢的,考虑以歌曲名:然后链接的形式
最任务列表,当然链接这里肯定可以是个list结构,储存多个地址,下的时候可以先判断速度
和死链接问题,自动选择最优链接。呵呵!

大熊

unread,
Jun 8, 2006, 12:39:56 AM6/8/06
to pyth...@googlegroups.com
保存使用的文件名可以考虑使用unicode对象,这样保存的文件在非简体系统上也不会文件名乱码

--
茫茫人海,你是我的最爱
Reply all
Reply to author
Forward
0 new messages