用go+写一个图片下载神器,百来行代码的事儿

简介: 使用go+语言写一个图片下载神器!

前言

最近遭遇了图片荒(每次写文章都要附上一些图片心里才踏实)。之前去shopify上一张一张下载了一些图片,但是很快就用完了。刚好最近和go+社区小伙伴一起学习go+,就想着用go+写个批量下载图片的工具,晚上回来找了一下资料没想到百来行代码就写好了。

最后成果:

请添加图片描述

工具说明:该工具用于从https://pixabay.com/zh/网站免费下载无版权高清图片(通过网站注册获取api key,通过填写想要下载的图片特征、图片类型即可将图片保存到指定的路径)。

该工具最初的构想

刚好早上在网上找哪里有免费无版权的图片时找到https://pixabay.com/zh/可以提供大量高清无版权图片,并有api尽心调用下载。

构想:用go+构建一个web应用,通过web图形化界面配置将图片下载到本地。

最终:用go+与html实现

先说一下https://pixabay.com/zh/这个网站提供的免费图片的调用方式,使用get调用如下请求,请求参数包括:key(网站注册之后获取的api key),q(需要下载的图片特征),image_type(图片类型)。而返回参数也如下所示。更具体的可注册上述网站之后访问https://pixabay.com/api/docs/查看。

请添加图片描述

定义返回参数数据结构

所以说,首先第一步我要做的就是用在go+中定义一个数据结构,用来表示返回参数:

如下所示:

type Hit struct {
  ID              int    `json:"id"`
  PageURL         string `json:"pageURL"`
  Type            string `json:"type"`
  Tags            string `json:"tags"`
  PreviewURL      string `json:"previewURL"`
  PreviewWidth    int    `json:"previewWidth"`
  PreviewHeight   int    `json:"previewHeight"`
  WebformatURL    string `json:"webformatURL"`
  WebformatWidth  int    `json:"webformatWidth"`
  WebformatHeight int    `json:"webformatHeight"`
  LargeImageURL   string `json:"largeImageURL"`
  FullHDURL       string `json:"fullHDURL"`
  ImageURL        string `json:"imageURL"`
  ImageWidth      int    `json:"imageWidth"`
  ImageHeight     int    `json:"imageHeight"`
  ImageSize       int    `json:"imageSize"`
  Views           int    `json:"views"`
  Downloads       int    `json:"downloads"`
  Likes           int    `json:"likes"`
  Comments        int    `json:"comments"`
  UserID          int    `json:"user_id"`
  User            string `json:"user"`
  UserImageURL    string `json:"userImageURL"`
}

type Result struct {
  Total     int   `json:"total"`
  TotalHits int   `json:"totalHits"`
  Hits      []Hit `json:"hits"`
}

通过动态请求获取图片下载地址

接着就可以调用上述接口对图片进行下载啦,但是请注意,我们要做的是图形化界面配置要,所以上述说到的请求参数当然不可以在代码中写死,而是通过downloadImages.gtpl前端界面表单请求的方式来获取

