Python爬虫-百度热搜

记于:2023-11-26 上午
地点:浙江省·温州市·家里
天气:晴天

背景#

最近在学习大数据技术,需要一些数据实践一下,正好又想做个新闻类的个人服务/app,所以先抓取一些新闻类数据;
虽然也有不少公开的数据集,但还是想自己抓取下,顺便练下爬虫技术。

代码#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#!/usr/bin/python
# -*- coding: utf-8 -*-

# ------------------------------------------------------------------------------
# import

from datetime import datetime
from bs4 import BeautifulSoup, Comment
from logging.handlers import TimedRotatingFileHandler
import logging
import requests
import json
import os

# ------------------------------------------------------------------------------
# define

# 定义
datetime_text = datetime.now().strftime('%Y%m%d_%H%M%S_%s')
date_text = datetime.now().strftime('%Y%m%d')

DATA_DIR = '/var/lib/ysmspace-crawler/data/'
LOG_DIR = '/var/log/ysmspace-crawler/'
RESPONSE_DATA_FILE = DATA_DIR + 'response.{}.html'.format(datetime_text)
PURE_DATA_FILE = DATA_DIR + 'data.{}.txt'.format(datetime_text)
LOG_FILE = LOG_DIR + 'message.{}.log'.format(date_text)

SDATA_STARTS = 's-data:'

# ------------------------------------------------------------------------------
# init

# 目录
os.makedirs(DATA_DIR, exist_ok=True)
os.makedirs(LOG_DIR, exist_ok=True)

