如何在golang中不使用ioutil.ReadAll来检索网站源代码

时间:2017-11-11 00:29:16

标签: http go get

我的代码:

func getSourceUrl(url string) (string, error) {
   resp, err := http.Get(url)
   if err != nil {
       fmt.Println("Error getSourceUrl: ")
       return "", err
   }
   defer resp.Body.Close()
   body := resp.Body
   // time = 0
   sourcePage, err := ioutil.ReadAll(body)
   // time > 5 minutes
   return string(sourcePage), err
}

我有一个网站链接,其中包含> 100000行。使用ioutil.ReadAll让我变得非常长(1个链接大约5分钟)。有没有办法让Source网站更快?谢谢!

3 个答案:

答案 0 :(得分:1)

@Minato尝试此代码,使用<ul> <li><a class="navi">One link</a></li> <li><a class="navi">Second link</a></li> </ul>限制参数进行播放。如果你得到太多错误(减少它),请使用它。

M

每次传输变化约为10-40KByte / sec,所有301个文件的最终总数为928MB,11.1分钟为1425 KByte / sec。我相信你应该能够得到类似的结果。

package main import ( "fmt" "io" "io/ioutil" "log" "net/http" "runtime" "time" ) // Token is an empty struct for signalling type Token struct{} // N files to get var N = 301 // at the source 00000 - 00300 // M max go routines var M = runtime.NumCPU() * 16 // Throttle to max M go routines var Throttle = make(chan Token, M) // DoneStatus is used to signal end of type DoneStatus struct { length int sequence string duration float64 err error } // ExitOK is simple exit counter var ExitOK = make(chan DoneStatus) // TotalBytes read var TotalBytes = 0 // TotalErrors captured var TotalErrors = 0 // URLTempl is templte for URL construction var URLTempl = "https://virusshare.com/hashes/VirusShare_%05d.md5" func close(c io.Closer) { err := c.Close() if err != nil { log.Fatal(err) } } func main() { log.Printf("start main. M=%d\n", M) startTime := time.Now() for i := 0; i < N; i++ { go func(idx int) { // slow ramp up fire getData after i seconds time.Sleep(time.Duration(i) * time.Second) url := fmt.Sprintf(URLTempl, idx) _, _ = getData(url) // errors captured as data }(i) } // Count N byte count signals for i := 0; i < N; i++ { status := <-ExitOK TotalBytes += status.length if status.err != nil { TotalErrors++ log.Printf("[%d] : %v\n", i, status.err) continue } log.Printf("[%d] file %s, %.1f MByte, %.1f min, %.1f KByte/sec\n", i, status.sequence, float64(status.length)/(1024*1024), status.duration/60, float64(status.length)/(1024)/status.duration) } // totals duration := time.Since(startTime).Seconds() log.Printf("Totals: %.1f MByte, %.1f min, %.1f KByte/sec\n", float64(TotalBytes)/(1024*1024), duration/60, float64(TotalBytes)/(1024)/duration) // using fatal to verify only one go routine is running at the end log.Fatalf("TotalErrors: %d\n", TotalErrors) } func getData(url string) (data []byte, err error) { var startTime time.Time defer func() { // release token <-Throttle // signal end of go routine, with some status info ExitOK <- DoneStatus{ len(data), url[41:46], time.Since(startTime).Seconds(), err, } }() // acquire one of M tokens Throttle <- Token{} log.Printf("Started file: %s\n", url[41:46]) startTime = time.Now() resp, err := http.Get(url) if err != nil { return } defer close(resp.Body) data, err = ioutil.ReadAll(resp.Body) if err != nil { return } return }

同样尝试http://www.dslreports.com/speedtest/转到设置并选择一堆美国服务器进行测试并将持续时间设置为60秒。这将告诉您实际有效总费率是多少美元。

祝你好运!

答案 1 :(得分:0)

您可以一次迭代响应的各个部分,例如;

responseSection := make([]byte, 128)
body.Read(responseSection)
return string(responseSection), err

一次读取128个字节。但是会建议确认下载速度不会导致负载缓慢。

答案 2 :(得分:0)

5分钟可能是网络时间。 也就是说,您通常不希望在内存中缓冲大量对象。 resp.Body是一名读者。 因此,您可以使用io.Copy将其内容复制到文件中。 将sourcePage转换为字符串是一个坏主意,因为它会强制进行另一次分配。