日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java爬虫系列之实战:爬取酷狗音乐网 TOP500 的歌曲(附源码)

發(fā)布時間:2023/12/29 java 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java爬虫系列之实战:爬取酷狗音乐网 TOP500 的歌曲(附源码) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在前面分享的兩篇隨筆中分別介紹了HttpClient和Jsoup以及簡單的代碼案例:

  • Java爬蟲系列二:使用HttpClient抓取頁面HTML
  • Java爬蟲系列三:使用Jsoup解析HTML

今天就來實戰(zhàn)下,用他們來抓取酷狗音樂網(wǎng)上的 Top500排行榜音樂。接下來的代碼中除了會用到HttpClient和Jsoup之外,還會用到log4j和ehcache,分別用來記錄日志和實現(xiàn)緩存,如果看官對這兩個不是很熟悉的話,請自行百度,現(xiàn)在網(wǎng)上的入門實例有很多,我就不專門記筆記了。

?

那為什么會想到爬取酷狗音樂網(wǎng)呢?其實也不是我想到的,而是不久前看過某位大神的博客就是爬取酷狗的(具體哪位大神不記得了,見諒哈~~~),我也想用自己的代碼試試,并且我看的博客里面好像沒有用到緩存,也沒有用到代理ip這種反反爬蟲的工具,我會在我的爬蟲程序里面補(bǔ)上,親測能自動處理全部23頁的歌曲(但是付費歌曲由于必須登錄購買才能訪問,因此未能下載到,只有其他的400+首非付費歌曲可以正常下載),所以酷狗網(wǎng)的工作人員不要擔(dān)心哦~~~

話有又說回來了,在那篇博客出來后,也沒見酷狗音樂去專門處理下,還能給我留下寫這段代碼的機(jī)會,說明人家酷狗不在乎,畢竟付費歌曲是不能爬取的,而且網(wǎng)站已經(jīng)有了一定的反爬蟲機(jī)制。

***************************************************************************

?聲明:

本爬蟲程序和程序爬取到的內(nèi)容僅限個人學(xué)習(xí)交流使用,

請勿用于商業(yè)用途,否則后果自負(fù)

***************************************************************************

好,廢話不多說,該上干貨了~~

================很華麗的分割線=================

一、設(shè)計思路

首先說下思路,我看過的那篇博客沒有把過程寫詳細(xì),我就把它補(bǔ)充下吧:

1.點進(jìn)去Top500排行榜,它的地址欄里面是:https://www.kugou.com/yy/rank/home/1-8888.html?from=homepage,而這個1其實就是頁碼,訪問第N頁就把1改成N就行,這個是我爬取的基礎(chǔ)

2.點具體某首歌曲,比如《你的酒館對我打了烊》,新打開頁面:https://www.kugou.com/song/#hash=BE1E1D3C2A46B4CBD259ACA7FF050CD3&album_id=14913769,

3.我們F12分析下網(wǎng)絡(luò)請求(啥?打開F12沒東西?大哥呀你不會再刷新下嗎),

你會發(fā)現(xiàn)有個耗時很長的請求,而且類型是media,它很可能就是真正獲取mp3的請求

仔細(xì)看,果然是的,mp3的真實地址是:http://fs.w.kugou.com/201905272134/9d4d81230e6f5c759df51618b03961a7/G126/M00/05/09/HocBAFxLAoeAT3BzAD1nWyW7V5M814.mp3

關(guān)掉頁面,重新進(jìn)入該頁面,MP3的真是地址是:http://fs.w.kugou.com/201905272139/2897cc9816b82f4cda304d927187b282/G126/M00/05/09/HocBAFxLAoeAT3BzAD1nWyW7V5M814.mp3

根據(jù)這個看不出來啥

?

繼續(xù)分析,那它是怎么找到這個真實地址的呢?應(yīng)該是前面的某個請求里面獲取到了真實地址,找前面的請求:

這個請求的response里面含有MP3的真實地址,

請求的request為:

https://wwwapi.kugou.com/yy/index.php?r=play/getdata&callback=jQuery19106506492572547629_1558964792005&hash=BE1E1D3C2A46B4CBD259ACA7FF050CD3&album_id=14913769&dfid=3LWatj1PQwvn09grkH3FbFAF&mid=31adc5218ff6a510b05aacad71bc7090&platid=4&_=1558964792007

退出重新獲取一次,然后再退出換首歌再獲取一下這個request,你會發(fā)現(xiàn)一些規(guī)律:

粉紅色是歌曲播放頁面地址欄里面的內(nèi)容,加粗部分是日期的long值,其他的都可以不變(“jQuery19106506492572547629_1558964792005”雖然每次有變化,但是經(jīng)過嘗試,其實沒有影響),

所以我們就可以通過請求這個鏈接來獲取帶有MP3真實地址的json,然后請求真實地址,從而獲取音樂文件。

