Golang 协程 采集必应背景图 正则匹配

Go爬取bing首页背景图

事情是这样的:突然坐在工位上打开bing首页,发现该背景,如下

在这里插入图片描述

当时直呼卧槽,于是萌生了看看bing之前每天都是些什么神仙背景···

查看背景图片的URL

首先打开控制台查看下URL,赶紧打开保存图片,顺便记下URL,便于后续采集。
在这里插入图片描述

Bing图库

此时我们突然发现在bing上只有当日的背景图,直接去找到bing图库,发现图片对应的域名为

http://bing.plmeizi.com/view/x

其中x为大于0的自然数;
这时随便取一个数用postman发送请求
在这里插入图片描述
发现了我们需要的图片URL;也就是说只要把这些域名匹配出来就能开始采集了!
但是此时随便取一个URL访问
在这里插入图片描述
发现被墙了,ACL denied。

转换思路

由于被墙了,导致不能采集图库里的图片,但结合之前首页发现的图片资源地址,不难发现他们的文件名应该是一样的。
于是我们可以把图库的图片文件名用正则匹配出来,再拼接上bing的域名就是一个完整的背景图URL了。

代码实现

完整代码地址:

https://gitee.com/viavia9527/go-spark

思路主要分为采集+存储两部分;

采集

看了下目前大概差不多2000个页面,每页有50个图片的URL,防止遗漏要考虑重复的URL问题。
这里采集方面的做法是把<img ‘xx’>标签内容用正则表达式匹配出来存入文件;

<img data-original="//bimgs.plmeizi.com/images/bing/2018/WhiteSwan_ZH-CN12970644283_1920x1080.jpg" src=//bimgs.plmeizi.com/images/bing/2018/WhiteSwan_ZH-CN12970644283_1920x1080.jpg-thumb alt="【2016-08-09】 【今日七夕】内蒙古阿尔山国家森林公园的一对天鹅 (© Blue Jean Images/Getty Images)" >

然后关于不同链接下图片的重复写入问题,考虑以时间为key维护一个(time)->value的map。

ret:=regexp.MustCompile("<img data-original=\"//bimgs.plmeizi.com/images/bing(\\S*?)[^>]*>.*?|<.*? />")
all:=ret.FindAllStringSubmatch(result,-1)
reg:=regexp.MustCompile("(.?)(\\d{4}-\\d{2}-\\d{2})(.?)")

其中ret匹配img标签,reg匹配时间yyyy-mm-dd。

开个协程

一个个等太慢了,这里我们开个协程。

 	data:=make(chan string)
	done:=make(chan bool)
	var maps = make(map[string]string)
	wg:=sync.WaitGroup{}

首先定义变量,data表示数据,done表示状态,maps维护唯一时间对应图片URL的map,wg则是等待组,用来维护协程池,保证任务完成数量。

for id:=0;id<=2000;id++{
		wg.Add(1)
		url:=urlbase+strconv.Itoa(id)
		go logic.Spark(url,data,&wg,maps)
	}

等待组加1,在协程Spark里消费掉,表示协程数量。

func Spark(url string,data chan string, wg *sync.WaitGroup,maps map[string]string)  {

	result,_:=Get(url)
	ret:=regexp.MustCompile("<img data-original=\"//bimgs.plmeizi.com/images/bing(\\S*?)[^>]*>.*?|<.*? />")
	all:=ret.FindAllStringSubmatch(result,-1)
	reg:=regexp.MustCompile("(.?)(\\d{4}-\\d{2}-\\d{2})(.?)")
	for _,v:=range all{
		key:=reg.FindAllStringSubmatch(v[0],-1)
		_, ok := maps[key[0][2]]
		if ok {//如果时间已经存在map中,则跳过
			continue
		}else {
			maps[key[0][2]]=v[0]
			data <- v[0]
		}
	}
	wg.Done()//等同于wg.add(-1)
}

此时图片链接数据都被堆在通道内,此时开协程来消费这些数据。

go logic.Consume(data,done)

当完成之后done传入true,否则为false

func Consume(data chan string, done chan bool) {
	f, err := os.OpenFile("spark2",os.O_APPEND|os.O_WRONLY,0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	for d := range data {
		_, err = fmt.Fprintln(f, d)
		if err != nil {
			fmt.Println(err)
			f.Close()
			done <- false
			return
		}
	}
	err = f.Close()
	if err != nil {
		fmt.Println(err)
		done <- false
		return
	}
	done <- true
}

然后等待组完成之后表示数据已经处理完毕,关闭通道。

go func() {
		wg.Wait()
		close(data)
		//close(done)
	}()

此时img标签内容已经存入文件中。
在这里插入图片描述

存储

读取文件中的数据,进行进一步正则匹配,拼接url

	mapss:=logic.ReadFile()
	for k,v:=range mapss {
		img:=models.BingImg{
			Time: k,
			Url: v.Urlz,
			Instr: v.Instr,
		}
		logic.SavePic(img.Time,img.Url,nil)
		}
	}

读取文件内容,进行正则匹配,提取有效信息拼接结构体,返回map。

func ReadFile() map[string]models.Urlzz{
	f, err := os.OpenFile("spark1",os.O_APPEND|os.O_RDONLY,0666)
	if err != nil {
		fmt.Println(err)
		return nil
	}
	reg:=regexp.MustCompile("\\d{4}-\\d{2}-\\d{2}")//匹配时间
	rep:=regexp.MustCompile("】(.*)\"")//匹配照片信息文本

	rey:=regexp.MustCompile("/\\d{4}/(.*jpg)\"")//匹配图片有效地址
	re0:="https://cn.bing.com/th?id="//用以拼接bing首页
	
	scanner := bufio.NewScanner(f)
	var mapp = make(map[string]models.Urlzz)
	for scanner.Scan() {
		lineText := scanner.Text()//读取文件
		time:=reg.FindAllStringSubmatch(lineText,-1)//时间
		instr:=rep.FindAllStringSubmatch(lineText,-1)//说明
		r1:=rey.FindAllStringSubmatch(lineText,-1)
		url:=re0+r1[0][1]//url
		mapp[time[0][0]]=models.Urlzz{
			Urlz: url,
			Instr: instr[0][1],
		}
		if scanner.Text()=="" {
			continue
		}

	}
	return mapp
}

此时再循环这个map,请求网页保存图片即可,这里按时间命名。

func SavePic(idstr string,url string,wg *sync.WaitGroup) {
	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		fmt.Println(err)
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
	}
	_ = ioutil.WriteFile("img/"+idstr+".jpg", body, 0755)

}

最后放上一些很nice的图

请添加图片描述
在这里插入图片描述

快动起手来吧!有不足之处欢迎指正

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值