植物のミカタの任意のページから複数の画像を取得してみる。

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がなければ、処理を続けるにしている。