はじめに
ウェブスクレイピングとデータ処理を行いたい場合、Pythonが選ばれることが多いですが、Goでも同様のことが可能です。本記事では、ウェブスクレイピングとCSV書き込みのコードを1つ1つ丁寧に解説します。
この記事では以下を学べます:
- GoでのHTTPリクエスト
- GoでHTMLを解析する方法
- データを整形しCSVファイルに保存する方法
Goに興味がある方に向けて、わかりやすく説明します!
実装手順
1. HTTPリクエストの送信
まず、GoでウェブページのHTMLを取得します。Goでは標準ライブラリnet/http
を使用します。
以下のコードで、指定したURLからHTMLデータを取得します。
resp, err := http.Get(url)
if err != nil {
fmt.Printf("Failed to fetch the URL: %v\n", err)
return
}
defer resp.Body.Close()
-
http.Get(url)
: 指定したURLからHTMLを取得 - エラーハンドリング: Goではエラー処理が必須なので、
err != nil
でエラーをチェック -
defer
: 関数終了時にresp.Body.Close()
を自動で実行
2. HTMLパース
Goではgoquery
を使用します。
以下のコードでHTMLを解析します。
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
fmt.Printf("Failed to parse HTML: %v\n", err)
return
}
-
goquery.NewDocumentFromReader
: HTTPレスポンスをパースして、操作可能なオブジェクトを生成します。
3. データ抽出と整形
HTMLからテキストを抽出し、不要なスペースや改行を削除します。
以下のコードで、記事内容を取得します。
// 投稿テキストの抽出
var textBuilder strings.Builder
doc.Find(".post_txt p").Each(func(i int, s *goquery.Selection) {
textBuilder.WriteString(strings.TrimSpace(s.Text()))
})
text := textBuilder.String()
// 不要なスペースや改行を削除
cleanedText := regexp.MustCompile(`\s+`).ReplaceAllString(text, "")
-
doc.Find()
: CSSセレクタでHTML要素を指定。 -
Each
: 各要素に対して処理を実行。 -
strings.Builder
: テキストを効率的に結合。 -
regexp.MustCompile
: 正規表現を使用してスペースや改行を削除。
4. 日付の解析
Goのtime.Parse
を使います。
timeElement := doc.Find(".nichi_post_title h1").Text()
dateObj, err := time.Parse("2006年1月2日", timeElement)
if err != nil {
fmt.Printf("Failed to parse date: %v\n", err)
return
}
-
time.Parse
: 日付フォーマットを指定して文字列を解析。 -
2006年1月2日
: Goのtime
パッケージでは、フォーマット指定子に特定の日付 (2006-01-02
) を使用します。
5. CSVにデータを保存
Goのencoding/csv
パッケージを使用して、データをCSVファイルに保存します。
csvFile := "岩手日日新聞_日日草.csv"
file, err := os.OpenFile(csvFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("Failed to open the CSV file: %v\n", err)
return
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
insertText := fmt.Sprintf("%d,%d,%d,%s", year, month, day, cleanedText)
err = writer.Write(strings.Split(insertText, ","))
if err != nil {
fmt.Printf("Failed to write to CSV file: %v\n", err)
}
-
os.OpenFile
: ファイルを開きます。存在しない場合は作成されます。 -
csv.NewWriter
: CSVファイルに書き込むためのライターを生成。 -
writer.Write
: 配列データを1行として書き込み。
完成したコード
ここまでの手順をすべて統合すると、以下のコードになります。
package main
import (
"encoding/csv"
"fmt"
"net/http"
"os"
"regexp"
"strings"
"time"
"github.com/PuerkitoBio/goquery"
)
func main() {
url := "https://www.iwanichi.co.jp/nichinichiso/"
// HTTPリクエスト
resp, err := http.Get(url)
if err != nil {
fmt.Printf("Failed to fetch the URL: %v\n", err)
return
}
defer resp.Body.Close()
// HTMLパース
doc, err := goquery.NewDocumentFromReader(resp.Body)
if err != nil {
fmt.Printf("Failed to parse HTML: %v\n", err)
return
}
// 投稿テキストの抽出
var textBuilder strings.Builder
doc.Find(".post_txt p").Each(func(i int, s *goquery.Selection) {
textBuilder.WriteString(strings.TrimSpace(s.Text()))
})
text := textBuilder.String()
// 不要なスペースや改行を削除
cleanedText := regexp.MustCompile(`\s+`).ReplaceAllString(text, "")
// 日付の抽出
timeElement := doc.Find(".nichi_post_title h1").Text()
dateObj, err := time.Parse("2006年1月2日", timeElement)
if err != nil {
fmt.Printf("Failed to parse date: %v\n", err)
return
}
year := dateObj.Year()
month := int(dateObj.Month())
day := dateObj.Day()
// データフォーマット
insertText := fmt.Sprintf("%d,%d,%d,%s", year, month, day, cleanedText)
// CSVに書き込む
csvFile := "岩手日日新聞_日日草.csv"
file, err := os.OpenFile(csvFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("Failed to open the CSV file: %v\n", err)
return
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
// データをCSVファイルに書き込む
err = writer.Write(strings.Split(insertText, ","))
if err != nil {
fmt.Printf("Failed to write to CSV file: %v\n", err)
return
}
fmt.Println("Data has been written to the CSV file.")
}
まとめ
Goを使うことで、Pythonとは異なるエラーハンドリングやパッケージの特性を学びながら、ウェブスクレイピングからCSV書き込みまで実装できました。Goの高速性や並行処理の特性を活かせば、さらに強力なアプリケーションが作れます。