go语言goquery下载图片实例「建议收藏」

crawl.gopackagemainimport(“fmt””strings””strconv””net/http””net/url””io/ioutil””os””log””runtime””flag””github.com/PuerkitoBio/goquery”)constH

大家好,又见面了,我是你们的朋友全栈君。

crawl.go

package main

import (
    "fmt"
    "strings"
    "strconv"
    "net/http"
    "net/url"
    "io/ioutil"
    "os"
    "log"
    "runtime"
    "flag"
    "github.com/PuerkitoBio/goquery"
)

const HOST     string  = "http://www.aitaotu.com"
const DOC_URL  string  = "http://www.aitaotu.com/search/%E9%BB%91%E4%B8%9D%E7%BE%8E%E8%85%BF/"

var (
    ch1 chan string
    ch2 chan string
    ch3 chan int
    img_dir string
)

//初始化变量
func init(){
    ch1 = make(chan string, 20)
    ch2 = make(chan string, 1000)
    ch3 = make(chan int, 1000)

    logfile, err := os.OpenFile("/var/log/crawl.log", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0777)
    if err != nil {
        os.Exit(1)
    }

    log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
    log.SetOutput(logfile)
}

func main(){
    runtime.GOMAXPROCS(runtime.NumCPU())

    img_path := flag.String("img_path", "/data/pic/", "where is image to save")
    flag.Parse()

    img_dir =  *img_path
    //检查目录是否存在
    file, err := os.Stat(img_dir)
    if err != nil || !file.IsDir() {
        dir_err := os.Mkdir(img_dir, os.ModePerm)
        if dir_err != nil {
            fmt.Println("create dir failed")
            os.Exit(1)
        }
    }

    go getListUrl()
    go parseListUrl()
    go downloadImage()

    count := 0
    for num := range ch3 {
        count = count + num
        fmt.Println("count:", count)
    }
    fmt.Println("crawl end")
}

func getListUrl(){
    doc, err := goquery.NewDocument(DOC_URL)
    if err  != nil {
        fmt.Println("err:", err)
        os.Exit(1)
    }

    doc.Find(".picbox").Each(func(i int, s *goquery.Selection){
        text, _    := s.Find("a").Attr("href")
        list_url   := HOST + text
        ch1 <- list_url
    })
}

//根据模块和总数据列出所有的图片页面
func parseListUrl(){
    suffix := ".html"
    for list_url := range ch1 {
        page_count := getPageCount(list_url)
        prefix     := strings.TrimRight(list_url, suffix)
        for i := 1; i <= page_count; i++ {
            img_list_url := prefix + "_" + strconv.Itoa(i) + suffix
            ch2 <- img_list_url
        }
    }
}

//获取总页数
func getPageCount(list_url string) (count int){
    count = 0
    doc, _ := goquery.NewDocument(list_url)
    doc.Find(".pages ul li").Each(func(i int, s *goquery.Selection){
        text := s.Find("a").Text()
        if text == "末页" {
            last_page_url, _ := s.Find("a").Attr("href")
            prefix := strings.Trim(last_page_url, ".html")
            index  := strings.Index(prefix, "_")
            last_page_num := prefix[index+1:]
            page_num, _   := strconv.Atoi(last_page_num)
            count = page_num
        }
    })
    return count
}

//解析图片url
func downloadImage(){
    for img_list_url := range ch2 {
        doc, _ := goquery.NewDocument(img_list_url)
        doc.Find("#big-pic p a").Each(func(i int, s *goquery.Selection){
            img_url, _ := s.Find("img").Attr("src")
            go func(){
                saveImages(img_url)
            }()
        })
    }
}

//下载图片
func saveImages(img_url string){
    log.Println(img_url)
    u, err := url.Parse(img_url)
    if err != nil {
        log.Println("parse url failed:", img_url, err)
        return 
    }

    //去掉最左边的'/'
    tmp := strings.TrimLeft(u.Path, "/")
    filename := img_dir + strings.ToLower(strings.Replace(tmp, "/", "-", -1))

    exists := checkExists(filename)
    if exists {
        return 
    }

    response, err := http.Get(img_url)
    if err != nil {
        log.Println("get img_url failed:", err)
        return 
    }

    defer response.Body.Close()

    data, err := ioutil.ReadAll(response.Body)
    if err != nil {
        log.Println("read data failed:", img_url, err)
        return 
    }

    image, err := os.Create(filename)
    if err != nil {
        log.Println("create file failed:", filename, err)
        return 
    }

    ch3 <- 1
    defer image.Close()
    image.Write(data)
}

func checkExists(filename string) bool {
    _, err := os.Stat(filename)
    return err == nil 
}

cd $GOPATH/bin
编译:go build crawl
运行:./crawl –img_path=/data/pic

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/127443.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • webstorm 2021激活码_通用破解码

    webstorm 2021激活码_通用破解码,https://javaforall.cn/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

  • 哈佛大学公开课-幸福课-个人笔记

    哈佛大学公开课-幸福课-个人笔记b站视频链接十一讲:养成良好习惯舒适区拉升区 慢慢的做出改变,一步步来。暴力区人的一生一般都是在舒适区度过的,你要让自己适度的走出然后走进拉升区。自律是有一定量的是有限的,用了可能就没有了,需要时间来恢复。我们不可能拥有很多自律,但同时自律也不是那么重要。老师比喻:1.AB—-榨菜与巧克力,A是巧克力-榨菜,B榨菜-巧克力 最后是A先吃了榨菜,因为A在克制自己不…

  • Linux运维必备技能:如何在 Vim 中删除多行?

    Linux运维必备技能:如何在 Vim 中删除多行?我们都会犯错,犯错是人之常情,改进它也很重要。如果你在Vim中出错,你可以dw在普通模式下使用删除一个单词。您键入dd它会删除当前行。如果要在Vim中删除多行,可以使用相同的ddVim命令,将行数添加到该命令中。因此,10dd将从光标底部删除10行(包括光标所在的行)。让我们详细了解如何在以效率着称的编辑器中删除一行或多行。删除单行以下是在Vim中删除单行文本的步骤:按Escape(Esc)键进入Normal模式确保光标位于要删除的行上。快速按下dd这

  • el-upload多文件上传_vue 界面

    el-upload多文件上传_vue 界面vue使用element-ui的el-upload实现上传文件到后台的功能1.添加el-upload控件<el-upload:action=”action”:file-list=”modeList”:http-request=”modeUpload”><el-buttonsize=”small”type=”primary…

  • tf2013_office2010绿色激活成功教程版

    tf2013_office2010绿色激活成功教程版
    TFS2010的安装与VSS升级到TFSVS2010正式发布有一个星期了,大家应该都尝鲜过VS2010下载了吧,当然还有TFS2010。TFS2010作为微软极力推荐的团队开发平台,可谓倾尽全力,当然也没有让我们失望。旧版本的TFS安装那一步步繁琐的配置过程和前提条件,还强迫我们去学习配置安装sharepointservice,这点真是无法容忍的,还有TFS2010吸取了以前的教训,我们终于可以尽情的NEXT了。TFS2010的安装之所以说不需要我们过分关注TFS2010的安装过程,不是不

  • robotium 代码

    robotium 代码Robotium之用例分析    http://blog.csdn.net/wirelessqa/article/details/7847466robotium各种方法:http://wenku.baidu.com/link?url=XoPtudf4lgpyzhbLPGJ-6ie8VM2hcCb4Gl6rHozgOrgxWfK52nj-kHzhFbZDkoc_FASztmmPG

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号