java爬虫——爬取抖音排行榜上的音乐

这次的目的是:将抖音排行榜上的音乐爬取下来

第一件事:分析网站的结构

java爬虫——爬取抖音排行榜上的音乐_第1张图片

分析之后得出的结论是:排行榜每首歌曲页面的地址都如下:

https://www.douyin.com/cnl_music/music_detail/?id=2 

每首歌曲的页面只是id的值不同,前面都是一样的

然后,我们需要拿到歌曲的名称和歌曲的地址,那么我们只需要取到id为vedio和id为musicName这两个元素即可

第二件事,爬取歌曲名称和歌曲地址

先上代码吧

package com.example.demo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

public class Test {
    public static void main(String[] args) {
        
        Map map = new HashMap<>();
        
        WebClient client = new WebClient(BrowserVersion.CHROME);
        client.getOptions().setUseInsecureSSL(true);
        client.getOptions().setJavaScriptEnabled(true);
        client.getOptions().setCssEnabled(false);
        client.getOptions().setThrowExceptionOnScriptError(false);
        client.getOptions().setThrowExceptionOnFailingStatusCode(false);
        client.getOptions().setActiveXNative(false);
        client.waitForBackgroundJavaScript(600*1000);
        client.setAjaxController(new NicelyResynchronizingAjaxController());
        client.getOptions().setDoNotTrackEnabled(false);
        client.getOptions().setTimeout(600*1000);
        try {
            
            for(int i=1; i<=19;i++) {
                String url = "https://www.douyin.com/cnl_music/music_detail/?id=";
                url = url +i;
                HtmlPage page = client.getPage(url);
                Thread.sleep(1000);
                String content = page.asXml();
                Document doc = Jsoup.parse(content);
                String music = doc.select("#video").attr("src");
                String musicName = doc.select("#musicName").text();
                map.put(musicName, music); 
            }
            
//            print(map);
            download(map);
            
        } catch ( Exception e) {
            e.printStackTrace();
        }
        
        client.close();
    }
    
    
    public static void print(Map map) {
        for(String name: map.keySet()) {
            System.out.print("歌曲:"+name+"  地址:"+map.get(name));
            System.out.println();
        }
    }
    
    
    public static void download(Map map) throws Exception {
        
        for(String name : map.keySet()) {
            String basePath = "f:/douyin/";
            String path = map.get(name);
            URL url = new URL(path);
            URLConnection connection = url.openConnection();
            InputStream inputStream = connection.getInputStream();
            FileOutputStream output = new FileOutputStream(new File(basePath+name+".mp3"));
            
            byte[] bytes = new byte[1024];
            
            int length = 0;
            while((length =inputStream.read(bytes))!= -1) {
                output.write(bytes, 0, length);
            }
            System.out.println("end");
            output.close();
            inputStream.close();
        }
    }
}

我一开始是使用jsoup来获取video这元素的,但是发现src的值和在控制台中看到的实际值不一致,后来才明白jsoup处理不了动态页面这种情况,比如利用js占位符,然后根据ajax形成的数据,jsoup是拿不到的

经过一番了解之后,采用了htmlUnit来获取完全加载之后的html,然后再用jsoup解析的方式来爬取,具体如上代码

总结:

httpUnit就相当于一个没有界面的浏览器,可以用来模拟浏览器的行为,支持复杂的ajax操作,拿到了完整的html之后,拿jsoup解析就非常方便了,jsoup支持css选择器,jquery选择器这些语法,非常方便,所以我觉得jsoup更适合用来解析html文档。

 

你可能感兴趣的:(java)