ch7/ch7-02 #150
ch7/ch7-02
#150
Replies: 4 comments
-
练习7.4 将第5章的某一些功能重新了一下package main
import (
"fmt"
"golang.org/x/net/html"
"io"
"net/http"
"strings"
)
type Html interface {
io.ReadCloser
Getdoc(url string) (err error)
ForeachNode(n *html.Node, pre, post func(n *html.Node))
SearchNode(tag string) []*html.Node
PrintAll()
}
// 不对外暴露,一切操作均通过方法实现
// 除了Html接口中定义的方法, 还可以自己拓展方法, 例如Show方法
type htmlParser struct {
Html
str string
node *html.Node
resp *http.Response
}
// 自定义读入
func (doc *htmlParser) Read(p []byte) (n int, err error) {
if len(p) == 0 {
return 0, fmt.Errorf("error, read data is empty")
}
n = copy(p, doc.str)
if doc.node != nil {
return 0, fmt.Errorf("error, node is not empty")
}
doc.node, err = html.Parse(strings.NewReader(doc.str))
return n, err
}
// Clear 清空
func (doc *htmlParser) Clear() {
doc.node = nil
doc.resp = nil
}
// Close 关闭连接
func (doc *htmlParser) Close() error {
return doc.resp.Body.Close()
}
// Getdoc 通过url获取网页内容
func (doc *htmlParser) Getdoc(url string) (err error) {
doc.resp, err = http.Get(url)
defer doc.Close() // 关闭连接
if doc.resp.StatusCode != http.StatusOK {
err = fmt.Errorf("http get error: %s", doc.resp.Status)
return err
}
doc.node, err = html.Parse(doc.resp.Body)
if err != nil {
return fmt.Errorf("html parse error: %s", err)
}
return nil
}
// ForEachNode 遍历节点
func (doc *htmlParser) ForEachNode(n *html.Node, pre, post func(n *html.Node)) {
if n == nil {
return
}
if pre != nil {
pre(n)
}
doc.ForEachNode(n.FirstChild, pre, post)
doc.ForEachNode(n.NextSibling, pre, post)
if post != nil {
post(n)
}
}
// SearchNode 搜索节点
func (doc *htmlParser) SearchNode(tag string) []*html.Node {
var nodes []*html.Node
doc.ForEachNode(doc.node, func(n *html.Node) {
if n.Type == html.ElementNode && n.Data == tag {
nodes = append(nodes, n)
}
}, nil)
return nodes
}
// PrintAll 打印所有节点
func (doc *htmlParser) PrintAll() {
doc.ForEachNode(doc.node, func(n *html.Node) {
if n.Type == html.ElementNode {
fmt.Printf("%s\n", n.Data)
}
}, nil)
}
// Show 是没有定义在接口中的方法,所以只能通过结构体实例调用
func (doc *htmlParser) Show() {
fmt.Println(doc.resp)
fmt.Println()
fmt.Println(doc.node)
}
func main() {
var doc htmlParser
doc.Getdoc("https://go.dev/")
doc.Show()
// 如果使用接口类型,则不能使用Show方法
//var doc Html
//doc.Getdoc("https://go.dev/")
// 因为接口类型中没有定义Show方法,所以不能调用
//doc.Show() // error, Show undefined (type Html has no field or method Show)
} |
Beta Was this translation helpful? Give feedback.
0 replies
-
7.4package main
import (
"fmt"
"io"
"os"
"golang.org/x/net/html"
)
// 定义一个html结构体
type HtmlReader struct {
html []byte
i int
}
// 跟着strings.NewReader写的
func (h *HtmlReader) Read(p []byte) (n int, err error) {
// 存储的索引大于byte数组,表示都读完了
if h.i >= len(h.html) {
return 0, io.EOF
}
// 复制p长度/剩余长度的字节到p
n = copy(p, h.html[h.i:])
// 变化索引
h.i += n
return
}
// NewReader,将html转化为reader,以供解析器解析
func NewReader(html string) *HtmlReader {
return &HtmlReader{html: []byte(html), i: 0}
}
func main() {
doc, err := html.Parse(NewReader(`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
hahaha
</body>
</html>
`))
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Printf("%#v", doc)
} |
Beta Was this translation helpful? Give feedback.
0 replies
-
7.5package main
import (
"bufio"
"fmt"
"io"
"strings"
)
type reader struct {
i int
read io.Reader
n int
}
func (r *reader) Read(p []byte) (n int, err error) {
// 到达n,直接结束
if r.i >= r.n {
return 0, io.EOF
}
// 剩余的长度不够p
if r.n-r.i < len(p) {
n, _ = r.read.Read(p[:r.n-r.i])
err = io.EOF
return
}
// 通过嵌套读取另一个流
n, err = r.read.Read(p)
// 另一个流读到尾部了
if err != nil {
return
}
// 修改索引
r.i += n
return
}
func LimitReader(r io.Reader, n int) io.Reader {
return &reader{i: 0, read: r, n: n}
}
func main() {
// 创建一个读入流
r := strings.NewReader("1234567890")
r1 := LimitReader(r, 4)
s := bufio.NewScanner(r1)
s.Split(bufio.ScanBytes)
for s.Scan() {
fmt.Println(s.Text())
}
} |
Beta Was this translation helpful? Give feedback.
0 replies
-
翻译看晕了,能好好表述吗,好绕 |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
ch7/ch7-02
中文版
https://golang-china.github.io/gopl-zh/ch7/ch7-02.html
Beta Was this translation helpful? Give feedback.
All reactions