goquery как вывести текст с пагинацией?
Нужно чтобы при обнаружении текста в котором будут квадратные скобки [Rand]. Весь текст, что будет после них и до следующих кв.скобок заносился в массив. Фото для примера, взял отсюда https://genius.com/The-used-the-taste-of-ink-lyrics
Уже есть почти готовый код, но никак не могу понять как его развить дальше
import (
"fmt"
"log"
"net/http"
"strings"
"github.com/PuerkitoBio/goquery"
)
func FindTextSong(groupName, songName string) []string {
songName = strings.ReplaceAll(songName, " ", "-")
url := fmt.Sprintf("https://genius.com/%s-%s-lyrics", groupName, songName)
res, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != 200 {
log.Fatalf("Ошибка: состояние ответа %d", res.StatusCode)
}
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
log.Fatal(err)
}
var date []string
doc.Find("[class^='Lyrics__Container']").Each(func(i int, s *goquery.Selection) {
text := s.Text()
if strings.TrimSpace(text) != "" {
date = append(date, text)
}
})
return date
}
Ответы (1 шт):
s.Text() удаляет все элементы и сливает строчки в одну.
Решение в лоб: итерировать s.Nodes и выбирать оттуда текст самостоятельно.
package main
import (
"fmt"
"log"
"net/http"
"strings"
"github.com/PuerkitoBio/goquery"
"golang.org/x/net/html"
)
func FindTextSong(groupName, songName string) (Song, error) {
songName = strings.ReplaceAll(songName, " ", "-")
url := fmt.Sprintf("https://genius.com/%s-%s-lyrics", groupName, songName)
result := Song{}
res, err := http.Get(url)
if err != nil {
return result, err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return result, fmt.Errorf("Ошибка: состояние ответа %d", res.StatusCode)
}
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
return result, err
}
currentVerse := Verse{
Header: "",
Lines: []string{},
}
doc.Find("[class^='Lyrics__Container']").Each(func(i int, s *goquery.Selection) {
sel := s.Contents()
for _, n := range sel.Nodes {
if n.Type == html.TextNode {
text := strings.TrimSpace(n.Data)
if text[0] == '[' {
if currentVerse.Header != "" {
result = append(result, currentVerse)
currentVerse = Verse{}
}
currentVerse.Header = text
} else {
currentVerse.Lines = append(currentVerse.Lines, text)
}
}
}
if currentVerse.Header != "" {
result = append(result, currentVerse)
}
})
return result, nil
}
func main() {
song, err := FindTextSong("The-used", "the-taste-of-ink")
if err != nil {
log.Fatal(err)
}
fmt.Println(song)
}
type Verse struct {
Header string
Lines []string
}
func (l Verse) String() string {
return l.Header + "\n" + strings.Join(l.Lines, "\n")
}
type Song []Verse
func (s Song) String() string {
builder := &strings.Builder{}
for _, v := range s {
builder.WriteString(v.String())
builder.WriteRune('\n')
}
return builder.String()
}
В своём ответе я добавил типы Song и Verse для представления песни и отдельных куплетов/припевов
Этот пример работает для genius.com, так как там строки целиком и без элементов форматирования, но в общем случае надо анализировать тип узла и заканчивать строку только для узлов <br>, <p>, <div> и прочих с display=block, и игнорировать / заменять на пробелы остальные узлы-элементы.
