hozonsite/src/scanpage.go

173 行
4.7 KiB
Go

package src
import (
"os"
"fmt"
"strings"
"net/http"
"net/url"
"io"
"regexp"
"errors"
"path/filepath"
)
func Scanpage (path string, domain string, thisdomain string) error {
// 先に保存したページを読み込む
fn, err := os.ReadFile(path + "/index.html")
if err != nil { return err }
// 要らないタグを削除
var script = regexp.MustCompile(
`(<script.*</script>)`).ReplaceAllString(string(fn), "",
)
var noscript = regexp.MustCompile(
`(<noscript.*</noscript>)`).ReplaceAllString(string(script), "",
)
var audio = regexp.MustCompile(
`(<audio.*</audio>)`).ReplaceAllString(string(noscript), "",
)
var video = regexp.MustCompile(
`(<video.*</video>)`).ReplaceAllString(string(audio), "",
)
var iframe = regexp.MustCompile(
`(<iframe.*</iframe>)`).ReplaceAllString(string(video), "",
)
// 追加ダウンロード+ローカル化
var ass = regexp.MustCompile(
// ルールに違反けど、長いからしょうがない・・・
`(<img.*src=['"]|<meta.*content=['"]|<link.*href=['"])(.*\.)(png|webp|jpg|jpeg|gif|css|js|ico|svg|ttf|woff2)(\?[^'"]*)?`,
)
// 必要であれば、ページ内のURLを修正
spath := "static/"
if !strings.HasSuffix(path, "/") { spath = "/" + spath }
spath = path + spath
// また、追加ダウンロードのファイルに上記のフォルダを創作
err = os.Mkdir(spath, 0755)
if err != nil { return err }
repmap := make(map[string]string)
for _, cssx := range ass.FindAllString(iframe, -1) {
// ページ内のURLを受け取る
s := regexp.MustCompile(
`(.*src=['"]|.*content=['"]|.*href=['"])`).Split(cssx, -1,
)
ss := regexp.MustCompile(`(['"].*)`).Split(s[1], -1)
ogurl := ss[0] // 変わる前に元のURLを保存して
// URLは//で始まるは愛
if strings.HasPrefix(ss[0], "//") {
ss[0] = "https:" + ss[0]
}
// ファイル名を見つけて
fss := strings.Split(ss[0], "/")
assdom := ""
filename := fss[len(fss)-1]
// httpかhttpsで始まる場合
if strings.HasPrefix(ss[0], "http://") ||
strings.HasPrefix(ss[0], "https://") {
assdom = fss[2]
}
// フォルダの創作
asspath := path + "/static/" + assdom
err = os.MkdirAll(asspath, 0755)
// 出来なければ、死ね
if err != nil { return err }
// ファイル名がなければ、次に値にスキップしてね
if filename == "" { continue }
// httpかhttpsで始まったら、ダウンロードだけしよう
if strings.HasPrefix(ss[0], "http://") ||
strings.HasPrefix(ss[0], "https://") {
err = dlres(ss[0], filepath.Join(asspath, filename))
if err != nil { return err }
} else {
// ローカルファイルなら、ちょっと変更は必要となるかしら
u, err := url.Parse(domain)
if err != nil { return err }
rel, err := url.Parse(ss[0])
if err != nil { return err }
af := u.ResolveReference(rel).String()
err = dlres(af, filepath.Join(asspath, filename))
if err != nil { return err }
}
repmap[ogurl] = filepath.Join("/static", assdom, filename)
if assdom == "" {
repmap[ogurl] = filepath.Join("/static", filename)
}
if err != nil {
fmt.Println(err)
return errors.New("ダウンロードに失敗:")
}
}
// URLをローカル化
for ourl, lurl := range repmap {
aurl := strings.ReplaceAll(path, thisdomain, "") + stripver(lurl)
iframe = strings.ReplaceAll(iframe, ourl, aurl)
}
// index.htmlファイルを更新する
err = os.WriteFile(path + "/index.html", []byte(iframe), 0644)
if err != nil {
fmt.Println(err)
return errors.New("書込に失敗")
}
// エラーが出なかったから、返すのは不要
return nil
}
// 画像、JS、CSS等ファイルのURLでパラメートルがある場合
func stripver (durl string) string {
u, err := url.Parse(durl)
if err != nil {
fmt.Println("エラー:", err)
return ""
}
u.RawQuery = ""
return u.Path
}
func dlres (durl string, dest string) error {
// ダウンロード
res, err := http.Get(durl)
if err != nil { return err }
defer res.Body.Close()
// URLでパラメートルがあれば、消す
dest = stripver(dest)
// MIMEタイプを確認
ct := res.Header.Get("Content-Type")
for mime, ext := range getmime() {
if strings.Contains(ct, mime) && !strings.HasSuffix(dest, ext) {
dest += ext
break
}
}
// ファイルを作成
f, err := os.Create(dest)
if err != nil { return err }
defer f.Close()
// ファイルを書き込む
_, err = io.Copy(f, res.Body)
if err != nil { return err }
return nil
}