效果
代码
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 ;
}