植物のミカタの任意のページから複数の画像を取得してみる。
func main() { url := "https://saitodev.co/article/%E6%AF%94%E5%8F%A1%E5%B1%B1%E3%81%AE%E5%B1%B1%E9%A0%82%E4%BB%98%E8%BF%91%E3%81%AB%E3%81%82%E3%81%A3%E3%81%9F%E5%A4%A7%E3%81%8D%E3%81%AA%E5%B2%A9" response, err := http.Get(url) if err != nil { log.Fatal(err) } defer response.Body.Close() imagePaths := make([]string, 0) r := regexp.MustCompile("<img.*src=\"(.*?)\".*?>") reader := bufio.NewReader(response.Body) for { line, err := reader.ReadString('\n') if err == io.EOF { break } else if err != nil { log.Fatal(err) } res := r.FindStringSubmatch(line) if len(res) > 1 && strings.Index(res[1], "/site/files") >= 0 { imagePaths = append(imagePaths, res[1]) } } fmt.Println(imagePaths) }
まず、トップページのアドレスをコピーしurl変数に代入する。response, err := http.Get(url)でデータを取得する。imagePaths := make([]string, 0)で0個の値をもつimagePathsスライスを作成する。r := regexp.MustCompile("<img.*src=\"(.*?)\".*?>")の正規表現でsrc=の属性の値を探す。reader := bufio.NewReader(response.Body)でresponse.Bodyを全部読み込むという意味になる。line, err := reader.ReadString('\n')で改行コードを発見するまで読みこんだものがlineになる。
if err == io.EOF でエラーにEoFが返ってきたら、繰り返しを終わる(break)。res := r.FindStringSubmatch(line)でlineの中で、rの条件のものがあるかないかを検索する。
if len(res) > 1で検索したものがあれば、かつ(&&)、strings.Index(res[1], "/site/files") >= 0でres[1]に/site/filesの文字列があれば、append(imagePaths, res[1])でimagePathsにres[1]を追加するという意味になる。strings.Indexは、文字列操作の機能をまとめたパッケージの関数で、指定した文字列が含まれれば、返し点を返す、含まれなければ-1を返す。
そうすると、画像のパスがとれる。ここで、fmt.Println(imagePaths)すると下記のように表示される。
※ioutil.ReadAllと bufio.NewReaderの違いは、区切って読みこむときは、bufio.NewReader、全部読むこむ時は、ioutil.ReadAllを使う。パスとは、データがある場所を意味する。
次にファイルを作成し、画像のパスを書き込む作業を行う。
length := len(imagePaths) if length > 0 { for i := 0; i < length; i++ { imagePath := imagePaths[i] n := strings.LastIndex(imagePath, "/") p := imagePath[n+1:] url = "https://saitodev.co" + imagePath resp, err := http.Get(url) if err == nil { file, err := os.Create(p) if err != nil { log.Fatal(err) } body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Fatal(err) } file, err := os.Create(p) if err != nil { log.Fatal(err) } file.Write(body) file.Close() } resp.Body.Close() } }
length := len(imagePaths)で、imagePathsのスライスの個数をlengthとする。今、lengthの中に入っているスライスを一つづつ読み込む作業が必要になる。まず、if length > 0で画像のパスがあるならば、for i := 0; i < length; i++ {でlengthの中に入っている数だけ、繰り返す。n := strings.LastIndex(imagePath, "/")で、imagePathの中で最後に/がある部分が最初の文字から何番目にあるかを示すnを作成する。n+1番目からが、画像の名前になるので、p := imagePath[n+1:]で画像のファイル名を表すpを作成する。
url = "https://saitodev.co" + imagePathで画像のurlが作成する。resp, err := http.Get(url)で画像のデータをrespで取得する。ちなみにrespには、下記のようなデータが入っている。
body, err := ioutil.ReadAll(resp.Body)で取得したデータをバイト型の値に変えたbodyを作成する。file, err := os.Create(p)でpという名前のファイルを作成する。file.Write(body)でファイルにbodyを書き込む。すると、下記のように画像ファイルが複数作成される。
※Getでデータを取得する際、if err == nilで、errがなければ、処理を続けるにしている。