【前往】对于使用「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))
}
bannerAds