csdn博客转markdown

近期完成了csdn上的部分博客转到个人博客上,csdn使用的传统编辑器,个人博客使用的markdown,所以下面分享一下两者之间转化。

1. 安装nodejs和npm,这两步网上教程很多,可以参考下网上
2.安装clean-mark
1
npm install clean-mark --global

该工具可以将我们的博客做一个初步的转markdown,用法如下

1
clean-mark "https://blog.csdn.net/yyy/article/details/xxx"

双引号内部为某篇具体需要转换的博文链接,转换成功后在当前目录下会出现xxx.md

3.对md文件做进一步的修正

使用clean-mark工具转换的md目前有两个问题

  1. 图片,使用的图片链接会是csdn服务器上的图片,并带有水印,需要将去除水印的图片下载到本地,并将md文件中的链接替换为本地图片链接
  2. 乱码,在一些未识别编程语言的代码片中,中文会出现乱码,形如变,这是XML字符实体的一种表示形式,,&#x表示十六进制
    由于需要修正的md文件很多,一个个处理很不方便,所以将需要转换的博客通过第二步转换后同一在一个目录,然后编写程序,只要扫描到该目录下的md文件,就进行修正
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CsdnHandle {

private final String fileRoot = "H:\\CSDN";
private final String artImgFilePath = "file://D:/Program Files/Gridea/post-images/";

public static void main(String[] args) {
CsdnHandle handle = new CsdnHandle();
handle.process();
}

public void process() {

String imgRoot = fileRoot+"\\img\\";
String tomd = fileRoot+"\\tomd\\";
File file = new File(imgRoot);
if (!file.exists()) {
file.mkdirs();
}
file = new File(tomd);
if (!file.exists()) {
file.mkdirs();
}

file = new File(fileRoot);
File[] fileArray = file.listFiles();
for (File file1 : fileArray) {
if (!file1.isDirectory()) {

Integer hz = file1.getAbsolutePath().indexOf(".md");
if (hz != -1) {
conversionMd(file1,imgRoot,tomd);
System.out.println(file1.getName() + " ok");
}
}
}
}

public void conversionMd(File file,String imgRootPath,String toMdPath) {

List<String> allLines = null;
try {
allLines = Files.readAllLines(Paths.get(file.getAbsolutePath()));
} catch (IOException e) {
e.printStackTrace();
}
int head = 0;
String title = null;
Pattern pattern = Pattern.compile("!\\[]\\(.*?\\)");
int imgId = 1;
OutputStream out = null;
BufferedWriter bw = null;
for (String line : allLines) {
if(line.equals("---")) {
head++;
continue;
}
if(head == 1) {
if(line.indexOf("title: ") != -1) {
title = line.substring("title: ".length());
title = title.replace(" ","之");
title = title.replace("-","之");

File mdfile = new File(toMdPath+title+".md");
try {
out=new FileOutputStream(mdfile);
bw=new BufferedWriter(new OutputStreamWriter(out,"utf-8"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
if(head == 2 && title != null && bw != null) {
Matcher matcher = pattern.matcher(line);
while (matcher.find()) {
String httpLink = matcher.group(0).substring(4,matcher.group(0).length()-1);
String path = linkSaveImg(imgId, title,imgRootPath,httpLink);
line = line.replace(httpLink, path);
imgId++;
}
try {
bw.write(unescape(line));
bw.newLine();
} catch (IOException e) {
e.printStackTrace();
}
}

}

try {
if(bw != null)
bw.close();
if(out != null)
out.close();
} catch (IOException e) {
e.printStackTrace();
}

}

public String linkSaveImg(int imgId, String title,String filePath,String http) {

String sp[] = http.split("\\?");
String suffix = sp[0].substring(sp[0].lastIndexOf("."));

try {
URL url = new URL(sp[0]);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setConnectTimeout(3 * 1000);

conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

InputStream inputStream = conn.getInputStream();

byte[] getData = readInputStream(inputStream);

File file = new File(filePath+title+"_"+imgId+suffix);
FileOutputStream fos = new FileOutputStream(file);
fos.write(getData);
if (fos != null) {
fos.close();
}
if (inputStream != null) {
inputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return artImgFilePath+title+"_"+imgId+suffix;
}

public byte[] readInputStream(InputStream inputStream) throws IOException {
byte[] buffer = new byte[1024];
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((len = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.close();
return bos.toByteArray();
}

public static String unescape(String src) {
int index = -1;
while((index=src.indexOf(""&#x")) != -1) {
String data = src.substring(index+3,index+7);
char ch = (char) Integer.parseInt(data, 16);
src = src.replace(""&#x"+data+";",""+ch);
}
return src;
}

}

使用Java编写这个程序的主要原因是网络相关操作真香!

上面分享的是传统编辑器转markdown,如果本身博文就是使用markdown编写,那么有个可全部打包下载的方案


链接打开会发现是一个404,没错,不用怀疑是操作错了。

; 2.F12 -> console

在该404界面F12打开 开发者工具,并选择控制台(console)
输入如下代码回车

1
var s=document.createElement('script');s.type='text/javascript';document.body.appendChild(s);s.src='//cdn.jsdelivr.net/gh/ame-yu/csdn-move@latest/dist/index.js';

稍等片刻便可打包下载一个zip文件,里面包含所有的md文章,文章数越多,其等待时间越长,可将鼠标放置浏览器标签页查看其打包进度情况。