scanpage.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package main
  2. import (
  3. "os"
  4. "fmt"
  5. "strings"
  6. "net/http"
  7. "net/url"
  8. "io"
  9. "regexp"
  10. "errors"
  11. "path/filepath"
  12. )
  13. func scanpage (path string, domain string, thisdomain string) error {
  14. // 先に保存したページを読み込む
  15. fn, err := os.ReadFile(path + "/index.html")
  16. if err != nil {
  17. return err
  18. }
  19. // 要らないタグを削除
  20. var script = regexp.MustCompile(`(<script.*</script>)`).ReplaceAllString(string(fn), "")
  21. var noscript = regexp.MustCompile(`(<noscript.*</noscript>)`).ReplaceAllString(string(script), "")
  22. var audio = regexp.MustCompile(`(<audio.*</audio>)`).ReplaceAllString(string(noscript), "")
  23. var video = regexp.MustCompile(`(<video.*</video>)`).ReplaceAllString(string(audio), "")
  24. var iframe = regexp.MustCompile(`(<iframe.*</iframe>)`).ReplaceAllString(string(video), "")
  25. // 追加ダウンロード+ローカル化
  26. var ass = regexp.MustCompile(`(<img.*src=['"]|<meta.*content=['"]|<link.*href=['"])(.*\.)(png|webp|jpg|jpeg|gif|css|js|ico|svg|ttf|woff2)(\?[^'"]*)?`)
  27. // 必要であれば、ページ内のURLを修正
  28. spath := "static/"
  29. if !strings.HasSuffix(path, "/") {
  30. spath = "/" + spath
  31. }
  32. spath = path + spath
  33. // また、追加ダウンロードのファイルに上記のフォルダを創作
  34. err = os.Mkdir(spath, 0755)
  35. if err != nil {
  36. return err
  37. }
  38. repmap := make(map[string]string)
  39. for _, cssx := range ass.FindAllString(iframe, -1) {
  40. // ページ内のURLを受け取る
  41. s := regexp.MustCompile(`(.*src=['"]|.*content=['"]|.*href=['"])`).Split(cssx, -1)
  42. ss := regexp.MustCompile(`(['"].*)`).Split(s[1], -1)
  43. ogurl := ss[0] // 変わる前に元のURLを保存して
  44. // URLは//で始まるは愛
  45. if strings.HasPrefix(ss[0], "//") {
  46. ss[0] = "https:" + ss[0]
  47. }
  48. // ファイル名を見つけて
  49. fss := strings.Split(ss[0], "/")
  50. assdom := ""
  51. filename := fss[len(fss)-1]
  52. // httpかhttpsで始まる場合
  53. if strings.HasPrefix(ss[0], "http://") || strings.HasPrefix(ss[0], "https://") {
  54. assdom = fss[2]
  55. }
  56. // フォルダの創作
  57. asspath := path + "/static/" + assdom
  58. err = os.MkdirAll(asspath, 0755)
  59. if err != nil { // 出来なければ、死ね
  60. return err
  61. }
  62. if filename == "" { // ファイル名がなければ、次に値にスキップしてね
  63. continue
  64. }
  65. if strings.HasPrefix(ss[0], "http://") || strings.HasPrefix(ss[0], "https://") { // httpかhttpsで始まったら、ダウンロードだけしよう
  66. err = dlres(ss[0], filepath.Join(asspath, filename))
  67. if err != nil { // 出来なければ、死ね
  68. return err
  69. }
  70. } else { // ローカルファイルなら、ちょっと変更は必要となるかしら
  71. u, err := url.Parse(domain)
  72. if err != nil { // 出来なければ、死ね
  73. return err
  74. }
  75. rel, err := url.Parse(ss[0])
  76. if err != nil { // 出来なければ、死ね
  77. return err
  78. }
  79. af := u.ResolveReference(rel).String()
  80. err = dlres(af, filepath.Join(asspath, filename))
  81. if err != nil { // 出来なければ、死ね
  82. return err
  83. }
  84. }
  85. repmap[ogurl] = filepath.Join("/static", assdom, filename)
  86. if assdom == "" {
  87. repmap[ogurl] = filepath.Join("/static", filename)
  88. }
  89. if err != nil { // 出来なければ、死ね
  90. fmt.Println(err)
  91. return errors.New("ダウンロードに失敗:")
  92. }
  93. }
  94. // URLをローカル化
  95. for ourl, lurl := range repmap {
  96. aurl := strings.ReplaceAll(path, thisdomain, "") + stripver(lurl)
  97. iframe = strings.ReplaceAll(iframe, ourl, aurl)
  98. }
  99. // index.htmlファイルを更新する
  100. err = os.WriteFile(path + "/index.html", []byte(iframe), 0644)
  101. if err != nil { // 出来なければ、死ね
  102. fmt.Println(err)
  103. return errors.New("書込に失敗")
  104. }
  105. return nil // エラーが出なかったから、返すのは不要
  106. }
  107. // 画像、JS、CSS等ファイルのURLでパラメートルがある場合
  108. func stripver (durl string) string {
  109. u, err := url.Parse(durl)
  110. if err != nil {
  111. fmt.Println("エラー:", err)
  112. return ""
  113. }
  114. u.RawQuery = ""
  115. return u.Path
  116. }
  117. func dlres (durl string, dest string) error {
  118. // ダウンロード
  119. res, err := http.Get(durl)
  120. if err != nil {
  121. return err
  122. }
  123. defer res.Body.Close()
  124. dest = stripver(dest) // URLでパラメートルがあれば、消す
  125. // MIMEタイプを確認
  126. ct := res.Header.Get("Content-Type")
  127. for mime, ext := range getmime() {
  128. if strings.Contains(ct, mime) && !strings.HasSuffix(dest, ext) {
  129. dest += ext
  130. break
  131. }
  132. }
  133. // ファイルを作成
  134. f, err := os.Create(dest)
  135. if err != nil {
  136. return err
  137. }
  138. defer f.Close()
  139. // ファイルを書き込む
  140. _, err = io.Copy(f, res.Body)
  141. if err != nil {
  142. return err
  143. }
  144. return nil
  145. }