?

4.那粉紅色部分的值怎么獲取呢?查看top500的列表頁的源碼會發(fā)現(xiàn)有段內(nèi)容,這個里面記錄的第N頁所有歌曲的hash值、歌曲名、id等基本信息

// 列表數(shù)據(jù) global.features = [{"Hash":"BE1E1D3C2A46B4CBD259ACA7FF050CD3","FileName":"\u9648\u96ea\u51dd - \u4f60\u7684\u9152\u9986\u5bf9\u6211\u6253\u4e86\u70ca","timeLen":251.048,"privilege":10,"size":4024155,"album_id":14913769,"encrypt_id":"tlk6517"},{"Hash":"9198B18815EE8CE42AE368AE29276F78","FileName":"\u9648\u96ea\u51dd - \u7eff\u8272","timeLen":269.064,"privilege":10,"size":4314636,"album_id":15270740,"encrypt_id":"txskm8f"},{"Hash":"458E9B9F362277AC37E9EEF1CB80B535","FileName":"\u738b\u742a - \u4e07\u7231\u5343\u6069","timeLen":322.011,"privilege":10,"size":5152644,"album_id":18712576,"encrypt_id":"vsdz726"},{"Hash":"7E91FDE7E8D33E8ED11C6DB4620917E2","FileName":"\u5b64\u72ec\u8bd7\u4eba - \u6e21\u6211\u4e0d\u6e21\u5979","timeLen":182.23,"privilege":10,"size":2916145,"album_id":14624971,"encrypt_id":"th6cka5"},{"Hash":"9681F4CCD830B8436DB5F8218C7DF0C7","FileName":"\u864e\u4e8c - \u4f60\u4e00\u5b9a\u8981\u5e78\u798f","timeLen":259.066,"privilege":10,"size":4155201,"album_id":12249679,"encrypt_id":"rniv71f"},{"Hash":"44ABEAA9CCE29AFB5C947D4FBD2C567F","FileName":"\u5927\u58ee - \u4f2a\u88c5","timeLen":301.004,"privilege":10,"size":4817151,"album_id":15999493,"encrypt_id":"u6n6i28"},{"Hash":"5FCE4CBCB96D6025033BCE2025FC3943","FileName":"\u5468\u6770\u4f26 - \u544a\u767d\u6c14\u7403","timeLen":215,"privilege":10,"size":3443771,"album_id":1645030,"encrypt_id":"d5c5m23"},{"Hash":"0A62227CAAB66F54D43EC084B4BDD81F","FileName":"\u5468\u6770\u4f26 - \u7a3b\u9999","timeLen":223.582,"privilege":10,"size":3577344,"album_id":960399,"encrypt_id":"74itc7"},{"Hash":"A11F7A8BD2EA5BBDB32F58A9081F27B4","FileName":"\u82b1\u59d0 - \u72c2\u6d6a","timeLen":181.037,"privilege":10,"size":2902317,"album_id":13476703,"encrypt_id":"sfzob9f"},{"Hash":"33EB8FE0DC9F70D9F7FE4CB77305D5A8","FileName":"\u6d77\u6765\u963f\u6728\u3001\u963f\u5477\u62c9\u53e4\u3001\u66f2\u6bd4\u963f\u4e14 - \u522b\u77e5\u5df1","timeLen":280.111,"privilege":10,"size":4482365,"album_id":16324799,"encrypt_id":"uajki71"},{"Hash":"76D04F195C1F081CC0CD027A310A7D9A","FileName":"\u738b\u742a - \u7ad9\u7740\u7b49\u4f60\u4e09\u5343\u5e74","timeLen":381.083,"privilege":10,"size":6109771,"album_id":13886090,"encrypt_id":"sunkg88"},{"Hash":"9C00A468D2658487DB2DE4ED16A12B5A","FileName":"\u738b\u8d30\u6d6a - \u50cf\u9c7c","timeLen":285.031,"privilege":10,"size":4565459,"album_id":13621986,"encrypt_id":"smhia84"},{"Hash":"4F76587A5B0B93EEF15883E54DD3E2DB","FileName":"\u6bdb\u4e0d\u6613 - \u6d88\u6101 (Live)","timeLen":179,"privilege":10,"size":2870658,"album_id":2900867,"encrypt_id":"gf96d56"},{"Hash":"8B7DF540F77042FB76DA1EE3A79EAE0A","FileName":"NCF-\u827e\u529b - \u9ece\u660e\u524d\u7684\u9ed1\u6697 (\u5973\u58f0\u7248)","timeLen":145.058,"privilege":10,"size":2329748,"album_id":17997426,"encrypt_id":"twhgf05"},{"Hash":"7A3269C36D07E88A24FB35D246856FA4","FileName":"Yusee\u897f - \u5fc3\u5982\u6b62\u6c34","timeLen":182.883,"privilege":10,"size":2926594,"album_id":19692772,"encrypt_id":"wd07h77"},{"Hash":"7995A2173ED0914868BB860F93C3D642","FileName":"\u9b4f\u65b0\u96e8 - \u4f59\u60c5\u672a\u4e86","timeLen":216.189,"privilege":10,"size":3459539,"album_id":20709823,"encrypt_id":"wnru4c8"},{"Hash":"D8E40DA7F51C0486224E008A3B6ABD45","FileName":"\u5154\u5b50\u7259 - \u5c0f\u767d\u5154\u9047\u4e0a\u5361\u5e03\u5947\u8bfa","timeLen":163.087,"privilege":10,"size":2622454,"album_id":12492325,"encrypt_id":"rrrbccf"},{"Hash":"D2462B148305FF7D990F3B6EB3F90D66","FileName":"\u5f20\u656c\u8f69 - \u53ea\u662f\u592a\u7231\u4f60","timeLen":254.302,"privilege":10,"size":4080941,"album_id":558311,"encrypt_id":"3f65bd"},{"Hash":"03FE01457005CEEF8627BE5E5313D230","FileName":"\u84dd\u4e03\u4e03 - \u9ece\u660e\u524d\u7684\u9ed1\u6697 (\u5973\u58f0\u7248)","timeLen":111.986,"privilege":10,"size":1792253,"album_id":19842582,"encrypt_id":"w8lwi96"},{"Hash":"96E064A41AB84EBE4C03C6AAE3CB9334","FileName":"\u5f20\u7d2b\u8c6a - \u53ef\u4e0d\u53ef\u4ee5","timeLen":240.093,"privilege":10,"size":3855453,"album_id":9618875,"encrypt_id":"mkt6v7f"},{"Hash":"5D6CCE061BD65404BF5669FDD26C40B1","FileName":"\u4e01\u8299\u59ae - \u53ea\u662f\u592a\u7231\u4f60","timeLen":247.797,"privilege":10,"size":3965342,"album_id":18231730,"encrypt_id":"vhrxi30"},{"Hash":"95B48A0894FC2198B6E2B93C034AAC72","FileName":"\u5468\u6770\u4f26 - \u9752\u82b1\u74f7","timeLen":239.046,"privilege":10,"size":3825206,"album_id":979856,"encrypt_id":"7a6sd6"}];

