// 生成真实的url // 传来的url可能是http://a.com, 也可能是a.com // getRelativeUrl传来的可以是http://a.com // url = a.com/a/?id=12&id=1221, 那么genUrl=a.com/a/index.html?id=121 func (this *Crawler) genUrl(url string) string { // 去掉?后面的 queryParam, fragment := "", "" // 包含?,# pos := strings.Index(url, "?") if pos != -1 { queryParam = util.Substring(url, pos) url = util.Substr(url, 0, pos) } else { pos = strings.Index(url, "#") if pos != -1 { fragment = util.Substring(url, pos) url = util.Substr(url, 0, pos) } } // 如果url == host if url == this.host || url == this.schemeAndHost { return url + "/" + this.defaultFilename + queryParam + fragment } genFilename, needApend := this.genFilename(url) if genFilename != "" { if needApend { url += "/" + genFilename + queryParam + fragment } else { // 是a.php => a.html urlArr := strings.Split(url, "/") urlArr = urlArr[:len(urlArr)-1] url = strings.Join(urlArr, "/") + "/" + genFilename } } return url }
// 入口 func (this *Crawler) Fetch(url, targetPath string) { url = strings.TrimSpace(url) this.parseUrl(url) // 保存路径 this.doTargetPath(targetPath) // 去掉scheme // a.com, a.com/index.html url = util.Substring(url, len(this.scheme)) // url2, ok := this.getRalativeUrl("a.com/b/c/d/kk/eee.html", "http://a.com/e/c/d/kk") // println(url2) // println(ok) // return this.goDo(url, false) this.w.Wait() // 处理异常 this.doExceptionUrl() }
// url : a.com/a/b/d.html // a.com/a/b/c genFilename: c_leaui_index.html // 生成子的相对目录有用 func (this *Crawler) doHTML(pUrl, realPUrl, content string) (children []string) { regular := "(?i)(src=|href=)[\"']([^#].*?)[\"']" reg := regexp.MustCompile(regular) re := reg.FindAllStringSubmatch(content, -1) log.Println(pUrl + " => " + realPUrl) log.Println(pUrl + " 含有: ") //log.Println(re); baseDir := filepath.Dir(realPUrl) for _, each := range re { // 为了完整替换 // 只替换src=""里的会有子串的问题, 一个url是另一个url子串 rawFullUrl := each[0] // src='http://www.uiueux.com/wp/webzine/wp-content/themes/webzine/js/googlefont.js.php?ver=1.6.4' rawFullUrlPrefix := each[1] // src= // http://a.com/, /a/b/c/d.html, /a/b.jgp // 如果是/a/b.jpg, 那么是相对host的, 而不是本文件的路径 rawCUrl := each[2] cUrl := rawCUrl // strings.TrimRight(rawCUrl, "/") // 万一就是/呢? // 如果一个链接以//开头, 那么省略了http:, 如果以/开头, 则相对于host prefixNotHttp := false if strings.HasPrefix(cUrl, "//") { cUrl = this.scheme + util.Substring(cUrl, 2) prefixNotHttp = true } else if strings.HasPrefix(cUrl, "/") { cUrl = this.schemeAndHost + cUrl } // 如果这个url是一个目录, 新建一个文件 // 如果这个url是以http://a.com开头的, host是一样的, // 那么content的url是相对于该url // 生成的url, 如果是目录, 会生成一个文件 cRealUrl, ok := this.getRalativeUrl(realPUrl, cUrl) // 错误, 不是本页面, 本host的页面 if ok == -1 { // 如果之前//替换成了http:// if prefixNotHttp { content = strings.Replace(content, rawFullUrl, rawFullUrlPrefix+"\""+cRealUrl+"\"", -1) } continue } // 表示已处理过, 是相对目录了, 必须把内容的替换掉 // 但要处理的还是之前的链接http:// if ok == 1 { cRealUrl = strings.Trim(cRealUrl, "/") // 把//变成/ for strings.Index(cRealUrl, "//") != -1 { cRealUrl = strings.Replace(cRealUrl, "//", "/", -1) } log.Println(rawCUrl + " >>>>>> " + cRealUrl) content = strings.Replace(content, rawFullUrl, rawFullUrlPrefix+"\""+cRealUrl+"\"", -1) cUrl = strings.Replace(cUrl, this.scheme, "", 1) // 把sheme去掉, do children = append(children, cUrl) // 不需要clean } else { children = append(children, this.cleanUrl(baseDir+"/"+cRealUrl)) } } // 把content保存起来 if !this.writeFile(realPUrl, content) { return } // this.t++ // return return }