github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zhttp/utils.go (about) 1 package zhttp 2 3 import ( 4 "net/http" 5 "os" 6 "path/filepath" 7 "strings" 8 9 "golang.org/x/net/html" 10 11 "github.com/sohaha/zlsgo/zfile" 12 "github.com/sohaha/zlsgo/zstring" 13 ) 14 15 type ( 16 selector struct { 17 Attr map[string]string 18 Name string 19 i int 20 Child bool 21 Brother bool 22 } 23 ) 24 25 func (s *selector) appendAttr(key, val string, index int) { 26 if key == "" { 27 s.Name = val[s.i:index] 28 } else { 29 val = val[s.i:index] 30 if v, ok := s.Attr[key]; ok && v != "" { 31 s.Attr[key] = s.Attr[key] + " " + val 32 } else { 33 s.Attr[key] = val 34 } 35 } 36 s.i = index + 1 37 } 38 39 // ConvertCookie Parse Cookie String 40 func ConvertCookie(cookiesRaw string) map[string]*http.Cookie { 41 cookie := map[string]*http.Cookie{} 42 c := strings.Split(cookiesRaw, ";") 43 for _, s := range c { 44 v := strings.Split(zstring.TrimSpace(s), "=") 45 if len(v) == 2 { 46 name := zstring.TrimSpace(v[0]) 47 cookie[name] = &http.Cookie{Name: name, Value: v[1]} 48 } 49 } 50 return cookie 51 } 52 53 // BodyJSON make the object be encoded in json format and set it to the request body 54 func BodyJSON(v interface{}) *bodyJson { 55 return &bodyJson{v: v} 56 } 57 58 // BodyXML make the object be encoded in xml format and set it to the request body 59 func BodyXML(v interface{}) *bodyXml { 60 return &bodyXml{v: v} 61 } 62 63 func File(path string, field ...string) interface{} { 64 var matches []string 65 path = zfile.RealPath(path) 66 uploads := make([]FileUpload, 0) 67 fieldName := "media" 68 if len(field) > 0 { 69 fieldName = field[0] 70 } 71 s, err := os.Stat(path) 72 if err == nil && !s.IsDir() { 73 file, _ := os.Open(path) 74 return []FileUpload{{ 75 File: file, 76 FileName: filepath.Base(path), 77 FieldName: fieldName, 78 }} 79 } 80 m, err := filepath.Glob(path) 81 if err != nil { 82 return err 83 } 84 matches = append(matches, m...) 85 if len(matches) == 0 { 86 return ErrNoMatched 87 } 88 89 for _, match := range matches { 90 if s, e := os.Stat(match); e != nil || s.IsDir() { 91 continue 92 } 93 file, _ := os.Open(match) 94 uploads = append(uploads, FileUpload{ 95 File: file, 96 FileName: filepath.Base(match), 97 FieldName: fieldName, 98 }) 99 } 100 101 return uploads 102 } 103 104 var UserAgentLists = []string{ 105 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36", 106 "Mozilla/5.0 (Linux; U; Android 2.3.6; zh-cn; GT-S5660 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MicroMessenger/4.5.255", 107 "Mozilla/5.0 (X11; OpenBSD i386) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36", 108 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1944.0 Safari/537.36", 109 "Mozilla/5.0 (Windows NT 5.1) Gecko/20100101 Firefox/14.0 Opera/12.0", 110 "Mozilla/5.0 (compatible; Googlebot/2.1;+http://www.google.com/bot.html)", 111 } 112 113 func RandomUserAgent() Header { 114 return Header{"User-Agent": UserAgentLists[zstring.RandInt(0, len(UserAgentLists)-1)]} 115 } 116 117 func matchElName(n *html.Node, name string) bool { 118 return name == "" || name == n.Data 119 } 120 121 func arr2Attr(args []map[string]string) map[string][]string { 122 var attr map[string][]string 123 if len(args) > 0 { 124 attr = make(map[string][]string, len(args[0])) 125 for i := range args[0] { 126 attr[i] = strings.Fields(args[0][i]) 127 } 128 } 129 return attr 130 } 131 132 func getAttrValue(attributes []html.Attribute) map[string]string { 133 var values = make(map[string]string) 134 for i := 0; i < len(attributes); i++ { 135 _, exists := values[attributes[i].Key] 136 if !exists { 137 values[attributes[i].Key] = attributes[i].Val 138 } 139 } 140 return values 141 } 142 143 func findAttrValue(attr html.Attribute, attribute string, value []string) bool { 144 if attr.Key == attribute { 145 attr := strings.Fields(attr.Val) 146 num := len(value) 147 // todo optimization 148 for i := range value { 149 for a := range attr { 150 if attr[a] == value[i] { 151 num-- 152 break 153 } 154 } 155 } 156 return num == 0 157 } 158 return false 159 } 160 161 func getElText(r QueryHTML, full bool) string { 162 b := zstring.Buffer() 163 var f func(*html.Node) 164 f = func(n *html.Node) { 165 if n == nil { 166 return 167 } 168 169 if n.Type == html.TextNode { 170 b.WriteString(n.Data) 171 } 172 173 if full { 174 for i := range r.filter { 175 if n == r.filter[i] { 176 return 177 } 178 } 179 if matchElName(n, "script") || matchElName(n, "style") { 180 return 181 } 182 if n.Type == html.ElementNode { 183 f(n.FirstChild) 184 } 185 } 186 187 if n.NextSibling != nil { 188 f(n.NextSibling) 189 } 190 } 191 f(r.getNode().FirstChild) 192 return b.String() 193 } 194 195 func forChild(node *html.Node, fn func(n *html.Node) bool) { 196 n := node.FirstChild 197 for { 198 if n == nil { 199 return 200 } 201 if n.Type == html.ElementNode { 202 if !fn(n) { 203 return 204 } 205 } 206 n = n.NextSibling 207 } 208 } 209 210 func matchEl(n *html.Node, el string, args map[string][]string) *html.Node { 211 if n.Type == html.ElementNode && matchElName(n, el) { 212 if len(args) > 0 { 213 for i := 0; i < len(n.Attr); i++ { 214 attr := n.Attr[i] 215 for name, val := range args { 216 if findAttrValue(attr, name, val) { 217 return n 218 } 219 } 220 } 221 } else { 222 return n 223 } 224 } 225 return nil 226 } 227 228 func findChild(node *html.Node, el string, args []map[string]string, multiple bool) (elArr []*html.Node) { 229 attr := arr2Attr(args) 230 n := matchEl(node, el, attr) 231 if n != nil { 232 elArr = []*html.Node{n} 233 if !multiple { 234 elArr = []*html.Node{n} 235 return 236 } 237 } 238 for c := node.FirstChild; c != nil; c = c.NextSibling { 239 p := findChild(c, el, args, multiple) 240 elArr = append(elArr, p...) 241 if !multiple && len(elArr) > 0 { 242 return 243 } 244 } 245 246 return 247 }