效果
代码
BilibiliVideoDurationCrawler
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class BilibiliVideoDurationCrawler {private static final Pattern VIDEO_PART_PATTERN = Pattern.compile("\"part\":\"(.*?)\",\"duration\":(\\d+),");public static void main(String[] args) {String url = "https://www.bilibili.com/video/BV1834y1676P/";List<VideoPart> videoParts = new ArrayList<>();try {videoParts = getVideoPartsFromUrl(url); } catch (IOException | ParseException e) {System.err.println("获取视频信息失败:" + e.getMessage());return;}if (!videoParts.isEmpty()) {for (int i = 0; i < videoParts.size(); i++) {String progress = getProgressStr(videoParts, i); System.out.println("p" + (i + 1) + " " + videoParts.get(i).getPart() + " " + progress); }}}public static List<VideoPart> getVideoPartsFromUrl(String url) throws IOException, ParseException {Document doc = Jsoup.connect(url).userAgent("Mozilla/5.0").get();Elements elements = doc.select("script");List<String> result = new ArrayList<>();for (Element element : elements) {Matcher matcher = VIDEO_PART_PATTERN.matcher(element.html());while (matcher.find()) {result.add("Part: " + matcher.group(1) + ", Duration: " + matcher.group(2));}}List<VideoPart> videoParts = new ArrayList<>();long totalDuration = 0;for (String str : result) {String[] parts = str.split(", ");String part = parts[0].split(": ")[1];long duration = Long.parseLong(parts[1].split(": ")[1]);totalDuration += duration;VideoPart videoPart = new VideoPart(part, duration);videoParts.add(videoPart);}VideoPart.setTotalDuration(totalDuration);return videoParts;}public static String getProgressStr(List<VideoPart> videoParts, int p) {if (videoParts == null || p < 0 || p >= videoParts.size()) {throw new IllegalArgumentException("Invalid video parts or index p");}long totalLength = VideoPart.getTotalDuration();long lengthBeforeP = 0;for (int i = 0; i <= p; i++) {lengthBeforeP += videoParts.get(i).getDuration();}double progress = (double) lengthBeforeP / (totalLength == 0 ? 1 : totalLength) * 100;return String.format("%.2f%%", progress);}
}
VideoPart
import lombok.AllArgsConstructor;
import lombok.Data;import java.util.Date;@Data
@AllArgsConstructor
public class VideoPart {public VideoPart(String part,long duration){this.part = part;this.duration = duration;}public static void setTotalDuration(long totalDuration) {VideoPart.totalDuration = totalDuration;}public static long getTotalDuration() {return totalDuration;}public void Duration2NeedTime(){this.needTime = new Date(duration*1000);}private String part; private long duration; private Date needTime; private double progress; private static long totalDuration =-1;
}