把這些信息獲取后放到ehcache緩存,hash為key,album_id為value,循環(huán)單個歌曲的時候播放頁也能獲取到hash,然后根據(jù)hash到緩存里面取值即可

5.根據(jù)以上獲取的信息就可以正常爬取文件了,但是在爬取了一段時間后會發(fā)現(xiàn)無法正常下載了,在log中看到請求不到MP3的真實地址, 返回的json報文里面error_code不為0,這個就是爬蟲程序被網(wǎng)站識別了,這就要用到代理ip了,當(dāng)被識別出后就換個代理ip,如此循環(huán)下去直到歌曲輪詢完或代理ip被用完為止。

?

二、核心代碼展示

有了思路之后,就可以寫代碼了,由于篇幅原因,這里只貼出部分核心代碼,完整代碼請在下面的gitee上獲取

代碼結(jié)構(gòu):

  • 需要的依賴

    <!-- httpclient 抓取html --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.8</version></dependency><!-- Jsoup 解析html--><dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.11.3</version></dependency><!-- 用來下載歌曲,就不用自己寫流操作了 --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency><!-- fastjson用來處理json --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.58</version></dependency><!-- ehcache用作緩存 --><dependency><groupId>net.sf.ehcache</groupId><artifactId>ehcache</artifactId><version>2.10.6</version></dependency><!-- 引入slf4j-nop 純粹是防止ehcache執(zhí)行報錯 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-nop</artifactId><version>1.7.2</version></dependency><!-- log4j作為日志系統(tǒng) --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>

    ?

  • 主類

    package com.sam.kugou.main;import java.util.List;import org.apache.log4j.Logger; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements;import com.alibaba.fastjson.JSONObject; import com.sam.kugou.utils.DownLoadMusic; import com.sam.kugou.utils.EhcacheUtil; import com.sam.kugou.utils.HttpClientUtil;public class KugouSpiderMain {static final Logger logger = Logger.getLogger(KugouSpiderMain.class);static String URL_TEMP = "https://www.kugou.com/yy/rank/home/PAGE_NUM-8888.html?from=homepage";public static final int SLEEP_TIME_WHEN_DENY = 1000*60*60;//被網(wǎng)站識別后睡眠時間public static final int SPIDER_DURING = 1;//隔多久爬取下一首,單位:mspublic static final String DIR_NAME = "E:\\personal\\音樂\\酷狗\\";//音樂下載地址public static void main(String[] args) {//酷狗TOP500頁面try {for (int i = 1; i <= 23; i++) {String url = URL_TEMP;url = url.replace("PAGE_NUM", i + "");/*** 1.請求歌曲列表*/logger.info(url);String html = HttpClientUtil.getHtml(url);logger.debug(html);/*** 2.獲取該頁的hash和id 放到緩存*/int beginIdx = html.indexOf("global.features = ");int endIdx = html.indexOf("];", beginIdx);String features = html.substring(beginIdx, endIdx + 1).replace("global.features = ", "");logger.info("containingOwnText >>>>>> " + features);List<JSONObject> list = JSONObject.parseArray(features, JSONObject.class);for (JSONObject jsonObject : list) {String hash = (String) jsonObject.get("Hash");Integer albumId = (Integer) jsonObject.get("album_id");EhcacheUtil.setCache(hash, albumId);}/*** 3.解析列表內(nèi)容*/Document doc = Jsoup.parse(html);Elements songList = doc.select(".pc_temp_songlist ul li a");for (Element element : songList) {String title = element.attr("title");String href = element.attr("href");if(href.contains("https")) {try {Thread.sleep(SPIDER_DURING);} catch (InterruptedException e) {logger.error(e.getMessage());}logger.info("title " + title +" >>> href " + href);DownLoadMusic.requestMusic(title, href);}}}} catch(Exception ex) {logger.error(ex.getMessage(), ex);} finally {/**** 4.關(guān)閉*/EhcacheUtil.shutDownManager();}}}

    ?

  • 獲取真實地址

    ?

  • 執(zhí)行下載

    public static void downLoad(String title, String url) {if(url == null || url.equals("")) {return ;}//已經(jīng)完成的就不再重新下載Element finishedCache = EhcacheUtil.getFinishedCache(title);logger.debug("finishedCache >>>>> " + finishedCache);if(finishedCache != null) {logger.info("歌曲已經(jīng)存在!!!");return;}String suffix = url.substring(url.lastIndexOf("."));try {HttpEntity httpEntity = HttpClientUtil.getHttpEntity(url);InputStream inputStream = httpEntity.getContent();String filePath = KugouSpiderMain.DIR_NAME+title+suffix;FileUtils.copyToFile(inputStream, new File(filePath));logger.info("***完成下載:***"+title+suffix);logger.info("***總歌曲數(shù)量:***"+(new File(KugouSpiderMain.DIR_NAME)).list().length);EhcacheUtil.setFinishedCache(url, title);} catch (IOException e) {logger.error(e.getMessage());}}

    ?

  • 設(shè)置代理ip

    public static boolean setProxy() {// 1.創(chuàng)建一個httpClientCloseableHttpClient httpClient = HttpClients.createDefault();CloseableHttpResponse response = null;String url = "https://raw.githubusercontent.com/fate0/proxylist/master/proxy.list";try {response = doRequest(httpClient, url);logger.debug("getHtml " + url + "**處理結(jié)果:**" + response.getStatusLine());// 5.判斷返回結(jié)果,200, 成功if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {HttpEntity httpEntity = response.getEntity();String html = EntityUtils.toString(httpEntity, "utf-8");html = "["+html+"]";List<JSONObject> list = JSONArray.parseArray(html, JSONObject.class);for (JSONObject jsonObject : list) {int port = Integer.valueOf(jsonObject.get("port").toString());String host = jsonObject.get("host").toString();logger.info(host + ":"+port);if(isHostConnectable(host, port)) {//代理ip可以連接Element ipsCache = EhcacheUtil.getProxyIpsCache(host, port);//代理ip未使用過if(ipsCache == null) {proxyIp = host;proxyPort = port;EhcacheUtil.setProxyIpsCache(host, port);break;} else {logger.info("該代理ip已經(jīng)使用過,切換下一個");}}}}} catch (Exception e) {logger.error(e.getMessage(),e);return false;} finally {// 關(guān)閉HttpClientUtils.closeQuietly(response);HttpClientUtils.closeQuietly(httpClient);}logger.info("切換代理ip成功:>>>" + proxyIp + ":" + proxyPort);return true;}

    ?

  • 三、源碼?

    留言源碼 謝謝

    ?四、遺留問題

    1.只能抓取到免費歌曲,對于收費歌曲不能抓取,其實我們也不該抓取

    2.代碼中為了方便用了很多static,不能支持多線程或并發(fā)抓取

    3.其實代理IP那里可以優(yōu)化的


    聲明:

    本爬蟲程序和程序爬取到的內(nèi)容僅限個人學(xué)習(xí)交流使用,請勿用于商業(yè)用途,否則后果自負(fù)!!!謝謝

    總結(jié)

    以上是生活随笔為你收集整理的Java爬虫系列之实战:爬取酷狗音乐网 TOP500 的歌曲(附源码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。