# 日志
log = logging.getLogger(__name__)
logging.basicConfig(filename=LOG_FILE, level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

# 输出基本信息
log.info('define.datetime_text: %s', datetime_text)
log.info('define.date_text: %s', date_text)
log.info('define.DATA_DIR: %s', DATA_DIR)
log.info('define.LOG_DIR: %s', LOG_DIR)
log.info('define.RESPONSE_DATA_FILE: %s', RESPONSE_DATA_FILE)
log.info('define.PURE_DATA_FILE: %s', PURE_DATA_FILE)
log.info('define.LOG_FILE: %s', LOG_FILE)

log.info('init finish...')

# ------------------------------------------------------------------------------
# main

# 请求原始数据
url = 'https://top.baidu.com/board?tab=realtime'
log.info('response.url: %s', url)
response = requests.get(url)
log.info('response.status_code: %s', response.status_code)
with open(RESPONSE_DATA_FILE, 'w') as file:
file.write(response.text)
log.info('write response.text to %s', RESPONSE_DATA_FILE)

# 检查请求是否成功
if response.status_code == 200:
log.info('request success')
# 解析HTML内容
soup = BeautifulSoup(response.text, 'html.parser')

# 获取包含数据的注释
comment_sdata = soup.find_all(string=lambda text: isinstance(text, Comment) and text.strip().startswith(SDATA_STARTS))
# 提取数据
data_text = comment_sdata[0][len(SDATA_STARTS):]
log.info('parse data success')
with open(PURE_DATA_FILE, 'w') as file:
file.write(data_text)
log.info('write data to %s', PURE_DATA_FILE)
else:
log.info('request failed')

log.info('--------------------------------------------------------------------------------')

以上为第一版代码,后续可能进行优化,比如输出文件按日期分组到目录;

执行与输出#

执行

1
# python baidu-realtime.py

查看日志文件

1
# ll /var/log/ysmspace-crawler
1
2
total 2920
-rw-r--r-- 1 yeshimin wheel 414990 11 26 10:58 message.20231126.log

查看数据文件

1
# ll /var/lib/ysmspace-crawler/data
1
2
-rw-r--r--  1 yeshimin  wheel  45522 11 26 10:58 data.20231126_105801_1700967481.txt
-rw-r--r-- 1 yeshimin wheel 194748 11 26 10:58 response.20231126_105801_1700967481.html

补充#

微博热搜抓取代码逻辑类似

Java集成FFmpeg实现音频转码

记于:2023-10-24 下午
地点:浙江省·温州市·家里
天气:晴天

背景#

Java项目上的一个需求,需要对各种格式的音频文件进行转码,输出为mp3格式;
在了解到可选实现方案有【阿里云媒体处理MPS】和【自己使用FFmpeg】后,优先选择前者进行调研与测试;
在一番配置之后,【阿里云媒体处理MPS】能够成功实现自动转码,但是转码后的文件始终不能在项目的硬件设备中播放;
比对项目要求的转码参数:采样率-16kHz,单声道,比特率-32k,并且需要是CBR固定码率的模式;
注意到【阿里云媒体处理MPS】自动转码任务配置中,仅支持【ABR平均码率模式】,怀疑是这个导致(此时还没有找到合适的查看参数的工具(mediainfo));
在询问客服之后,得到的答复是,可以尝试手动调用API并指定相关参数的方式;
我是觉得手动调用API的方式比较麻烦,而且转码还要费用,索性选择自己使用FFmpeg进行转码;

尝试FFmpeg#

先是测试ffmpeg命令转码的方式;
首先指定了基本参数:
ffmpeg -hide_banner -i input.wav -ar 16000 -ab 32k -ac 1 output.mp3
输出文件在macos的【音乐】软件下可正常播放,但是查看其信息时发现码率始终为40k,与指定的32k参数不符;
在尝试各种参数及组合之后,始终不正确;
尝试参数大概有:

1
2
3
4
5
-vn 仅输出音频流
-b:a 32k 以不同形式指定码率
-c:a libmp3lame 明确指定mp3编码器
-af "volume=1" 指定音量不变
-map_metadata -1 -fflags +bitexact -flags:a +bitexact 各种去除元信息的参数

在各种尝试无果后,无意间发现一篇博客,标题为【解决ffmpeg生成mp3在ios上时长不对的问题】;
在博客中,作者提到了一个参数:-write_xing 0,同时发现这个问题是一个bug(见参考资料);
在添加了-write_xing 0参数后,转码成功,输出文件的码率也正确为32k(可以使用mediainfo查看);

最终命令为:
ffmpeg -hide_banner -i input.wav -ar 16000 -ab 32k -ac 1 -write_xing 0 -map_metadata -1 -fflags +bitexact -flags:a +bitexact -c:a libmp3lame output.mp3

参数解释如下:

1
2
3
4
5
6
7
8
9
10
11
`-hide_banner`: 隐藏 FFmpeg 的标志栏
`-i input.wav`: 指定输入文件为 "input.wav"
`-ar 16000`: 设置音频采样率为 16,000 Hz
`-ab 32k`: 设置音频比特率为 32 kbps(千位每秒)
`-ac 1`: 设置输出音频为单声道(单通道)
`-write_xing 0`: 禁用写入 Xing VBR 头部信息
`-map_metadata -1`: 删除输入文件的元数据(如标签信息)
`-fflags +bitexact`: 设置输入文件的比特精度标志
`-flags:a +bitexact`: 设置输出文件的音频比特精度标志
`-c:a libmp3lame`: 使用 libmp3lame 编码器来进行 MP3 压缩
`output.mp3`: 指定输出文件名为 "output.mp3"

Java集成#

发现没有直接用Java实现的ffmpeg库,要么是调用本地ffmpeg命令,要么是使用jni;
发现一个叫做【javacv】的库,可以使用Java调用ffmpeg命令,进行尝试了,由于定位不到ffmpeg命令,所以放弃了,改用Java的ProcessBuilder方式;
核心代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    @Override
public int transcoding(String input, String output) throws IOException, InterruptedException {
String[] ffmpegCommand = {
"/usr/bin/ffmpeg", // linux
// "/opt/homebrew/bin/ffmpeg", // macos
"-hide_banner",
"-i", input,
"-ar", "16000",
"-ab", "32k",
"-ac", "1",
"-write_xing", "0",
"-map_metadata", "-1",
"-fflags", "+bitexact",
"-flags:a", "+bitexact",
"-c:a", "libmp3lame",
output
};

ProcessBuilder pb = new ProcessBuilder(ffmpegCommand);
int exitCode = pb.inheritIO().start().waitFor();
log.info("transcoding.exitCode: {}", exitCode);
return exitCode;
}

还有一个功能点,是获取音频文件的时长;
原来的思路是,调用ffmpeg输出音频文件信息,但是发现输出无法被捕获,经查询发现ffmpeg默认输出到了stderr,而不是stdout;
在连同stderr一起输出后,依然无法捕获,经过一番搜索与尝试,定位到问题在ProcessBuilder的重定向逻辑上;
如果有重定向的逻辑,调用方式为(/bin/sh):
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", String.join(" ", ffmpegCommand));
核心代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
    private Double getAudioLength(String input) {
String infoFile = input + ".info";
String[] ffmpegCommand = {
"/usr/bin/ffmpeg", // linux
// "/opt/homebrew/bin/ffmpeg", // macos
"-hide_banner",
"-i", input,
"2>&1", "|", "cat",
">", infoFile
};

Double durationInSeconds = null; // 初始化为 null

try {
// ProcessBuilder pb = new ProcessBuilder(ffmpegCommand);
// 如果有重定向的逻辑,一定要这样调用!!!
ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", String.join(" ", ffmpegCommand));
Process process = pb.inheritIO().start();
int exitCode = process.waitFor();
log.info("exitCode: {}", exitCode);

// 读取infoFile,提取音频时长信息
List<String> lines = FileUtil.readLines(infoFile, "UTF-8");
for (String line : lines) {
if (line.contains("Duration:")) {
// 提取包含 "Duration:" 的行
String durationLine = line.trim();
String durationPart = durationLine.split("Duration:")[1].trim().split(",")[0].trim();

// 解析时长信息,转换为 Double,精确到毫秒
String[] timeParts = durationPart.split(":");
double hours = Double.parseDouble(timeParts[0]);
double minutes = Double.parseDouble(timeParts[1]);
double seconds = Double.parseDouble(timeParts[2]);
double milliseconds = (hours * 3600 + minutes * 60 + seconds) * 1000;

durationInSeconds = milliseconds / 1000.0; // 转换为秒
}
}

process.destroy();

if (durationInSeconds != null) {
log.info("音频时长(秒,精确到毫秒):{}", durationInSeconds);
} else {
log.info("未找到音频时长信息。");
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
FileUtil.del(infoFile);
}

return durationInSeconds;
}

Docker部署#

由于项目在非本地环境是以Docker形式部署,所以又出现问题了;
ffmpeg命令安装的问题,如果是安装到宿主机上,担心跟环境绑定得太死;
所以选择使用Dockerfile将其安装到容器中;
但是使用原镜像(pig4cloud/java:8-jre)无法直接安装ffmpeg;
经过一番搜索与测试,最终使用(openjdk:8-jdk-alpine)镜像,同时配置源,ffmpeg安装成功;
Dockerfile示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
FROM openjdk:8-jdk-alpine

MAINTAINER yeshimin

ENV TZ=Asia/Shanghai
ENV JAVA_OPTS="-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom"

RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

RUN mkdir -p /xxx-module

RUN mkdir -p /tmp/xxx-audio

RUN echo "http://mirrors.aliyun.com/alpine/v3.6/main" > /etc/apk/repositories \
&& echo "http://mirrors.aliyun.com/alpine/v3.6/community" >> /etc/apk/repositories \
&& apk update upgrade \
&& apk add --no-cache procps unzip curl bash tzdata \
&& apk add yasm && apk add ffmpeg \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo "Asia/Shanghai" > /etc/timezone

WORKDIR /xxx-module

EXPOSE 10003

ADD ./target/xxx-module-biz.jar ./

CMD java $JAVA_OPTS -jar xxx-module-biz.jar

控制输出文件大小#

要求:在采样率、码率、声道数固定的情况下,控制输出文件的大小不超过60K;
经过搜索,可以使用-fs参数来控制输出文件的大小;
但是实际执行之后会报错:

1
2
3
# ffmpeg -hide_banner -i caiqin.wav -ar 16000 -ab 32k -ac 1 \
-write_xing 0 -map_metadata -1 -fflags +bitexact -flags:a +bitexact \
-c:a libmp3lame -fs 60k caiqin.mp3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Guessed Channel Layout for Input Stream #0.0 : stereo
Input #0, wav, from 'caiqin.wav':
Duration: 00:50:07.91, bitrate: 1411 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, 2 channels, s16, 1411 kb/s
File 'caiqin.mp3' already exists. Overwrite? [y/N] y
Stream mapping:
Stream #0:0 -> #0:0 (pcm_s16le (native) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
Output #0, mp3, to 'caiqin.mp3':
Stream #0:0: Audio: mp3, 16000 Hz, mono, s16p, 32 kb/s
Metadata:
encoder : Lavc libmp3lame
[out#0/mp3 @ 0x6000016b80c0] Error muxing a packet.0kbits/s speed=N/A
size= 59kB time=00:00:15.15 bitrate= 31.7kbits/s speed= 307x
video:0kB audio:59kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.033307%
Conversion failed!

根据输出的第14行信息,应该是特定的采样率、码率、声道数下,转码后所需的文件大小超出指定的60K(展示为59kB)所导致;

在对时长进行控制后(使用-t参数),可以正常转码:

1
2
3
# ffmpeg -hide_banner -i caiqin.wav -ar 16000 -ab 32k -ac 1 \
-write_xing 0 -map_metadata -1 -fflags +bitexact -flags:a +bitexact \
-c:a libmp3lame -fs 60k -t 14 caiqin.mp3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Guessed Channel Layout for Input Stream #0.0 : stereo
Input #0, wav, from 'caiqin.wav':
Duration: 00:50:07.91, bitrate: 1411 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, 2 channels, s16, 1411 kb/s
File 'caiqin.mp3' already exists. Overwrite? [y/N] y
Stream mapping:
Stream #0:0 -> #0:0 (pcm_s16le (native) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
Output #0, mp3, to 'caiqin.mp3':
Stream #0:0: Audio: mp3, 16000 Hz, mono, s16p, 32 kb/s
Metadata:
encoder : Lavc libmp3lame
size= 55kB time=00:00:13.97 bitrate= 32.3kbits/s speed= 230x
video:0kB audio:55kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.035521%

在以上方案实现后,偶然发现ffmpeg指定输出文件大小后,虽然转码超过指定大小时依然会报错,但还是会自动截断并生成指定大小的文件;
所以不需要像上面方案那么绕了,直接执行一次,结果就满足了,只是exitCode返回非0而已;

问题处理-mp3文件附带封面导致指定大小参数失效#

在对某个音频文件进行转码时,发现转码后的文件大小没有被自动截断,执行信息如下:

1
2
3
# ffmpeg -hide_banner -i xx.mp3 -ar 16000 -ab 32k -ac 1 \
-write_xing 0 -map_metadata -1 -fflags +bitexact -flags:a +bitexact \
-c:a libmp3lame -fs 60k yy60k.mp3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
Input #0, mp3, from 'xx.mp3':
Metadata:
encoder : Lavf58.76.100
comment : 163 key(Don't modify):cEgtqHxwpdRKcBCRPBlPkg2DgcBlNoDaE7DLI/2UHqz2lBjNbotyjPpbetGfYEpSHze+evmlulEGcCplT1L5nqhLHeK3XTcyEgnHwW9Ow1JY2+gbzf04bwvVKdfiIWN3LL/zdLfLxvlVsPvobu6nWgvQC6Nw7MGw5umsTeRPyYHy4w5YVSD8VHyFEo0eQKeaubW3qofyzOlJ0gYXQlMHN4RCn1jpkefyBGBCOcjKE
album : 大风遇到了雨
title : 不找了
artist : 隔壁老樊
album_artist : 隔壁老樊
disc : 01
track : 1
Duration: 00:04:11.81, start: 0.023021, bitrate: 128 kb/s
Stream #0:0: Audio: mp3, 48000 Hz, stereo, fltp, 128 kb/s
Metadata:
encoder : Lavc58.13
Stream #0:1: Video: mjpeg (Baseline), yuvj420p(pc, bt470bg/unknown/unknown), 1080x1920 [SAR 72:72 DAR 9:16], 90k tbr, 90k tbn (attached pic)
Metadata:
comment : Other
Stream mapping:
Stream #0:1 -> #0:0 (mjpeg (native) -> png (native))
Stream #0:0 -> #0:1 (mp3 (mp3float) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
[swscaler @ 0x128378000] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x128378000] [swscaler @ 0x118008000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x128378000] [swscaler @ 0x128388000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x128378000] [swscaler @ 0x128398000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x128378000] [swscaler @ 0x1283a8000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x128378000] [swscaler @ 0x1283b8000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x128378000] [swscaler @ 0x1283c8000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x128378000] [swscaler @ 0x1283d8000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x128378000] [swscaler @ 0x1283e8000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x128378000] [swscaler @ 0x1283f8000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x110008000] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x110008000] [swscaler @ 0x118008000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x110008000] [swscaler @ 0x118018000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x110008000] [swscaler @ 0x118028000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x110008000] [swscaler @ 0x118038000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x110008000] [swscaler @ 0x118048000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x110008000] [swscaler @ 0x118058000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x110008000] [swscaler @ 0x118068000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x110008000] [swscaler @ 0x118078000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x110008000] [swscaler @ 0x118088000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x130008000] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x130008000] [swscaler @ 0x118088000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x130008000] [swscaler @ 0x118008000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x130008000] [swscaler @ 0x118018000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x130008000] [swscaler @ 0x118028000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x130008000] [swscaler @ 0x118038000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x130008000] [swscaler @ 0x118048000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x130008000] [swscaler @ 0x118058000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x130008000] [swscaler @ 0x118068000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x130008000] [swscaler @ 0x118078000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x118078000] deprecated pixel format used, make sure you did set range correctly
[swscaler @ 0x118078000] [swscaler @ 0x118088000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x118078000] [swscaler @ 0x118008000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x118078000] [swscaler @ 0x118018000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x118078000] [swscaler @ 0x118028000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x118078000] [swscaler @ 0x118038000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x118078000] [swscaler @ 0x118048000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x118078000] [swscaler @ 0x118058000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x118078000] [swscaler @ 0x118068000] No accelerated colorspace conversion found from yuv420p to rgb24.
[swscaler @ 0x118078000] [swscaler @ 0x118098000] No accelerated colorspace conversion found from yuv420p to rgb24.
[vost#0:0/png @ 0x126f0cef0] Frame rate very high for a muxer not efficiently supporting it.
Please consider specifying a lower framerate, a different muxer or setting vsync/fps_mode to vfr
Output #0, mp3, to 'yy60k.mp3':
Stream #0:0: Video: png, rgb24(pc, gbr/unknown/unknown, progressive), 1080x1920 [SAR 1:1 DAR 9:16], q=2-31, 200 kb/s, 90k fps, 90k tbn (attached pic)
Metadata:
comment : Other
encoder : Lavc png
Stream #0:1: Audio: mp3, 16000 Hz, mono, fltp, 32 kb/s
Metadata:
encoder : Lavc libmp3lame
[out#0/mp3 @ 0x6000017a80c0] Error muxing a packet02:27.60 bitrate= 0.0kbits/s speed= 288x
frame= 1 fps=0.0 q=-0.0 Lsize= 1061kB time=00:04:11.75 bitrate= 34.5kbits/s speed= 287x
video:78kB audio:983kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.003959%
Conversion failed!

可以看到里面有一个图片流:Stream #0:1 -> #0:0 (mjpeg (native) -> png (native)),怀疑是这个差异导致的;
一开始把图片也当作元信息,原来使用的参数中已经包含-map_metadata -1,用于去除元信息,为什么会无效;
查询了解到音频流中的封面图片属于数据流的一部分,不能算是常规的元信息;
然后使用了-map 0:a参数,指定只输出音频流,最终问题得到解决;

参考资料#

记·桂林游记

记于:2023-10-01 下午
地点:浙江省·温州市·家里
天气:阴雨

阿德出去长途旅游了,几天后我也出去了,09月26日于桂林汇合;
本来想着没做过飞机,正好可以坐一下飞机,而且看起来价格和高铁也差不多,
都是600上下,没想到机票付款页看到还要燃油费等费用,最终还是选择了高铁~
坐了8小时左右的高铁,晚上6点半左右到达桂林;
26日晚上住在伯曼酒店;
晚上出去买了点小吃,买多了,没吃完~

27日上午,去到一个古镇逛了逛,这里有竹筏漂流,80元一个人,没报;
这里有战斗机在天上飞,声音好大,手机拍不大清;
下午,游玩漓江,报了个团,300元一个人~然后去门店等待,11点半左右出发;
先坐大巴到岸边,一路上导游讲解、洗脑~讲广西/桂林经济不好,很不容易,为国家付出了很多,全国都欠它的,意思是要大家多消费~
第一个项目是坐竹筏,4人一组,没抢到前排,可惜;注意到竹筏居然都是金属的~后面装了个引擎~
上岸后准备吃饭,导游把队伍引导至一家饭店,说是附近只有这一家;
和阿德进去看了下菜单价格,就出来了,准备去周边再找找,导游还尝试劝说,生怕我们发现周边有更便宜的;
在门口有很多老奶奶推销水果、栗子等,我买了栗子,以免万一真找不到其他饭店~
没走多远就发现一家米粉店,只要10元一碗,还不错,就在这吃了;期间还买了一份水果;
吃完坐了一会,然后集合去坐游轮,游轮还是挺大的,没记错的话好像是四星级的;
然后就是吃吃栗子和水果,拍拍照,看看风景,偶尔船上导游讲解一下;
再次上岸后,又坐大巴,接下来是去一个少数民族寨子,应该是侗族;
有个寨子里的导游带着讲解,喝了米酒,刚入口感觉就是喝水,稍后上来一点酒气,之前没喝过;
最终往里走,就是卖银器的地方,没什么人,基本上就是这一团的人;
好说歹说反正我们就是不买,其他人有几个买的;里面逛了逛,待了挺久的,最终导游带着从另一条路线出去了;
然后就是坐大巴回程了,在车上导游分了点零食,以为只是简简单单分点零食,没想到最终还是推销~当然还是没买~
想起来旅游团居然没到阳朔,就是20元人民币上的风景地;
晚上到了某宾馆,出去吃了啤酒鱼,还不错,有点饱~

28日上午,准备去20元人民币上的风景地,因为前一天坐过竹筏,这次就不坐了,岸边拍了拍照;
接下来租了两辆电瓶车,30元每辆,押金100,车是改过的,表显最高25,实际上速度估计有50以上;随便逛,挺有意思的;
上午没什么太阳,很是凉快惬意,中午太阳出来了就有些热了;
中午吃的汉堡快餐,味道也不错;然后就开回去还车了;

然后就是准备上高速回家了,因为29日开始高速免费,怕堵车,所以早点回去;
全程高速1300多公里,原计划是两天开回去,中间在服务区休息一晚;
28日下午在休息区吃了面,然后继续出发,刚上路前方就发生车祸,堵了有半小时以上,一路上有多起大小车祸,所幸看起来没有人员伤亡;
后来阿德非要连夜开回去,总耗时18个小时左右,开车时间13个小时左右,大概是从下午1点多开到第二天早上6点多到家;
实在是危险,我一个坐车的,怕出事车上也没睡,真是坐车的比开车的都累,不过还好,最终平安到家了;
夜晚高速行车,也是不一样的一种体验,挺有意思的~后半夜路上车也比较少;

29日到家后,直接躺下就睡了,睡到中午。


某古镇
某古镇
竹筏山水
竹筏山水
竹筏山水
侗族寨子表演
侗族寨子银砖
侗族寨子银店
侗族寨子银匠
20元人民币风景地
20元人民币风景地

记·《乌合之众》读后感

记于:2023-09-14 下午
地点:浙江省·温州市·家里
天气:多云·晴

有些书还是要一口气读完,最好是在有兴趣的开始一段时间内迅速读完,不然会失去耐心和兴趣。

这本书主要写个人与群体,个人用于与群体做对比,最主要还是群体方面的研究,包括群体的性格、思想观念以及各种群体的特点等;
叙述方面多少有些啰嗦、枯燥,知识密度低了点,以至于断断续续快读完了仿佛也没学到什么,或许也跟内容本就属于较抽象的东西有关;
最后章节有总结,再回过头来看看书本简介,大致讲的是这些吧:

1
2
3
个体与群体的各方面差异巨大,个体融入/形成群体之后,个性化的东西将(逐渐)丧失;
群体往往表现出“愚钝/麻木”、“暴力”、“情绪化”、“易受操控”等特性;
操控群体,就要抓住群体的情绪,给予满足(哪怕是欺骗),然后“驯养”(书中简介用到这个词,不得不承认这词用的很精髓);

不过,难道所有的群体(最终)都会有“暴民”属性吗,我总希望有例外。


接下来想看看《空间的诗学》,很多年前就想看这本书了,书买来也有一两年了,这次,干它。

记·摩旅·回家

记于:2023-07-22 晚上
地点:浙江省·温州市
天气:阴雨

开销:
加油:76
总计:76

此次摩旅开销总计:189.8+215.71+259.40+76=740.91

早上应该是6点多出发的,走京福线/104国道,下午4点多到家;
早上就吃了一根玉米香肠,中午没吃,开到下午一共9个多小时,400公里左右,第一次开这么远,突然感觉自己好牛逼,就是肩背和腰部痛的不行,都有点想换车了;
今天实实在在体验了把什么叫缺德导航,开到台州,剩余路程一直停留在181km,导航的路线不知对不对,重新导航都没用,最后连导航记录都没保存,淦;
后面的路程用的是百度导航;
好像是在台州,有一长段桥上的路很好开,一个个九十上百的速度,一度以为自己是不是不小心上了高速~;
今天感觉差点要撞了,记得应该是在冲最后几秒绿灯,见左边一辆超级大卡车准备掉头,我还特意按了几声喇叭,按照以往经验,这种大块头肯定是要等一等的,所以我也基本没减速,几乎是刚过路口,反应过来,这厮居然在掉头,几乎同一时间,右边一辆轿车飞速驶来准备要右转,但是这速度对于转弯来说有点快了,我整个人都震惊恍惚了一下,感觉肾上腺都分泌出来了,一拧油门就从三五米宽的中间冲过去了,然后就是有些后怕了,看了下后视镜,这两个卧龙凤雏好像也刹停了,为什么不撞起来呢~想骂人;
开车还是要小心,不过话虽如此,即便自己猥琐着开,比如不冲绿灯,但是在路上久了出状况的概率肯定也是越来越大的,特别是骑摩托,毕竟肉包铁,除了小心慢慢开和穿护具之外,剩下的真就是看运气了~;
当时的一瞬间,脑海里有闪过自己飞出去的画面,而且是穿护具的,难道是因为穿了护具,所以潜意识里想飞一次?~;
还有件事想不起来了,可能是昨晚睡觉时蟑螂爬我手上,我被吓得从床上弹起来这件事~;
第一次的摩旅就结束了,有机会继续。

记·摩旅·游玩

记于:2023-07-21 晚上
地点:浙江省·杭州市·萧山区·凤盛大酒店
天气:阴雨

开销:
住宿:92
公交地铁:3+3+6+2+2+6+8+3
充电宝:3+12
午餐:17.90
西湖游船:70
晚餐:29.50
买水:2
总计:259.40

早上8点出发,下午6点左右回来;上午去下沙,下午去西湖;
上午坐第一趟公交就坐反了,还好发现及时,两三站下车了~;
到了下沙,只是去杭职和计量门口拍了个照,不让进;
中午开了个工作会议,然后在便利店吃了份快餐;
下午去了西湖,70块钱买票坐了游船到湖中的岛,没啥好玩的,随便逛了逛,拍了点照就回岸上了;
西湖边的充电宝价格太贵了,比景点外的贵了一倍,一个半多小时花了12块钱;
晚上吃麻辣烫点多了,有点撑~
不知道为什么,晚上头有点痛,今天阴雨天,而且基本上都在坐车,不至于中暑,难道新冠?~
把最后一瓶藿香正气液喝掉了;
明天回家,挑战看看一天时间直接开到家。


杭州西湖

记·摩旅·到达杭州

记于:2023-07-20 晚上
地点:浙江省·杭州市·萧山区·凤盛大酒店
天气:阴雨

开销:
午餐:17
加油:76.41
住宿:92
晚餐:26.30
买水:4
总计:215.71

中午12点前出发,走351国道,下午3点多到达杭州萧山区,下午4点左右到达萧山区凤盛大酒店;
全程150公里左右(可能有几十公里误差~);
刚开出去没多久就大下雨,鞋子都湿了;
351国道真好开,车少,想试试拉个极速,到110的时候又怕死亡摇摆,赶紧松了油门~;
在杭州开,多次开错路,怕开到禁行区被罚,多次纠正路线,还好最终没事;
路上遇到一个叼毛翘头,没翻车真可惜~;
明天去一趟西湖、去一趟杭职。


路边躲雨

记·摩旅·去杭州

记于:2023-07-19 晚上
地点:浙江省·金华市·磐安县·永加宾馆
天气:阴、多云

开销:
加油:76.73
住宿:92.07
晚餐:17
买水:4
总计:189.8

凌晨1点睡,早上5点醒,6点起,头有点疼,吃完早餐继续睡到中午;
家里吃过午饭,下午1点启程,走223省道,从温州经过台州,下午6点左右到达到达金华磐安县;
中途一路段大雨;
明天继续去往杭州。


开不动了休息下