【前往】对于使用「http.Get」获取的html,需要注意字符编码
概述
我认为在使用Go语言的GET方法获取HTML并将其转换为字符串的过程中,大部分页面都可以正常运行。然而,如果使用这种方式,对于除utf-8之外的字符编码,可能会出现乱码的问题。
因此,我会留下一些备忘录关于如何获取设置了非utf-8字符编码的HTML。
应对策略
这次我们将尝试使用stackoverflow的golang HTML字符集解码答案中提到的charset.DetermineEncoding方法。根据这个stackoverflow的内容,我们考虑到了以下两个问题。
第一点是在charset.DetermineEncoding中,正如在Determining the character encoding文档中所述,似乎是通过多个要素来推断字符编码。而且,似乎在shift-jis页面上判断时,certain有时会变为false(经过一些页面的尝试)。这次我们将certain的结果设置为不使用。
第二点是关于用来判断字符编码的,所以需要通过Reader进行一次读取,如果要读取全部的html内容,则需要复制它。可以使用【golang】中的io.Reader来判断ContentType,有一篇介绍在S3上传后遇到问题的文章中提到了一些方法,但这次我们决定使用io.TeeReader来实现。
实施样本
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"net/http"
"golang.org/x/net/html/charset"
"golang.org/x/text/encoding/htmlindex"
)
func detectContentCharset(body io.Reader) string {
r := bufio.NewReader(body)
if data, err := r.Peek(1024); err == nil {
// certainがfalseの場合もそのまま使う
_, name, _ := charset.DetermineEncoding(data, "")
if name != "" {
return name
}
}
return "utf-8"
}
func main() {
// htmlページの取得
// webPage := ("https://mayukasports.blogspot.com/") // UTF-8のサイト
webPage := ("http://abehiroshi.la.coocan.jp/top.htm") // Shift_JISのサイト
resp, err := http.Get(webPage)
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
// 文字コードチェック用のreadのためにbodyをコピーしておく
body := new(bytes.Buffer)
bodyForCheck := io.TeeReader(resp.Body, body)
// 文字コードの判定
charset := detectContentCharset(bodyForCheck)
encode, err := htmlindex.Get(charset)
if err != nil {
fmt.Println(err)
return
}
// htmlのRead
var contentBytes []byte
if name, _ := htmlindex.Name(encode); name != "utf-8" {
encodeBody := encode.NewDecoder().Reader(body)
contentBytes, err = io.ReadAll(encodeBody)
} else {
contentBytes, err = io.ReadAll(body)
}
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(contentBytes))
}