Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4547468

Browse files
author
雷科伟
committed
update api url and signature
1 parent b44e35f commit 4547468

File tree

4 files changed

+97
-41
lines changed

4 files changed

+97
-41
lines changed

‎.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
.idea/
1+
.idea/
2+
*.md
3+
*.html

‎README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
# 批量导出CSDN博客
22
> 批量导出`csnd`博客,并转化为`hexo`博客样式,如果你是用富文本编辑器写的则会导出`html`样式
33
4-
注:有些文章可能获取不到造成进度条无法达到100%,如果走到90%多,走不动了,直接取消即可
4+
注:有些文章可能获取不到造成进度条无法达到100%,如果走到99%,走不动了,直接取消即可
55

66
# Quick start
7+
8+
**安装**
79
```bash
8-
go run main.go -username 你的csdn用户名 -cookie 你csdn的cookie -page 1
10+
go get github.com/pibigstar/csdn-hexo
911
```
10-
> page不写,默认为下载全部页
1112

12-
# Demo
13+
**使用**
14+
```bash
15+
csdn-hexo -username 你的csdn用户名 -cookie 你csdn的cookie -page 1
16+
```
17+
> page不写,默认为下载全部页
1318
19+
**完整示例**
1420
```bash
1521
go run main.go -username "junmoxi" -cookie "UserName=junmoxi; UserToken=c3c29cca48be43c4884fe36d052d5851"
1622
```
@@ -21,13 +27,6 @@ go run main.go -username "junmoxi" -cookie "UserName=junmoxi; UserToken=c3c29cca
2127
2228
[点击下载](https://github.com/pibigstar/csdn-hexo/releases/tag/v1.1)
2329

24-
**使用**
25-
> 以Windows用户为例
26-
27-
```bash
28-
main.exe -username 你的csdn用户名 -cookie 你csdn的cookie
29-
```
30-
3130

3231
# cookie获取
3332
![](cookie.png)

‎go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module csdn-hexo
1+
module github.com/pibigstar/csdn-hexo
22

33
go 1.12
44

‎main.go

Lines changed: 83 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package main
22

33
import (
4+
"crypto/hmac"
5+
"crypto/sha256"
6+
"encoding/base64"
47
"encoding/json"
58
"flag"
69
"fmt"
710
"io/ioutil"
811
"math/rand"
912
"net/http"
13+
"net/url"
1014
"os"
1115
"regexp"
1216
"strings"
@@ -21,7 +25,7 @@ import (
2125

2226
const (
2327
ListPostURL = "https://blog.csdn.net/%s/article/list/%d?"
24-
PostDetailURL = "https://mp.csdn.net/mdeditor/getArticle?id=%s"
28+
PostDetailURL = "https://bizapi.csdn.net/blog-console-api/v3/editor/getArticle?id=%s&model_type="
2529
HexoHeader = `
2630
---
2731
title: %s
@@ -40,7 +44,6 @@ categories: %s
4044
</html>`
4145
)
4246

43-
var postTime = time.Now()
4447

4548
type DetailData struct {
4649
Data PostDetail `json:"data"`
@@ -63,39 +66,45 @@ var (
6366
count int
6467
wg sync.WaitGroup
6568
bar *pgbar.Bar
69+
postTime = time.Now()
70+
)
71+
72+
const (
73+
appSecret = "9znpamsyl2c7cdrr9sas0le9vbc3r6ba"
74+
appCaKey = "203803574"
75+
signHeaders = "x-ca-key,x-ca-nonce"
6676
)
6777

6878
func init() {
6979
flag.StringVar(&username, "username", "junmoxi", "your csdn username")
70-
flag.StringVar(&cookie, "cookie", "UserName=junmoxi;UserToken=c3c29cca48be43c4884fe36d052d5851;", "your csdn cookie")
80+
flag.StringVar(&cookie, "cookie", "UserName=junmoxi;UserToken=34543a5e65f7cae7cb3c4;", "your csdn cookie")
7181
flag.IntVar(&page, "page", -1, "download pages")
7282
flag.Parse()
83+
rand.Seed(time.Now().Unix())
7384
}
7485

7586
func main() {
7687
urls, err := crawlPosts(username)
7788
if err != nil {
7889
panic(err)
7990
}
80-
8191
bar = pgbar.NewBar(0, "下载进度", len(urls))
82-
for _, url := range urls {
92+
93+
for _, ul := range urls {
8394
wg.Add(1)
84-
go crawlPostMarkdown(url)
95+
go crawlPostMarkdown(ul)
8596
}
86-
8797
wg.Wait()
8898
}
8999

90100
// Crawl posts by username
91101
func crawlPosts(username string) ([]string, error) {
92-
client := http.Client{}
93-
var (
94-
urls []string
95-
)
102+
defer fmt.Println("地址抓取完成,开始下载...")
96103

104+
var urls []string
97105
for {
98-
resp, err := client.Get(fmt.Sprintf(ListPostURL, username, currentPage))
106+
fmt.Printf("正在抓取第%d页文章地址... \n", currentPage)
107+
resp, err := http.DefaultClient.Get(fmt.Sprintf(ListPostURL, username, currentPage))
99108
if err != nil {
100109
return nil, err
101110
}
@@ -124,34 +133,50 @@ func crawlPosts(username string) ([]string, error) {
124133
}
125134

126135
func crawlPostMarkdown(url string) {
136+
defer wg.Done()
137+
defer bar.Add()
138+
defer func() {
139+
if err := recover(); err != nil {
140+
fmt.Println(err)
141+
}
142+
}()
143+
127144
index := strings.LastIndex(url, "/")
128145
id := url[index+1:]
146+
apiUrl := fmt.Sprintf(PostDetailURL, id)
129147

130-
client := http.Client{}
148+
uuid := createUUID()
149+
sign := createSignature(uuid, apiUrl)
131150

132-
req, _ := http.NewRequest("GET",fmt.Sprintf(PostDetailURL, id), nil)
151+
req, _ := http.NewRequest("GET",apiUrl, nil)
133152
req.Header.Set("cookie", cookie)
153+
req.Header.Set("x-ca-key", appCaKey)
154+
req.Header.Set("x-ca-nonce", uuid)
155+
req.Header.Set("x-ca-signature", sign)
156+
req.Header.Set("x-ca-signature-headers", signHeaders)
157+
req.Header.Set("Accept", "*/*")
134158

135-
resp, err := client.Do(req)
159+
resp, err := http.DefaultClient.Do(req)
136160
if err != nil {
137161
return
138162
}
139-
163+
if resp.StatusCode != http.StatusOK {
164+
return
165+
}
140166
data, err := ioutil.ReadAll(resp.Body)
141167
if err != nil {
142168
return
143169
}
144-
145-
post := new(DetailData)
146-
err = json.Unmarshal(data, post)
170+
var post DetailData
171+
err = json.Unmarshal(data, &post)
147172
if err != nil {
148173
return
149174
}
150175

151176
if post.Data.Markdowncontent != "" {
152-
go buildMarkdownPost(post.Data)
177+
buildMarkdownPost(post.Data)
153178
} else if post.Data.Content != "" {
154-
go buildHtmlPost(post.Data)
179+
buildHtmlPost(post.Data)
155180
}
156181
}
157182

@@ -171,15 +196,10 @@ func buildMarkdownPost(post PostDetail) {
171196
rand.Seed(time.Now().UnixNano())
172197
d := rand.Intn(3) + 1
173198
postTime = postTime.AddDate(0, 0, -d).Add(time.Hour)
174-
175199
count++
176-
177-
defer wg.Done()
178-
defer bar.Add()
179200
}
180201

181202
func buildHtmlPost(post PostDetail) {
182-
183203
html := fmt.Sprintf(HtmlBody, post.Title, post.Content)
184204
err := ioutil.WriteFile(
185205
fmt.Sprintf("%s.html", post.Title),
@@ -188,7 +208,42 @@ func buildHtmlPost(post PostDetail) {
188208
if err != nil {
189209
return
190210
}
211+
}
191212

192-
defer wg.Done()
193-
defer bar.Add()
213+
func createSignature(uuid, apiUrl string) string {
214+
u, err := url.Parse(apiUrl)
215+
if err != nil {
216+
panic(err)
217+
}
218+
query := u.Query().Encode()
219+
query = query[:len(query)-1]
220+
message := fmt.Sprintf("GET\n*/*\n\n\n\nx-ca-key:%s\nx-ca-nonce:%s\n%s?%s", appCaKey, uuid, u.Path, query)
221+
hc := hmac.New(sha256.New, []byte(appSecret))
222+
hc.Write([]byte(message))
223+
res := hc.Sum(nil)
224+
225+
result := base64.StdEncoding.EncodeToString(res)
226+
return result
194227
}
228+
229+
func createUUID() string {
230+
s := strings.Builder{}
231+
chars := make([]string, 0, 10)
232+
for i := 97; i < 103; i++ {
233+
chars = append(chars, string(i))
234+
}
235+
for i := 49; i < 58; i++ {
236+
chars = append(chars, string(i))
237+
}
238+
xs := "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
239+
for _, k := range xs {
240+
x := string(k)
241+
if x == "4" || x == "-" {
242+
s.WriteString(x)
243+
} else {
244+
i := rand.Intn(len(chars))
245+
s.WriteString(chars[i])
246+
}
247+
}
248+
return s.String()
249+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /