目录
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的图