はじめに
WebカメラのサイトのサムネイルのURLを格納しているテーブルを参照し、それぞれの画像をダウンロードして保存するプログラムを作成した。テーブルの参照、更新はgormを使用したが、思ったより使うのがしんどかった。
環境
- go 1.17 → go 1.20
- Windows 10
- PostgreSQL 14
golangのバージョンアップ
プログラムを作る以前にgormのインポートからうまくいかず。
gorm.io/driver/postgresをインポートしようとして、go getしようとしたが、エラー。1.17から1.20にアップデートして解消した。
go get gorm.io/driver/postgres
C:\Users\xxxx\go\pkg\mod\github.com\jackc\pgx\v5@v5.3.1\pgtype\builtin_wrappers.go:9:2: package net/netip is not in GOROOT
(C:\Program Files\Go\src\net\netip)
問題なく作業できるかと思ったら、VS Codeでデバッガ起動したときにエラーが出力されて動かず。
Failed to launch:Version of Delve is too old for Go version 1.20.5(maximum supported version 1.18 suppress
this error with --check-go-version=false)
なので、delveをアップデートした。
go get -u github.com/go-delve/delve/cmd/dlv
プログラムの作成
使用したテーブル名は、thumbnail_linkという名前で、以下のような形式。今思えば、更新するなら、IDくらいつけとけばよかったように思う。
列名 | データ型 |
---|---|
link | varchar(100) |
download_flag | integer |
テーブル自体は以前作ったもので、もとのデータは、Webカメラのサイトからとってきたもの。
linkのデータは、次のようなthumbnailのURLが設定されている。
https://images-webcams.windy.com/92/1177842892/current/thumbnail/1177842892.jpg
donload_flagは、未ダウンロード:0 ダウンロード済:1で、ダウンロードした後1に更新する。
テーブルに合わせてモデルを定義した。一文字目を大文字にしないと検索しても値が入ってこない。
type thumbnail_link struct {
Link string
Download_flag int
}
モデルをthumbnail_linkに定義した場合、生成されるSQLのテーブル名は、デフォルトでは複数形のthumbnail_linksになってしまうため、テーブル名をカスタマイズする関数を定義した。TableName()Gorm ライブラリで使用されるメソッド。
func (o thumbnail_link) TableName() string {
return "thumbnail_link"
}
後から知ったが、db.Table("<テーブル名>")でもテーブルを指定することができるとのこと。
download_flagが0のもののみ取得して、ループしてダウンロードを実行した。
var link []thumbnail_link
db.Where("download_flag = ?", "0").Find(&link)
for _, v := range link {
downloadImage(v, db)
}
画像は、http.Getで取得し、取得できたものに対してdownload_flagに1を設定した。
func downloadImage(v thumbnail_link, db *gorm.DB) {
fmt.Println(v.Link)
resp, err := http.Get(v.Link)
if err != nil {
panic(err)
}
defer resp.Body.Close()
<保存処理>
db.Model(&v).Where("link = ?", v.Link).Update("download_flag", 1)
【コード全文】
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type thumbnail_link struct {
Link string
Download_flag int
}
func (o thumbnail_link) TableName() string {
return "thumbnail_link"
}
func downloadImage(v thumbnail_link, db *gorm.DB) {
fmt.Println(v.Link)
resp, err := http.Get(v.Link)
if err != nil {
panic(err)
}
defer resp.Body.Close()
lastSlashIndex := strings.LastIndex(v.Link, "/")
if lastSlashIndex == -1 {
fmt.Println("スラッシュが見つからなかった")
return
}
// スラッシュの後ろの文字列を取得
fileName := v.Link[lastSlashIndex+1:]
savefile, _ := os.Create("c:/temp/" + fileName)
defer savefile.Close()
image, _ := ioutil.ReadAll(resp.Body)
data := []byte(image)
savefile.Write(data) // 画像書き込み
db.Model(&v).Where("link = ?", v.Link).Update("download_flag", 1)
}
func main() {
dsn := "host=localhost user=user1 password=pass dbname=postgres port=5432 sslmode=disable TimeZone=Asia/Tokyo"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
var link []thumbnail_link
db.Where("download_flag = ?", "0").Find(&link)
for _, v := range link {
downloadImage(v, db)
}
}