func DownloadImages(w http.ResponseWriter, r *http.Request) {

  if r.Method == "GET" {
    t, _ := template.ParseFiles("downloadImages.gtpl")
    log.Println(t.Execute(w, nil))
  } else {
    err := r.ParseForm()
    if err != nil {
      log.Fatal("ParseForm: ", err)
    }

    println("key:", r.Form["key"])
    println("q:", r.Form["q"])
    println("image_type:", r.Form["image_type"])
    println("save_path:", r.Form["save_path"])

    _, keyOk := r.Form["key"]
    _, qOk := r.Form["q"]
    _, imageTypeOk := r.Form["image_type"]
    _, savePathOk := r.Form["save_path"]
    if !keyOk || !qOk || !imageTypeOk || !savePathOk {
      fmt.Fprintf(w, "请输入正确的参数")
      return
    }

    resp, err := http.Get("https://pixabay.com/api/?key=" + r.Form["key"][0] + "&q=" + r.Form["q"][0] + "&image_type=" + r.Form["image_type"][0])

    if err != nil {
      panic(err)
    }

    var res Result

    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)

    json.Unmarshal(body, &res)
    for i, hit := range res.Hits {
      println(i, hit.LargeImageURL)

      var iURLSplit = strings.Split(hit.LargeImageURL, "/")

      imageResp, err := http.Get(hit.LargeImageURL)

      defer resp.Body.Close()

      CreatePathIfNotExists(r.Form["save_path"][0])

      if err != nil {
        panic(err)
      }

      out, err := os.Create(r.Form["save_path"][0] + iURLSplit[len(iURLSplit)-1])
      if err != nil {
        panic(err)
      }
      defer out.Close()
      _, err = io.Copy(out, imageResp.Body)
      if err != nil {
        panic(err)
      }
    }
    fmt.Fprintf(w, "图片下载完成,下载路径为:"+r.Form["save_path"][0])
  }
}

保存路径

当然还有一点,我们可以动态配置我们想要下载的图片,那当然也要能够动态配置保存的路径啦,所以我们还开放了参数,用于图片保存的路径。

下述代码表示如果配置的路径不存在,则新建文件夹

func CreatePathIfNotExists(path string) {
  _, err := os.Stat(path)
  if os.IsNotExist(err) {
    os.Mkdir(path, os.ModePerm)
  }
}

构建http服务

基于上述逻辑,我们就可以启用一个http服务

http.HandleFunc("/", DownloadImages)     // 设置访问的路由
err := http.ListenAndServe(":8888", nil) // 设置监听的端口

if err != nil {
  log.Fatal("ListenAndServe: ", err)
}

完整代码

最后附上完整的gop代码和html代码:

main.gop

import (
  "encoding/json"
  "fmt"
  "html/template"
  "io"
  "io/ioutil"
  "log"
  "net/http"
  "os"
  "strings"
)

type Hit struct {
  ID              int    `json:"id"`
  PageURL         string `json:"pageURL"`
  Type            string `json:"type"`
  Tags            string `json:"tags"`
  PreviewURL      string `json:"previewURL"`
  PreviewWidth    int    `json:"previewWidth"`
  PreviewHeight   int    `json:"previewHeight"`
  WebformatURL    string `json:"webformatURL"`
  WebformatWidth  int    `json:"webformatWidth"`
  WebformatHeight int    `json:"webformatHeight"`
  LargeImageURL   string `json:"largeImageURL"`
  FullHDURL       string `json:"fullHDURL"`
  ImageURL        string `json:"imageURL"`
  ImageWidth      int    `json:"imageWidth"`
  ImageHeight     int    `json:"imageHeight"`
  ImageSize       int    `json:"imageSize"`
  Views           int    `json:"views"`
  Downloads       int    `json:"downloads"`
  Likes           int    `json:"likes"`
  Comments        int    `json:"comments"`
  UserID          int    `json:"user_id"`
  User            string `json:"user"`
  UserImageURL    string `json:"userImageURL"`
}

type Result struct {
  Total     int   `json:"total"`
  TotalHits int   `json:"totalHits"`
  Hits      []Hit `json:"hits"`
}

func CreatePathIfNotExists(path string) {
  _, err := os.Stat(path)
  if os.IsNotExist(err) {
    os.Mkdir(path, os.ModePerm)
  }
}

