一、简介
近日,迷惑墙报道了一个神奇的网站,网站域名为www.ustcnet.com ,没错,就是ustcnet…访问网站之后发现,该网站的ustc实际上是指Unexceptionable Songs Taken from Cartoon,看到这么多好听的动漫歌曲并且可以直接下载,肥宅病顿时复发了😆😆😆,博主遂决定写一个爬虫来批量下载所有的歌曲,以作收藏。遗憾的是,该网站从2014年开始已经停更了,所以内容较少。
二、使用的环境
python3.9.0
re库(正则表达式)
requests库(请求特定网页)
threading库(多线程爬取,加快速度)
bs4库(主要使用BeautifulSoup解析网页结构)
三、网页解析
1、获取网页的最大页数
在网站主页最底部可以看到,会显示网站的最大页数以及当前页数,因此可以在源码中找到这些信息。点击鼠标右键查看网页源代码,ctrl+F搜索“/2 ",就能在网页源码中找到该位置。如图:
有了这一信息之后,就可以使用正则表达式在获取到的网页源码文本中搜索相关信息,从而找到最大页面,使用的表达式是:
1 pattern=re.compile (r'(?<=</b></font>/)\d+' )
其中表达式(?<=exp)表示的是先定位到exp表达式的位置,然后从后面开始匹配,\d+表示匹配1到多个数字,满足贪婪匹配。然后通过该表达式对获取的网页源码进行匹配,就能够得到最大页数。
2、获取每一页的url形式
在主页上点击下一页,可以很容易地发现网站每一页网页的形式为:
1 'http://www.ustcnet.com/index.asp?page={}' .format (page_count)
同时有了最大页数,就可以批量生成网站每一页地url,然后对每页进行访问提取需要的信息。
3、获取每首歌曲的相关信息
通过网页调试工具发现,网页每一首歌曲的信息存放在一条tr 标签中,同时可以根据标签的onmouseover 属性来定位这一标签。
每个tr 标签中包含一系列td 标签,第2、3、4个td 标签分别存储了歌曲的歌曲名、歌曲出处和歌手。
有了这些信息之后,就可以通过BeautifulSoup 查找这些标签,从而获取这些信息,用于文件的命名。
4、获取下载的链接
通过网页调试工具发现,歌曲的下载链接存放在target 属性为_blank的a 标签中,因此获得了这一链接之后就可以批量生成每一首歌曲的下载链接。
这里还有一个小插曲,点进去这个链接之后不是直接下载,而是跳到了一个新的页面,如图,在这个页面中的a 标签存放着歌曲下载的正确的url。
四、代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 import reimport requestsimport threadingfrom bs4 import BeautifulSoupdef GetHtmlText (url ): try : user_agent = {'user-agent' :'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36' } rspon = requests.get(url, headers = user_agent) rspon.encoding = 'GBK' rspon.raise_for_status() except : print ('网页获取失败:' , rspon.status_code) return None return rspon def GetMaxPageCount (): max_page_count = 0 url = 'http://www.ustcnet.com/' html=GetHtmlText(url) if html==None : return max_page_count pattern=re.compile (r'(?<=</b></font>/)\d+' ) match=pattern.search(html.text) max_page_count=int (match.group(0 )) return max_page_count def SaveSongInUrl (song_url,song_name,song_path ): source = GetHtmlText(song_url) if source == None : return file_name = '{}.wma' .format (song_name) file = open (song_path+file_name, "wb" ) file.write(source.content) file.close() def GetOnePageSong (page_count, song_path ): url = 'http://www.ustcnet.com/index.asp?page={}' .format (page_count) suop = BeautifulSoup(GetHtmlText(url).text, 'html.parser' ) tag_container = suop.find_all('tr' , {'onmouseover' :'this.style.backgroundColor=\'#eeeeee\'' }) thread_list=[] for child in tag_container: tag_song_inf=child.find_all('td' ) song_number=tag_song_inf[0 ].string song_name=tag_song_inf[1 ]['title' ] song_from=tag_song_inf[2 ]['title' ] song_sing=tag_song_inf[3 ].string file_name=song_name+'_' +song_from+'_' +song_sing tag_download=child.find('a' ,{'target' :'_blank' }) download_url='http://www.ustcnet.com/' +tag_download.attrs['href' ] target_soup=BeautifulSoup(GetHtmlText(download_url).text, 'html.parser' ) target_a=target_soup.find('a' ) if target_a==None : continue target_url=target_a.attrs['href' ] t=threading.Thread(target=SaveSongInUrl,args=(target_url,file_name,song_path)) t.start() thread_list.append(t) print ('page:{}\tnumber:{}\tthreading num:{}\tis downloading...' .format (page_count,song_number,len (thread_list))) alive_thread_count=len (thread_list) while alive_thread_count>5 : for i in thread_list: if not i.is_alive(): alive_thread_count-=1 thread_list.remove(i) print ('{} downloading threading remain...' .format (alive_thread_count)) alive_thread_count=len (thread_list) while alive_thread_count>0 : for i in thread_list: if not i.is_alive(): alive_thread_count-=1 thread_list.remove(i) print ('{} downloading threading remain...' .format (alive_thread_count)) def GetAllPageSong (song_path ): max_page_count = GetMaxPageCount() for page_index in range (1 , max_page_count+1 ): GetOnePageSong(page_index, song_path) def main (): song_path='E:/ustcnetsong/' GetAllPageSong(song_path) main()
运行发现有些歌曲下载时会出现404错误,访问网站发现是由于网站本身的原因。