Go goquery
last modified April 25, 2026
In this article, we demonstrate how to perform web scraping and HTML parsing in Go using the goquery library. Goquery provides a convenient, jQuery‑like API that makes it easy to traverse HTML documents, extract elements, and manipulate content using familiar CSS selectors.
Under the hood, goquery builds on two core components from the Go ecosystem: the standard library's net/html package, which parses HTML into a DOM tree, and the cascadia library, which implements CSS selector matching. Together, they allow goquery to offer a high-level, expressive interface while relying on robust, battle-tested parsing tools.
To install goquery, run:
This command downloads the goquery package and makes it available for use in your project.
Go goquery get title
The following example, we get a title of a webpage.
package main
import (
"fmt"
"log"
"net/http"
"github.com/PuerkitoBio/goquery"
)
func main() {
webPage := "https://example.com"
resp, err := http.Get(webPage)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
log.Fatalf("failed to fetch data: %d %s", resp.StatusCode, resp.Status)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
log.Fatal(err)
}
title := doc.Find("title").Text()
fmt.Println(title)
}
We generate a GET request to the specified webpage and retrieve its contents. From the body of the response, we generate a goquery document. From this document, we retrieve the title.
title := doc.Find("title").Text()
The Find method returns a set of matched elements. In our case,
it is one title tag. With Text, we get the text
content of the tag.
$ go run main.go Example Domain
Go goquery read local file
The following example reads a local HTML file.
<!DOCTYPE html>
<html lang="en">
<body>
<main>
<h1>My website</h1>
<p>
I am a Go programmer.
</p>
<p>
My hobbies are:
</p>
<ul>
<li>Swimming</li>
<li>Tai Chi</li>
<li>Running</li>
<li>Web development</li>
<li>Reading</li>
<li>Music</li>
</ul>
</main>
</body>
</html>
This is a simple HTML file.
package main
import (
"fmt"
"log"
"os"
"regexp"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
data, err := os.ReadFile("index.html")
if err != nil {
log.Fatal(err)
}
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(data)))
if err != nil {
log.Fatal(err)
}
text := doc.Find("h1,p").Text()
re := regexp.MustCompile(`\s{2,}`)
fmt.Println(re.ReplaceAllString(text, "\n"))
}
We get the text contents of two tags.
data, err := os.ReadFile("index.html")
We read the file.
doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(data)))
We generate a new goquery document with NewDocumentFromReader.
text := doc.Find("h1,p").Text()
We get the text contents of two tags: h1 and p.
re := regexp.MustCompile(`\s{2,}`)
fmt.Println(re.ReplaceAllString(text, "\n"))
Using a regular expression, we remove excessive white space.
$ go run main.go My website I am a Go programmer. My hobbies are:
Go goquery read from HTML string
In the next example, we process a built-in HTML string.
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
data := `
<html lang="en">
<body>
<p>List of words</p>
<ul>
<li>dark</li>
<li>smart</li>
<li>war</li>
<li>cloud</li>
<li>park</li>
<li>cup</li>
<li>worm</li>
<li>water</li>
<li>rock</li>
<li>warm</li>
</ul>
<footer>footer for words</footer>
</body>
</html>
`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
words := doc.Find("li").Map(func(i int, sel *goquery.Selection) string {
return fmt.Sprintf("%d: %s", i+1, sel.Text())
})
fmt.Println(words)
}
We get the words from the HTML list.
words := doc.Find("li").Map(func(i int, sel *goquery.Selection) string {
return fmt.Sprintf("%d: %s", i+1, sel.Text())
})
With Find, we get all the li elements. The
Map method is used to build a string that contains the word
and its index in the list.
$ go run get_words.go [1: dark 2: smart 3: war 4: cloud 5: park 6: cup 7: worm 8: water 9: rock 10: warm]
Go goquery document node
When goquery parses an HTML document, it wraps everything in a virtual
document node. This node is not an HTML element; its Data
field is an empty string. The real page elements are its children.
The internal tree looks like this:
DocumentNode ("") ← doc.Selection.Get(0)
├── DoctypeNode ("html") ← <!DOCTYPE html>
└── ElementNode ("html") ← <html lang="en">
├── <head>
└── <body>
Because doc.Selection wraps the document node, calling
doc.Selection.Get(0).Data returns an empty string. To get the
root element tag name we must step into the document node's children.
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
data := `<!DOCTYPE html>
<html lang="en">
<head><title>Test</title></head>
<body><p>Hello</p></body>
</html>`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
// doc.Selection is a DocumentNode — Data is empty
fmt.Printf("doc.Selection Data: %q\n", doc.Selection.Get(0).Data)
// Step into children to reach the <html> element
rootTag := doc.Selection.Children().First().Get(0).Data
fmt.Printf("root element tag: %q\n", rootTag)
}
The example demonstrates the difference between the document node and the root HTML element.
fmt.Printf("doc.Selection Data: %q\n", doc.Selection.Get(0).Data)
Printing doc.Selection.Get(0).Data yields an empty string because
doc.Selection wraps the virtual document node, which has no tag name.
rootTag := doc.Selection.Children().First().Get(0).Data
Children returns the direct children of the document node — the
doctype declaration and the <html> element.
First picks the first child element, and Get(0)
retrieves the underlying *html.Node. Its Data field
holds the tag name.
$ go run main.go doc.Selection Data: "" root element tag: "html"
Go goquery filter words
The following example filters words.
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
data := `
<html lang="en">
<body>
<p>List of words</p>
<ul>
<li>dark</li>
<li>smart</li>
<li>war</li>
<li>cloud</li>
<li>park</li>
<li>cup</li>
<li>worm</li>
<li>water</li>
<li>rock</li>
<li>warm</li>
</ul>
<footer>footer for words</footer>
</body>
</html>
`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
f := func(i int, sel *goquery.Selection) bool {
return strings.HasPrefix(sel.Text(), "w")
}
var words []string
doc.Find("li").FilterFunction(f).Each(func(_ int, sel *goquery.Selection) {
words = append(words, sel.Text())
})
fmt.Println(words)
}
We retrieve all words starting with 'w'.
f := func(i int, sel *goquery.Selection) bool {
return strings.HasPrefix(sel.Text(), "w")
}
This is a predicate function that returns a boolean true for all words that begin with 'w'.
doc.Find("li").FilterFunction(f).Each(func(_ int, sel *goquery.Selection) {
words = append(words, sel.Text())
})
We locate the set of matching tags with Find. We filter the set
with FilterFunction and go over the filtered results with
Each. We add each filtered word to the words slice.
fmt.Println(words)
Finally, we print the slice.
$ go run main.go [war worm water warm]
Go goquery union words
With Union, we can combine selections.
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
data := `
<html lang="en">
<body>
<p>List of words</p>
<ul>
<li>dark</li>
<li>smart</li>
<li>war</li>
<li>cloud</li>
<li>park</li>
<li>cup</li>
<li>worm</li>
<li>water</li>
<li>rock</li>
<li>warm</li>
</ul>
<footer>footer for words</footer>
</body>
</html>
`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
var words []string
sel1 := doc.Find("li:first-child, li:last-child")
sel2 := doc.Find("li:nth-child(3), li:nth-child(7)")
sel1.Union(sel2).Each(func(_ int, sel *goquery.Selection) {
words = append(words, sel.Text())
})
fmt.Println(words)
}
The example combines two selections.
sel1 := doc.Find("li:first-child, li:last-child")
The first selection contains the first and the last element.
sel2 := doc.Find("li:nth-child(3), li:nth-child(7)")
The second selection contains the third and the seventh element.
sel1.Union(sel2).Each(func(_ int, sel *goquery.Selection) {
words = append(words, sel.Text())
})
We combine the two selections with Union.
$ go run main.go [dark warm war worm]
Go goquery get links
The following example retrieves links from a webpage.
package main
import (
"fmt"
"log"
"net/http"
"strings"
"github.com/PuerkitoBio/goquery"
)
func getLinks() {
webPage := "https://golang.org"
resp, err := http.Get(webPage)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
log.Fatalf("status code error: %d %s", resp.StatusCode, resp.Status)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
log.Fatal(err)
}
f := func(i int, s *goquery.Selection) bool {
link, _ := s.Attr("href")
return strings.HasPrefix(link, "https")
}
doc.Find("body a").FilterFunction(f).Each(func(_ int, tag *goquery.Selection) {
link, _ := tag.Attr("href")
linkText := tag.Text()
fmt.Printf("%s %s\n", linkText, link)
})
}
func main() {
getLinks()
}
The example retrieves external links to secured web pages.
f := func(i int, s *goquery.Selection) bool {
link, _ := s.Attr("href")
return strings.HasPrefix(link, "https")
}
In the predicate function we ensure that the link has the https
prefix.
doc.Find("body a").FilterFunction(f).Each(func(_ int, tag *goquery.Selection) {
link, _ := tag.Attr("href")
linkText := tag.Text()
fmt.Printf("%s %s\n", linkText, link)
})
We find all the anchor tags, filter them, and then print the filtered links to the console.
Go goquery DOM traversal
goquery provides methods to navigate the DOM tree relative to a matched
element: Parent, Prev, Next, and
NextAll/PrevAll.
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
data := `
<html lang="en">
<body>
<ul id="langs">
<li>Go</li>
<li>Rust</li>
<li>Python</li>
<li>Java</li>
<li>C++</li>
</ul>
</body>
</html>`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
third := doc.Find("li:nth-child(3)")
fmt.Println("Current: ", third.Text())
fmt.Println("Previous: ", third.Prev().Text())
fmt.Println("Next: ", third.Next().Text())
fmt.Println("Parent id:", third.Parent().AttrOr("id", ""))
fmt.Print("Following siblings: ")
third.NextAll().Each(func(_ int, s *goquery.Selection) {
fmt.Print(s.Text(), " ")
})
fmt.Println()
}
The example selects the third list item and navigates around it.
third := doc.Find("li:nth-child(3)")
We select the third li element using the CSS pseudo-class
:nth-child.
fmt.Println("Previous: ", third.Prev().Text())
fmt.Println("Next: ", third.Next().Text())
Prev and Next return the immediately adjacent
sibling elements.
fmt.Println("Parent id:", third.Parent().AttrOr("id", ""))
Parent moves up one level in the tree. AttrOr
reads an attribute value and returns the supplied default when the attribute
is absent.
third.NextAll().Each(func(_ int, s *goquery.Selection) {
NextAll returns all following siblings in document order.
$ go run main.go Current: Python Previous: Rust Next: Java Parent id: langs Following siblings: Java C++
Go goquery Has and Not
Has narrows a selection to elements that contain a given
descendant, while Not excludes elements that match a selector.
Together they let you split a set into two complementary subsets.
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
data := `
<html lang="en">
<body>
<ul>
<li><a href="https://golang.org">Go</a></li>
<li>Rust</li>
<li><a href="https://python.org">Python</a></li>
<li>Java</li>
<li><a href="https://isocpp.org">C++</a></li>
</ul>
</body>
</html>`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
fmt.Println("Items with a link:")
doc.Find("li").Has("a").Each(func(_ int, s *goquery.Selection) {
link, _ := s.Find("a").Attr("href")
fmt.Printf(" %-8s %s\n", s.Text(), link)
})
fmt.Println("Items without a link:")
doc.Find("li").Not(":has(a)").Each(func(_ int, s *goquery.Selection) {
fmt.Println(" ", s.Text())
})
}
The example separates list items that contain an anchor from those that do not.
doc.Find("li").Has("a").Each(...)
Has("a") keeps only li elements that have at least
one descendant a tag.
doc.Find("li").Not(":has(a)").Each(...)
Not(":has(a)") is the complement — it discards any
li that contains an anchor, leaving the plain-text items.
$ go run main.go Items with a link: Go https://golang.org Python https://python.org C++ https://isocpp.org Items without a link: Rust Java
Go goquery parse HTML table
A common scraping task is extracting data from an HTML table into a slice of structs. goquery makes this straightforward by letting you iterate over rows and cells.
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
type Person struct {
Name string
Age string
City string
}
func main() {
data := `
<html lang="en">
<body>
<table>
<thead>
<tr><th>Name</th><th>Age</th><th>City</th></tr>
</thead>
<tbody>
<tr><td>Alice</td><td>30</td><td>New York</td></tr>
<tr><td>Bob</td><td>25</td><td>London</td></tr>
<tr><td>Carol</td><td>35</td><td>Sydney</td></tr>
<tr><td>David</td><td>28</td><td>Berlin</td></tr>
</tbody>
</table>
</body>
</html>`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
var people []Person
doc.Find("tbody tr").Each(func(_ int, row *goquery.Selection) {
var cols []string
row.Find("td").Each(func(_ int, td *goquery.Selection) {
cols = append(cols, strings.TrimSpace(td.Text()))
})
if len(cols) == 3 {
people = append(people, Person{cols[0], cols[1], cols[2]})
}
})
fmt.Printf("%-8s %-5s %s\n", "Name", "Age", "City")
fmt.Println(strings.Repeat("-", 25))
for _, p := range people {
fmt.Printf("%-8s %-5s %s\n", p.Name, p.Age, p.City)
}
}
The example parses an HTML table into a slice of Person structs.
doc.Find("tbody tr").Each(func(_ int, row *goquery.Selection) {
We iterate over every data row inside tbody, skipping the header
row which lives in thead.
row.Find("td").Each(func(_ int, td *goquery.Selection) {
cols = append(cols, strings.TrimSpace(td.Text()))
})
For each row we collect the text of every cell into a string slice. The order of cells matches the column order in the HTML.
if len(cols) == 3 {
people = append(people, Person{cols[0], cols[1], cols[2]})
}
We guard against malformed rows before constructing the struct and appending it to the slice.
$ go run main.go Name Age City ------------------------- Alice 30 New York Bob 25 London Carol 35 Sydney David 28 Berlin
Go goquery ancestor traversal
Besides moving down the tree with Find, goquery lets you move
up the tree with Parents, ParentsFiltered,
and Closest. Closest walks up from the current
element and returns the nearest ancestor that matches a selector, including
the element itself.
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
data := `
<html lang="en">
<body>
<article id="post-1">
<section class="content">
<p>
See the <a href="/glossary" class="ref">glossary</a> for details.
</p>
</section>
</article>
</body>
</html>`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
link := doc.Find("a.ref")
// Nearest ancestor that is a section
section := link.Closest("section")
fmt.Println("Closest section class:", section.AttrOr("class", ""))
// Nearest ancestor that is an article
article := link.Closest("article")
fmt.Println("Closest article id: ", article.AttrOr("id", ""))
// All ancestors, outermost last
fmt.Print("All ancestor tags: ")
link.Parents().Each(func(_ int, s *goquery.Selection) {
fmt.Print(goquery.NodeName(s), " ")
})
fmt.Println()
// Only ancestor tags that are block-level containers
fmt.Print("Filtered ancestors (section, article, body): ")
link.ParentsFiltered("section, article, body").Each(func(_ int, s *goquery.Selection) {
fmt.Print(goquery.NodeName(s), " ")
})
fmt.Println()
}
The example starts from a deeply nested anchor tag and climbs the DOM tree in several ways.
section := link.Closest("section")
Closest starts at the element itself and walks up, returning the
first match. Here it finds the enclosing <section>.
link.Parents().Each(func(_ int, s *goquery.Selection) {
fmt.Print(goquery.NodeName(s), " ")
})
Parents returns all ancestors from the immediate parent
up to the document root. goquery.NodeName is a helper that
returns the lowercase tag name of a selection.
link.ParentsFiltered("section, article, body").Each(...)
ParentsFiltered is like Parents but keeps only
ancestors that match the supplied selector.
$ go run main.go Closest section class: content Closest article id: post-1 All ancestor tags: p section article body html Filtered ancestors (section, article, body): section article body
Go goquery modify document
goquery is not limited to reading HTML — it can also mutate the parsed tree.
SetAttr and RemoveAttr change element attributes,
while SetHtml replaces an element's inner HTML. The modified
document can be serialised back to a string with goquery.OuterHtml.
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
data := `
<html lang="en">
<body>
<ul id="links">
<li><a href="http://golang.org">Go</a></li>
<li><a href="http://rust-lang.org">Rust</a></li>
<li><a href="http://python.org">Python</a></li>
</ul>
</body>
</html>`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
// Upgrade every http:// link to https://
doc.Find("a[href]").Each(func(_ int, s *goquery.Selection) {
href, _ := s.Attr("href")
if strings.HasPrefix(href, "http://") {
s.SetAttr("href", strings.Replace(href, "http://", "https://", 1))
}
})
// Add a rel="noopener" attribute to all links
doc.Find("a").SetAttr("rel", "noopener")
// Replace the inner HTML of the list caption
doc.Find("ul#links").SetHtml(`<li><a href="https://go.dev" rel="noopener">Go (updated)</a></li>`)
// Serialise the modified ul back to a string
html, err := goquery.OuterHtml(doc.Find("ul#links"))
if err != nil {
log.Fatal(err)
}
fmt.Println(html)
}
The example upgrades all links from HTTP to HTTPS, adds a security attribute, then replaces the list contents entirely.
s.SetAttr("href", strings.Replace(href, "http://", "https://", 1))
SetAttr sets an attribute value on every node in the selection.
Here we rewrite the href to use a secure scheme.
doc.Find("a").SetAttr("rel", "noopener")
Calling SetAttr on a multi-element selection applies the change
to all matched elements at once.
doc.Find("ul#links").SetHtml(`<li>...</li>`)
SetHtml replaces the inner HTML of the matched element, discarding
its previous children.
html, err := goquery.OuterHtml(doc.Find("ul#links"))
goquery.OuterHtml serialises the element including its
own opening and closing tags back into an HTML string.
Go goquery StackOverflow questions
We are going to get the latest StackOverflow questions for the Raku tag.
package main
import (
"fmt"
"log"
"net/http"
"github.com/PuerkitoBio/goquery"
)
func main() {
webPage := "https://stackoverflow.com/questions/tagged/raku"
resp, err := http.Get(webPage)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
log.Fatalf("failed to fetch data: %d %s", resp.StatusCode, resp.Status)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
log.Fatal(err)
}
doc.Find(".question-summary .summary").Each(func(i int, s *goquery.Selection) {
title := s.Find("h3").Text()
fmt.Println(i+1, title)
})
}
In the code example, we print the last fifty titles of the StackOverflow questions on the Raku programming language.
doc.Find(".question-summary .summary").Each(func(i int, s *goquery.Selection) {
title := s.Find("h3").Text()
fmt.Println(i+1, title)
})
We locate the questions and print their titles; the title is in the
h3 tag.
$ go run get_qs.go 1 Raku pop() order of execution 2 Does the `do` keyword run a block or treat it as an expression? 3 Junction ~~ Junction behavior 4 Is there a way to detect whether something is immutable? 5 Optimize without sacrificing usual workflow: arguments, POD etc 6 Find out external command runability ...
Go goquery get earthquakes
In the next example, we fetch data about earthquakes.
$ go get github.com/olekukonko/tablewriter
We use the tablewriter package to display data in tabular format.
package main
import (
"log"
"net/http"
"os"
"strings"
"github.com/PuerkitoBio/goquery"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/tw"
)
type Earthquake struct {
Date string
Latitude string
Longitude string
Magnitude string
Depth string
Location string
IrisId string
}
var quakes []Earthquake
func fetchQuakes() {
webPage := "https://www.iris.edu/app/seismic-monitor/table?lat=16.4657&lng=-67.5192&zoom=2"
resp, err := http.Get(webPage)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
log.Fatalf("failed to fetch data: %d %s", resp.StatusCode, resp.Status)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
log.Fatal(err)
}
doc.Find("tbody tr").Each(func(j int, tr *goquery.Selection) {
if j >= 10 {
return
}
e := Earthquake{}
tr.Find("td").Each(func(ix int, td *goquery.Selection) {
switch ix {
case 0:
e.Date = td.Text()
case 1:
e.Latitude = td.Text()
case 2:
e.Longitude = td.Text()
case 3:
e.Magnitude = td.Text()
case 4:
e.Depth = td.Text()
case 5:
e.Location = strings.TrimSpace(td.Text())
case 6:
e.IrisId = td.Text()
}
})
quakes = append(quakes, e)
})
table := tablewriter.NewWriter(os.Stdout)
table.Header([]string{"Date", "Location", "Magnitude", "Longitude",
"Latitude", "Depth", "IrisId"})
table.Caption(tw.Caption{
Text: "Last ten earthquakes",
// Optional: choose placement, alignment, and width
Spot: tw.SpotBottomLeft, // or tablewriter.Top
Align: tw.AlignLeft, // or Left, Right
Width: 80, // custom width if needed
})
for _, quake := range quakes {
s := []string{
quake.Date,
quake.Location,
quake.Magnitude,
quake.Longitude,
quake.Latitude,
quake.Depth,
quake.IrisId,
}
table.Append(s)
}
table.Render()
}
func main() {
fetchQuakes()
}
The example retrieves ten latest earthquakes from the Iris database. It prints the data in a tabular format.
type Earthquake struct {
Date string
Latitude string
Longitude string
Magnitude string
Depth string
Location string
IrisId string
}
The data is grouped in the Earthquake structure.
var quakes []Earthquake
The structures will be stored in the quakes slice.
doc.Find("tbody tr").Each(func(j int, tr *goquery.Selection) {
Locating data is simple; we go for the tr tags inside the
tbody tag.
e := Earthquake{}
tr.Find("td").Each(func(ix int, td *goquery.Selection) {
switch ix {
case 0:
e.Date = td.Text()
case 1:
e.Latitude = td.Text()
case 2:
e.Longitude = td.Text()
case 3:
e.Magnitude = td.Text()
case 4:
e.Depth = td.Text()
case 5:
e.Location = strings.TrimSpace(td.Text())
case 6:
e.IrisId = td.Text()
}
})
quakes = append(quakes, e)
We create a new Earthquake structure, fill it with table row data
and put the structure into the quakes slice.
table := tablewriter.NewWriter(os.Stdout)
table.Header([]string{"Date", "Location", "Magnitude", "Longitude",
"Latitude", "Depth", "IrisId"})
table.Caption(tw.Caption{
Text: "Last ten earthquakes",
// Optional: choose placement, alignment, and width
Spot: tw.SpotBottomLeft, // or tablewriter.Top
Align: tw.AlignLeft, // or Left, Right
Width: 80, // custom width if needed
})
We create a new table for displaying our data. The data will be shown in the standard output (console). We create a header and a caption for the table.
for _, quake := range quakes {
s := []string{
quake.Date,
quake.Location,
quake.Magnitude,
quake.Longitude,
quake.Latitude,
quake.Depth,
quake.IrisId,
}
table.Append(s)
}
The table takes a string slice as a parameter; therefore, we transform the
structure into a slice and append the slice to the table with
Append.
table.Render()
In the end, we render the table.
Source
In this article we have scraped web/parsed HTML in Go with the goquery
package.
Author
List all Go tutorials.