func DownloadImages(w http.ResponseWriter, r *http.Request) {

  if r.Method == "GET" {
    t, _ := template.ParseFiles("downloadImages.gtpl")
    log.Println(t.Execute(w, nil))
  } else {
    err := r.ParseForm()
    if err != nil {
      log.Fatal("ParseForm: ", err)
    }

    println("key:", r.Form["key"])
    println("q:", r.Form["q"])
    println("image_type:", r.Form["image_type"])
    println("save_path:", r.Form["save_path"])

    _, keyOk := r.Form["key"]
    _, qOk := r.Form["q"]
    _, imageTypeOk := r.Form["image_type"]
    _, savePathOk := r.Form["save_path"]
    if !keyOk || !qOk || !imageTypeOk || !savePathOk {
      fmt.Fprintf(w, "请输入正确的参数")
      return
    }

    resp, err := http.Get("https://pixabay.com/api/?key=" + r.Form["key"][0] + "&q=" + r.Form["q"][0] + "&image_type=" + r.Form["image_type"][0])

    if err != nil {
      panic(err)
    }

    var res Result

    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)

    json.Unmarshal(body, &res)
    for i, hit := range res.Hits {
      println(i, hit.LargeImageURL)

      var iURLSplit = strings.Split(hit.LargeImageURL, "/")

      imageResp, err := http.Get(hit.LargeImageURL)

      defer resp.Body.Close()

      CreatePathIfNotExists(r.Form["save_path"][0])

      if err != nil {
        panic(err)
      }

      out, err := os.Create(r.Form["save_path"][0] + iURLSplit[len(iURLSplit)-1])
      if err != nil {
        panic(err)
      }
      defer out.Close()
      _, err = io.Copy(out, imageResp.Body)
      if err != nil {
        panic(err)
      }
    }
    fmt.Fprintf(w, "图片下载完成,下载路径为:"+r.Form["save_path"][0])
  }
}

http.HandleFunc("/", DownloadImages)     // 设置访问的路由
err := http.ListenAndServe(":8888", nil) // 设置监听的端口

if err != nil {
  log.Fatal("ListenAndServe: ", err)
}

downloadImages.gtpl

<html>
<head>
    <title>Pixabay图片下载器</title>
    <meta charset="UTF-8">
    <style>
        .a{
            width: 300px;
            height: 30px;
            margin-top: 20px;
        }
        #table{
            width: 500px;
        }
        #des{
            text-align: center;
        }
        #sub-title{
            text-align: center;
            font-size: 20px;
        }
    </style>
</head>
<body>


        <br/>
        <br/>    

some_text

        <br/>
        <br/>    
        <br/>    
        <h1>Pixabay图片下载工具</h1>            
<div id = "sub-title">
    还在为找不到图片而发愁吗,本工具帮助你免费批量从Pixabay下载高清图片。
        <br/>
        <br/>
</div>
<HR align=center width=300 color=#987cb9 SIZE=1>

<div id = "table">
    <form action="/" method="post">
        <br/>
        Pixabay申请的key
        <br/>
        <input type="text" class="a" name="key">
        <br/>
        <br/>
        搜索图片关键词
        <br/>
        <input type="text" class="a" name="q">
        <br/>
        <br/>
        图片类型
        <br/>
        <input type="text" class="a" name="image_type">
        <br/>
        <br/>
        本机保存路径
        <br/>
        <input type="text" class="a" name="save_path">
        <br/>
        <br/>
        <input type="submit" class="a" value="下载">
    </form>
</div>
<br/>
<HR align=center width=300 color=#987cb9 SIZE=1>

<div id = "des">
</br>
</br>
用法:
</br>
</br>    
要使用本工具,请先到Pixabay网站注册账号,注册地址:https://pixabay.com/zh/
</br>  
注册完之后即可在页面:https://pixabay.com/api/docs/ 查看给你分配的 API key
</br>
</br>    
申请到API key之后,将其填入上述"Pixabay申请的key"方框中。
</br>
</br>    
"搜索图片关键词"中输入您想要找的图片关键词,关键词与关键词之间用+连接,例如:yellow+flower
</br>
</br>
"图片类型"中输入您想要找的图片的类型,可选类型为:all, photo, illustration, vector
</br>
</br>    
最后输入下载的图片的本机保存路径,该工具会判断您输入的文件夹目录是否存在,如果不存在则会自动创建,例如,您可以输入windows系统中的合法地址 c:\\User\\xiaozhch5\\images\\
</div>
</body> </html>

