package parse import ( "fmt" "io" "log" "regexp" "strings" "github.com/PuerkitoBio/goquery" ) func parseSection(s *goquery.Selection) Block { // fmt.Printf("s.Length() = %d\n", s.Length()) // fmt.Printf("s.Size() = %d\n", s.Size()) // var tokens = make([]Token, s.Size()) var tokens []Token s.Children().Each(func(i int, s *goquery.Selection) { var t Token attr := make(map[string]string) if s.Is("span") { t = Token{NORMAL_TEXT, s.Text(), nil} } else if s.Is("a") { attr["href"], _ = s.Attr("href") t = Token{LINK, removeBrAndBlank(s.Text()), attr} } else if s.Is("img") { attr["src"], _ = s.Attr("src") t = Token{IMAGE, "", attr} } else { t = Token{NORMAL_TEXT, s.Text(), nil} // TODO } // fmt.Printf("i = %d\n", i) // fmt.Printf("%+v\n", t) // tokens[i] = t tokens = append(tokens, t) }) return Block{tokens} } func ParseFromReader(r io.Reader) Article { var article Article doc, err := goquery.NewDocumentFromReader(r) if err != nil { log.Fatal(err) } var mainContent *goquery.Selection = doc.Find("#img-content") // 标题 title := mainContent.Find("#activity-name").Text() fmt.Println(title) article.title = title // meta 细节待完善 meta := mainContent.Find("#meta_content").Text() meta = removeBrAndBlank(meta) fmt.Println(meta) article.meta = meta // tags 细节待完善 tags := mainContent.Find("#js_tags").Text() tags = removeBrAndBlank(tags) fmt.Println(tags) article.tags = tags // content // section[style="line-height: 1.5em;"]>span,a => 一般段落(含文本和超链接) // p[style="line-height: 1.5em;"] => 项目列表(有序/无序) // section[style=".*text-align:center"]>img => 居中段落(图片) content := mainContent.Find("#js_content") var sections []Block content.Find("section,p").Each(func(i int, s *goquery.Selection) { fmt.Println(s.Text()) // fmt.Println(s.Attr("style")) var block Block if s.Is("p") { block = parseSection(s) } else if s.Is("section") { block = parseSection(s) } else { // TODO } // sections[i] = block sections = append(sections, block) }) article.content = sections return article } func ParseFromHTMLString(s string) Article { return ParseFromReader(strings.NewReader(s)) } func removeBrAndBlank(s string) string { regstr := "\\s{2,}" reg, _ := regexp.Compile(regstr) sb := make([]byte, len(s)) copy(sb, s) spc_index := reg.FindStringIndex(string(sb)) //在字符串中搜索 for len(spc_index) > 0 { //找到适配项 sb = append(sb[:spc_index[0]+1], sb[spc_index[1]:]...) //删除多余空格 spc_index = reg.FindStringIndex(string(sb)) //继续在字符串中搜索 } return strings.Replace(string(sb), "\n", " ", -1) } var testHTML = `

终于有人喷我了!

闪客sun 低并发编程 2021-11-26

写公众号一年了,一直盼着能有人喷喷我,今天终于被我碰到了!

‍‍
还是我的一位读者发现的,在推特上,于是分享给了我。
图片
这是喷我最近的一个新系列, 你管这破玩意叫操作系统源码 ,正愁找不到借口推广一波呢,这不就给我来素材了。
` func Test() { res := ParseFromHTMLString(testHTML) fmt.Println("---------------------------------------") fmt.Printf("%+v\n", res) }