ch7/ch7-02 #150
ch7/ch7-02
#150
Replies: 7 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
-
|
Beta Was this translation helpful? Give feedback.
0 replies
-
|
Beta Was this translation helpful? Give feedback.
0 replies
-
6.5 type limitReader struct {
r io.Reader
n int64
}
func (r *limitReader) Read(p []byte) (int, error) {
if r.n <= 0 {
return 0, io.EOF
}
if int64(len(p)) > r.n {
p = p[:r.n]
}
n, err := r.r.Read(p)
r.n -= int64(n)
return n, err
}
func LimitReader(r io.Reader, n int64) io.Reader {
return &limitReader{r, n}
} |
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
Uh oh!
There was an error while loading. Please reload this page.
-
ch7/ch7-02
中文版
https://golang-china.github.io/gopl-zh/ch7/ch7-02.html
Beta Was this translation helpful? Give feedback.
All reactions