一步一步看成果

运行代码:

gop run .\main.gop

请添加图片描述

浏览器打开http://localhost:8888,可以看到

请添加图片描述

将从https://pixabay.com/zh/注册获取到的API key、你想要下载的图片的关键词(注意是英文类型)、图片类型(可选类型为:all, photo, illustration, vector)以及图片的保存路径填入上述表单中

请添加图片描述

点击下载即可在vscode终端看到相关下载信息:

请添加图片描述

再查看刚刚我们输入的下载路径

请添加图片描述

备注:默认情况下最多会下载20张图片,如果你输入的关键词匹配的图片小于20张,那么会下载所找到的所有图片(小于20张),上述关键词(yello+flowers)找到的为5张,因为黄色拼错了哈哈哈,本来是yellow,拼成了yello了。

打成exe文件

最后,可以把这个工程打包成一个exe项目,这样子我每次抓取图片就不需要打开vscode就可以啦。

执行:

gop build .

在当前目录下生成go+.exe文件,双击可直接运行。

然后同样在浏览器中输入http://localhost:8888可同样进入如下页面

请添加图片描述

下载体验

有兴趣的同学可以直接下载我构建好的exe文件,文件链接为:

https://github.com/xiaozhch5/gop-image-capture/releases/download/1.0-release/1.0-release.zip

或者访问我的完整代码:

https://github.com/xiaozhch5/gop-image-capture

相关文章
|
机器学习/深度学习 NoSQL Go
如何进行Go程序的打包发布
如何进行Go程序的打包发布
194 7
|
6月前
|
存储 IDE 编译器
编程笔记 GOLANG基础 005 第一个程序:hello world 使用vscode
编程笔记 GOLANG基础 005 第一个程序:hello world 使用vscode
117 0
|
6月前
|
Kubernetes Go 数据库
分享48个Go源码,总有一款适合您
分享48个Go源码,总有一款适合您
237 0
|
6月前
|
Go
Go命令行解析神器入门 - 10分钟上手flag包
Go命令行解析神器入门 - 10分钟上手flag包
184 0
|
Go iOS开发 MacOS
Go学习笔记-代码调试工具 dlv
Go学习笔记-代码调试工具 dlv
1022 1
Go学习笔记-代码调试工具 dlv
|
数据采集 XML JSON
Go编程:使用 Colly 库下载Reddit网站的图像
Reddit是一个社交新闻网站,用户可以发布各种主题的内容,包括图片。本文将介绍如何使用Go语言和Colly库编写一个简单的爬虫程序,从Reddit网站上下载指定主题的图片,并保存到本地文件夹中。为了避免被目标网站反爬,我们还将使用爬虫代理服务,通过动态切换代理IP来提高爬取效率和稳定性。
110 0
Go编程:使用 Colly 库下载Reddit网站的图像
|
11月前
|
存储 Go 图形学
如何使用 Go 语言来实现 GIF 动画?
如何使用 Go 语言来实现 GIF 动画?
130 0
|
监控 测试技术 Go
用 Go 从零实现日志包 - 第零篇 序言
设计一个日志包,需要考虑的基础功能有日志级别设置、标准输出和文件、输出格式配置、日志的时间戳、文件与打印行号、正文。高级功能有按级别分类输出、支持结构化日志、支持日志轮转。
136 0
|
编译器 Go 开发者
Go 开发常见问题和解决方法 | 学习笔记
快速学习 Go 开发常见问题和解决方法
Go 开发常见问题和解决方法 | 学习笔记
|
JSON Go 数据格式
Go 开发常用操作技巧--map
map 是一种特殊的数据类型,它是一种元素对的无序集合,元素对为 键(key)值(value) 形式。我们可以通过 key 来快速找到与之对应的 value。
141 0
Go 开发常用操作技巧--map