java獲取B站彈幕檔案的兩種方案

suhuanzhen發表於2019-02-27

(一)實現思路

1,定位彈幕檔案

一般用json或xml格式來儲存彈幕,所以我們只要找到視訊網頁裡面的xml檔案或json檔案,就能定位到彈幕檔案。

2,解析彈幕檔案

然後通過jsoup解析檔案,提取我們彈幕的文字內容。

(二)第一個實現方案,解析本地檔案

1,定位彈幕檔案

比如我們希望爬取下方視訊的彈幕檔案。

image.png

開啟Chrome的Network後重新整理網頁,再輸入框中輸入xml篩選出xml檔案資源:

image.png

游標移動到該檔案上,可以看到該檔案具體地址如下:

image.png

在該檔案上右鍵Open in new tab就可以在新的瀏覽器頁面檢視該彈幕檔案內容:

image.png

2,解析彈幕檔案

2.1 建立基本的maven專案
image.png

輸入GroupId和ArtifactId

image.png

本專案中會使用到jsoup這個jar包,於是在專案根目錄下建立lib目標,把jar拷貝進去,然後按下面操作將jar包構建到專案中:

image.png

選中該jar並點選OK。

image.png
2.2 在專案根目錄下建立彈幕檔案

在根目錄下建立3232417.xml檔案,複製https://comment.bilibili.com/3232417.xml彈幕頁面的內容,儲存到該檔案中。直接全選複製過去即可,我們後面解析檔案的時候只會提取有用的文字,所以第一行內容不用去除,如下:

image.png
2.3 程式碼實現

解析本地彈幕xml檔案的程式碼如下:

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.File;
import java.util.ArrayList;

/**
 * Created by shuhu on 2018/1/20.
 */
public class LocalFile {

    public static ArrayList<String> getData(String fileName){
        ArrayList<String> list = new ArrayList<String>();
        try{
            File input = new File(fileName);
            Document doc = Jsoup.parse(input, "UTF-8");
            //每條彈幕的內容都處於<d></d>標籤中,於是根據該標籤找到所有彈幕
            Elements contents = doc.getElementsByTag("d");

            for (Element content : contents) {
                list.add(content.text()); //將<d></d>標籤中的文字內容,也就是彈幕內容,新增到list中
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }
}
複製程式碼

在入口類Main.java中呼叫LocalFile類的getData方法,傳入引數為xml檔名,解析每條彈幕並輸出:

import java.util.ArrayList;

/**

 * Created by shuhu on 2018/1/20.

 */
public class Main {
    public static void main(String[] args){
        ArrayList<String> items = new ArrayList<String>();
        //1,通過解析本地檔案的方式得到所有彈幕

        items = LocalFile.getData("3232417.xml");

        //遍歷輸出每條彈幕

        for (String item : items) {
            System.out.println(item);
        }
    }
}
複製程式碼

輸出結果如下:

image.png

(三)第二個實現方案,解析遠端伺服器檔案

1,新增httpclient依賴

由於需要訪問遠端伺服器,所以用到了相關的依賴,該依賴提供了對http伺服器的訪問功能。在pom.xml檔案中新增:

    <dependencies>
        <!--提供了對http伺服器的訪問功能-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.3.3</version>
        </dependency>
    </dependencies>
複製程式碼

2,實現程式碼

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.util.ArrayList;

/**
 * Created by shuhu on 2018/1/20.
 */
public class RemoteFile {

    public static ArrayList<String> getData(String fileName)  throws IOException {
        ArrayList<String> list = new ArrayList<String>();
        //1,建立HttpClient物件,我們使用到Apache中的HttpClient的例項CloseableHttpClient
        CloseableHttpClient httpclient = HttpClients.createDefault();
        //2,建立HttpGet請求例項,該例項指示向目標URL發起GET請求
        HttpGet httpGet = new HttpGet(fileName);
        //3,執行HttpGet請求例項,也就是發起GET請求,響應結果儲存到httpResponse變數中
        CloseableHttpResponse httpResponse = httpclient.execute(httpGet);
        try {
            //4,得到彈幕檔案的檔案內容
            HttpEntity httpEntity = httpResponse.getEntity();
            String httpHtml = EntityUtils.toString(httpEntity);

            //5,解析彈幕檔案,把每條彈幕放入list中
            Document doc = Jsoup.parse(httpHtml, "UTF-8");
            Elements contents = doc.getElementsByTag("d");
            for (Element content : contents) {
                list.add(content.text()); //將<d></d>標籤中的文字內容,也就是彈幕內容,新增到list中
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpResponse.close();
        }
        return list;
    }
}
複製程式碼

CloseableHttpResponse httpResponse = httpclient.execute(httpGet);執行完GET請求後,響應結果存放在httpResponse中。response.getEntity()是響應結果中的訊息實體,因為響應結果中還包含其他內容比如Headers等如下圖,這裡我們只需要關注getEntity()訊息實體即可。

image.png

EntityUtils.toString(response.getEntity());返回的是服務端以流的形式寫出的響應內容,比如在服務端呼叫的方法最後為:responseWriter.write("just do it");那麼EntityUtils.toString(response.getEntity());獲取的就是just do it 這句話。
這裡可以簡單理解為網頁的html程式碼,即右鍵檢視網頁原始碼看到的全部html程式碼。我們需要解析的就是這樣的html程式碼。

在入口類Main.java中呼叫RemoteFile類的getData方法,傳入引數為xml檔名,解析每條彈幕並輸出:

import java.util.ArrayList;

/**

 * Created by shuhu on 2018/1/20.

 */
public class Main {
    public static void main(String[] args){
        ArrayList<String> items = new ArrayList<String>();
        //1,通過解析本地檔案的方式得到所有彈幕

//        items = LocalFile.getData("3232417.xml");


        //2,通過解析遠端伺服器檔案的方式得到所有彈幕

        items = RemoteFile.getData("https://comment.bilibili.com/3232417.xml");

        //遍歷輸出每條彈幕

        for (String item : items) {
            System.out.println(item);
        }
    }
}
複製程式碼

輸出結果如下:

image.png

專案程式碼

程式碼倉庫: 完整專案程式碼

相關文章