Web scraping is the process of extracting data from websites. It can be useful in many different scenarios, such as collecting market data for research or monitoring competitors’ pricing strategies. Go is a popular programming language that is well-suited for web scraping due to its simplicity, performance, and built-in concurrency support. In this tutorial, we will walk through the process of building a web scraper with Go.


Prerequisites

Before we get started, you will need to have Go installed on your machine. You can download the latest version of Go from the official website. Additionally, we will be using the following third-party packages:

  • goquery - a package that allows you to parse and query HTML documents using CSS selectors.
  • net/http - a package that allows you to make HTTP requests.

You can install these packages using the following commands:

go get -u github.com/PuerkitoBio/goquery
go get -u net/http


Step 1: Making an HTTP Request

The first step in building a web scraper is to make an HTTP request to the website that you want to scrape. In Go, this can be done using the net/http package. Here’s an example:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    url := "https://example.com"
    resp, err := http.Get(url)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    fmt.Println(resp.StatusCode)
}

In this example, we’re making an HTTP GET request to https://example.com. If the request is successful, we print the response status code to the console. Note that we’re using the defer keyword to ensure that the response body is closed after we’re done with it.


Step 2: Parsing HTML

Once we have made an HTTP request and received a response, we can parse the HTML content of the page using the goquery package. Here’s an example:

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/PuerkitoBio/goquery"
)

func main() {
    url := "https://example.com"
    resp, err := http.Get(url)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    doc, err := goquery.NewDocumentFromReader(resp.Body)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(doc.Find("title").Text())
}

In this example, we’re using goquery to parse the HTML content of the page. We first create a new Document object using the response body from the HTTP request. We then use the Find method to search for the title element and print its text to the console.


Step 3: Extracting Data

Now that we can parse HTML, we can extract data from the page. In this example, we’ll extract the titles and URLs of all the links on a page:

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/PuerkitoBio/goquery"
)

func main() {
    url := "https://example.com"
    resp, err := http.Get(url)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    doc, err := goquery.NewDocumentFromReader(resp.Body)
    if err != nil {
        log.Fatal(err)
    }

    doc.Find("a").Each(func(i int, s *goquery.Selection) {
        href, exists := s.Attr("href")
    if exists {
        fmt.Println(s.Text(), " -> ", href)
    }
})
}

In this example, we’re using the `Each` method of the `Selection` type to iterate over all the `a` elements on the page. For each element, we check if it has an `href` attribute, and if it does, we print the link text and URL to the console.


Step 4: Saving Data

Now that we can extract data from the page, we might want to save it to a file or database for further analysis. In this example, we’ll save the link data to a CSV file:

package main

import (
    "encoding/csv"
    "log"
    "net/http"
    "os"

    "github.com/PuerkitoBio/goquery"
)

func main() {
    url := "https://example.com"
    resp, err := http.Get(url)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    doc, err := goquery.NewDocumentFromReader(resp.Body)
    if err != nil {
        log.Fatal(err)
    }

    file, err := os.Create("links.csv")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    writer := csv.NewWriter(file)
    defer writer.Flush()

    doc.Find("a").Each(func(i int, s *goquery.Selection) {
        href, exists := s.Attr("href")
        if exists {
            err := writer.Write([]string{s.Text(), href})
            if err != nil {
                log.Fatal(err)
            }
        }
    })
}

In this example, we’re using the encoding/csv package to write the link data to a CSV file. We first create a new file called links.csv, and then create a new csv.Writer object to write to the file. For each link, we write a new row to the CSV file containing the link text and URL.


Conclusion

In this tutorial, we’ve walked through the process of building a simple web scraper with Go. We’ve covered making HTTP requests, parsing HTML with goquery, extracting data from the page, and saving data to a file. With these skills, you should be able to build more advanced web scrapers to suit your specific needs.