前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >golang 多线程爬虫

golang 多线程爬虫

作者头像
地球流浪猫
发布2018-08-02 15:36:05
9040
发布2018-08-02 15:36:05
举报
文章被收录于专栏:流浪猫的golang流浪猫的golang
代码语言:javascript
复制
这是一个golang爬虫demo 爬去一个美女图片网站的首页所有图片
采用golang 多线程的方式爬取图片 将爬到的图片保存到本地
代码中有用到goquery 网页数据解析框架 chan 控制goroutine 进行下载

http://www.umei.cc/
一个妹子图片网站  请求的 header 必须带着 Referer 否则404 (比较简单的一种反爬虫策略)
用wireshark 抓取浏览器请求图片的数据就可以得到 Referer

//代码不复杂,适合新手学习
代码语言:javascript
复制
var url = "http://www.umei.cc/"

var c chan int

func main() {
	runtime.GOMAXPROCS(4)
	spider()
	//testDownLoad()
}

//url->Document->所有图片url->开启多线程进行下载->保存到本地
func spider() {
	doc, err := goquery.NewDocument(url)
	if err != nil {
		log.Fatal(err)
	}
	urls := ImageRule(doc, match);
	fmt.Println("共解析到", len(urls), "图片地址")
	c = make(chan int)
	for _, s := range urls {
		fmt.Println(s)
		go downloadImage(s)
	}
	//可以等待一会儿,留时间给子goroutine 执行
	//但是这种方式不怎么靠谱 //直接采用chan 的方式
	//time.Sleep(1e9*10)
	for i := 0; i < len(urls); i++ {
		<-c
	}
}

// 单独测试了以下 下载方法
func testDownLoad() {
	var url_img = "http://i1.umei.cc/uploads/tu/201608/164/hanguomeinv.jpg";
	//var  url_img  = "http://t1.mmonly.cc/uploads/tu/sm/201601/19/005.jpg";
	downloadImage(url_img)
}

func match(image string) {
	fmt.Println(image);
}

func getData(url string) (eader io.Reader, err error) {
	req := buildRequest(url)
	resp, err := http.DefaultClient.Do(req)
	defer resp.Body.Close()
	return io.Reader(resp.Body), err
}

// 得到一个网页中所有 ImageUrl
func parseImageUrl(reader io.Reader) (res []string, err error) {

	doc, err := goquery.NewDocumentFromReader(reader)
	if err != nil {
		return nil, err
	}
	fmt.Println(doc.Url)
	ImageRule(doc, func(image string) {
		res = append(res, image)
	})
	return res, nil
}

func ImageRule(doc *goquery.Document, f func(image string)) (urls []string) {
	str := make([]string, 0)
	//直接找以img 开头的标签 过滤掉不符合规则的url 即可
	doc.Find("img").Each(func(i int, s *goquery.Selection) {
		url, result := s.Attr("src")
		if result {
			if strings.HasSuffix(url, ".jpg") {
				str = append(str, url)
			}
		}
	})
	return str
}

//根据url 创建http 请求的 request
//网站有反爬虫策略 wireshark 不解释
func buildRequest(url string) *http.Request {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		panic(err)
	}
	//	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36")
	//	req.Header.Set("Cookie", "Hm_lvt_c605a31292b623d214d012ec2a737685=1516111586; Hm_lpvt_c605a31292b623d214d012ec2a737685=1516111613")
	//req.Header.Set("If-None-Match", "5a309bab-26057")
	req.Header.Set("Referer", "http://www.umei.cc/")
	//req.Header.Set("If-Modified-Since", "Wed, 13 Dec 2017 03:16:59 GMT")
	return req
}
// 下载图片
func downloadImage(url string) {
	fileName := getNameFromUrl(url)
	req := buildRequest(url)
	http.DefaultClient.Timeout = 10 * time.Second;
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		fmt.Println("failed download ")
		panic(err)
	}
	if resp.StatusCode != http.StatusOK {
		fmt.Println("failed download " + url)
		return
	}
	defer func() {
		resp.Body.Close()
		if r := recover(); r != nil {
			fmt.Println(r)
		}
		c <- 0
	}()

	fmt.Println("begin download " + fileName)
	os.MkdirAll("./images/", 0777)
	localFile, _ := os.OpenFile("./images/"+fileName, os.O_CREATE|os.O_RDWR, 0777)

	if _, err := io.Copy(localFile, resp.Body); err != nil {
		panic("failed save " + fileName)
	}

	fmt.Println("success download " + fileName)
}
// 判读文件夹是否存在
func isExist(dir string) bool {
	_, err := os.Stat(dir)
	if err == nil {
		return true
	}
	return os.IsExist(err)
}

// 通过url 得到图片名字
func getNameFromUrl(url string) string {
	arr := strings.Split(url, "/")
	return arr[len(arr)-1]
}
代码语言:javascript
复制
项目地址:点击打开链接
代码语言:javascript
复制
goquery 传送门 https://godoc.org/github.com/PuerkitoBio/goquery
代码语言:javascript
复制
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018年01月17日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档