Как преобразовать таблицу HTML в массив с помощью golang
У меня возникла проблема при попытке преобразовать таблицу HTML в массив Golang. Я пытался добиться этого, используя x/net/html и goquery, но безуспешно для них обоих.
Допустим, у нас есть эта таблица HTML:
<html>
<body>
<table>
<tr>
<td>Row 1, Content 1<td>
<td>Row 1, Content 2<td>
<td>Row 1, Content 3<td>
<td>Row 1, Content 4<td>
</tr>
<tr>
<td>Row 2, Content 1<td>
<td>Row 2, Content 2<td>
<td>Row 2, Content 3<td>
<td>Row 2, Content 4<td>
</tr>
</table>
</body>
</html>
И я хотел бы закончить с этим массивом:
------------------------------------
|Row 1, Content 1| Row 1, Content 2|
------------------------------------
|Row 2, Content 1| Row 2, Content 2|
------------------------------------
Как вы видите, я просто игнорирую содержание 3 и 4.
Мой код извлечения:
func extractValue(content []byte) {
doc, _ := goquery.NewDocumentFromReader(bytes.NewReader(content))
doc.Find("table tr td").Each(func(i int, td *goquery.Selection) {
// ...
})
}
Я попытался добавить номер контроллера, который будет отвечать за игнорирование <td>
что я не хочу конвертировать и звоню
td.NextAll()
но без удачи. Ребята, вы знаете, что мне делать, чтобы это сделать?
Благодарю.
3 ответа
Вы можете уйти с пакетом golang.org/x/net/html
только.
var body = strings.NewReader(`
<html>
<body>
<table>
<tr>
<td>Row 1, Content 1<td>
<td>Row 1, Content 2<td>
<td>Row 1, Content 3<td>
<td>Row 1, Content 4<td>
</tr>
<tr>
<td>Row 2, Content 1<td>
<td>Row 2, Content 2<td>
<td>Row 2, Content 3<td>
<td>Row 2, Content 4<td>
</tr>
</table>
</body>
</html>`)
func main() {
z := html.NewTokenizer(body)
content := []string{}
// While have not hit the </html> tag
for z.Token().Data != "html" {
tt := z.Next()
if tt == html.StartTagToken {
t := z.Token()
if t.Data == "td" {
inner := z.Next()
if inner == html.TextToken {
text := (string)(z.Text())
t := strings.TrimSpace(text)
content = append(content, t)
}
}
}
}
// Print to check the slice's content
fmt.Println(content)
}
Этот код написан только для этого типичного HTML-шаблона, но рефакторинг, чтобы сделать его более общим, не составит труда.
Если вам нужен более структурированный способ извлечения данных из HTML-таблиц, https://github.com/nfx/go-htmltable поддерживает row/colspans.
type AM4 struct {
Model string `header:"Model"`
ReleaseDate string `header:"Release date"`
PCIeSupport string `header:"PCIesupport[a]"`
MultiGpuCrossFire bool `header:"Multi-GPU CrossFire"`
MultiGpuSLI bool `header:"Multi-GPU SLI"`
USBSupport string `header:"USBsupport[b]"`
SATAPorts int `header:"Storage features SATAports"`
RAID string `header:"Storage features RAID"`
AMDStoreMI bool `header:"Storage features AMD StoreMI"`
Overclocking string `header:"Processoroverclocking"`
TDP string `header:"TDP"`
SupportExcavator string `header:"CPU support[14] Excavator"`
SupportZen string `header:"CPU support[14] Zen"`
SupportZenPlus string `header:"CPU support[14] Zen+"`
SupportZen2 string `header:"CPU support[14] Zen 2"`
SupportZen3 string `header:"CPU support[14] Zen 3"`
Architecture string `header:"Architecture"`
}
am4Chipsets, _ := htmltable.NewSliceFromURL[AM4]("https://en.wikipedia.org/wiki/List_of_AMD_chipsets")
fmt.Println(am4Chipsets[2].Model)
fmt.Println(am4Chipsets[2].SupportZen2)
// Output:
// X370
// Varies[c]
Попробуйте такой подход, чтобы создать 2d-массив и обрабатывать переменные размеры строк:
z := html.NewTokenizer(body)
table := [][]string{}
row := []string{}
for z.Token().Data != "html" {
tt := z.Next()
if tt == html.StartTagToken {
t := z.Token()
if t.Data == "tr" {
if len(row) > 0 {
table = append(table, row)
row = []string{}
}
}
if t.Data == "td" {
inner := z.Next()
if inner == html.TextToken {
text := (string)(z.Text())
t := strings.TrimSpace(text)
row = append(row, t)
}
}
}
}
if len(row) > 0 {
table = append(table, row)
}