11package main
22
33import (
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
2226const (
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---
2731title: %s
@@ -40,7 +44,6 @@ categories: %s
4044</html>`
4145)
4246
43- var postTime = time .Now ()
4447
4548type 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
6878func 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=b9023fb39b534543a5e65f7cae7cb3c4 ;" , "your csdn cookie" )
7181 flag .IntVar (& page , "page" , - 1 , "download pages" )
7282 flag .Parse ()
83+ rand .Seed (time .Now ().Unix ())
7384}
7485
7586func 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
91101func 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
126135func 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
181202func 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 \n x-ca-key:%s\n x-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