【发布时间】:2017-09-20 01:04:04
【问题描述】:
我正在尝试使用 Go 构建一个网络爬虫,我对这门语言相当陌生,我不确定在使用 html 解析器时我做错了什么。我正在尝试解析 html 以查找锚标记,但我一直在获取 html.TokenTypeEnd 。
package main
import (
"fmt"
"golang.org/x/net/html"
"io/ioutil"
"net/http"
)
func GetHtml(url string) (text string, resp *http.Response, err error) {
var bytes []byte
if url == "https://www.coastal.edu/scs/employee" {
resp, err = http.Get(url)
if err != nil {
fmt.Println("There seems to ben an error with the Employee Console.")
}
bytes, err = ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Cannot read byte response from Employee Console.")
}
text = string(bytes)
} else {
fmt.Println("Issue with finding URL. Looking for: " + url)
}
return text, resp, err
}
func main() {
htmlSrc, response, err := GetHtml("https://www.coastal.edu/scs/employee")
if err != nil {
fmt.Println("Cannot read HTML source code.")
}
_ = htmlSrc
htmlTokens := html.NewTokenizer(response.Body)
i := 0
for i < 1 {
tt := htmlTokens.Next()
fmt.Printf("%T", tt)
switch tt {
case html.ErrorToken:
fmt.Println("End")
i++
case html.TextToken:
fmt.Println(tt)
case html.StartTagToken:
t := htmlTokens.Token()
isAnchor := t.Data == "a"
if isAnchor {
fmt.Println("We found an anchor!")
}
}
}
每当我打印时,我都会收到 html.TokenTypeEnd
fmt.Printf("%T", tt)
【问题讨论】:
-
您只能阅读
response.Body一次。它已经在您的GetHtml函数中用完。你为什么要读整个 html 字符串,然后还是扔掉它? -
我习惯了 Python,所以我认为我必须阅读 html 并将其作为字符串返回。这是我编写的第一个 Go 程序,我对这门语言非常陌生,所以我正在努力理解它。
-
当您遇到
io.Readers 或io.ReadClosers 时,您希望尽可能避免将其全部读入变量中。这些类型有一些优化,如果使用得当,可以提高效率。这就是为什么html.NewTokenizer排在第一位的原因。只是一些建议。如果您确定回复不是很大,通常可以使用ioutil.ReadAll。 -
谢谢!我一定会牢记您的建议,以便继续进行未来的项目。所以 io.Reader 更像是一个缓冲区?
-
是的。根据底层来源,它实际上可能是从例如读取网络套接字,或其他一些当时实际上不在内存中的源。像
html.NewTokenizer这样的东西可以通过读取足够的数据来获得完整的令牌来利用这一点,而不必在内存中拥有完整的输入。 Go 在幕后发生了很多很酷的事情。当您了解更多信息或想了解实际情况时,请阅读 godocs 并随时深入研究源代码(直接从文档链接)。 Go 是用 Go 编写的 :)
标签: html go web-scraping html-parsing