读书散文简友广场

分享一波GO的爬虫

2021-06-23  本文已影响0人  阿兵云原生

分享一波GO的爬虫

分享一波GO的爬虫.jpg

我们一起来回顾一下上一次咱们说到的 使用 GOLANG 发送邮件

Golang+chromedp+goquery 简单爬取动态数据 |Go主题月

想看看如何使用 GOLANG 发送邮件的,欢迎查看文章如何使用 GOLANG 发送邮件

image

还记得之前我们简单分享了一篇golang 爬取网页动态数据的文章 Golang+chromedp+goquery 简单爬取动态数据 |Go主题月

要是有朋友感兴趣的话,我们可以详细的研究一下这个chromedp框架的使用方式

今天咱们来分享一下使用 GO 来爬取网页的静态数据

啥是静态网页和动态网页呢

什么是静态网页数据呢?

那么顺便说一下什么是动态网页吧

也就是说,动态网页的页面代码虽然没有变,可是显示的内容是可以随着时间的流逝、不同的环境,数据库的变化而变化的

GO 来爬取网页的静态数据

咱们爬取静态网页的数据,例如我们爬取这个网站上的静态数据,爬取网页上的账号和密码信息

http://www.ucbug.com/jiaocheng/63149.html?_t=1582307696

咱们爬取这个网站的步骤:

image

咱们来写一个DEMO,爬上上述网址的账号和密码信息 ,网页上我们的要的信息是这样的,咱们仅仅是供学习使用,切莫用来做一些不好的事情

image image
package main

import (
   "io/ioutil"
   "log"
   "net/http"
   "regexp"
)

const (
   // 正则表达式,匹配出 XL 的账号密码
   reAccount = `(账号|迅雷账号)(;|:)[0-9:]+(| )密码:[0-9a-zA-Z]+`
)

// 获取网站 账号密码
func GetAccountAndPwd(url string) {
   // 获取网站数据
   resp, err := http.Get(url)
   if err !=nil{
      log.Fatal("http.Get error : ",err)
   }
   defer resp.Body.Close()

   // 去读数据内容为 bytes
   dataBytes, err := ioutil.ReadAll(resp.Body)
   if err !=nil{
      log.Fatal("ioutil.ReadAll error : ",err)
   }

   // 字节数组 转换成 字符串
   str := string(dataBytes)

   // 过滤 XL 账号和密码
   re := regexp.MustCompile(reAccount)

   // 匹配多少次, -1 默认是全部
   results := re.FindAllStringSubmatch(str, -1)

   // 输出结果
   for _, result := range results {
      log.Println(result[0])
   }
}

func main() {
   // 简单设置log 参数
   log.SetFlags(log.Lshortfile | log.LstdFlags)
   // 传入网站地址,爬取开始爬取数据
   GetAccountAndPwd("http://www.ucbug.com/jiaocheng/63149.html?_t=1582307696")
}

运行上述代码的结果如下:

2021/06/xx xx:05:25 main.go:46: 账号:357451317 密码:110120a
2021/06/xx xx:05:25 main.go:46: 账号:907812219 密码:810303
2021/06/xx xx:05:25 main.go:46: 账号:797169897 密码:zxcvbnm132
2021/06/xx xx:05:25 main.go:46: 迅雷账号:792253782:1密码:283999
2021/06/xx xx:05:25 main.go:46: 迅雷账号:147643189:2密码:344867
2021/06/xx xx:05:25 main.go:46: 迅雷账号:147643189:1密码:267297

可以看出,账号:开头的数据 和 迅雷账号:开头的数据都被我们爬取下来, 其实爬取静态网页的内容不难,时间基本上是花在正则表达式匹配和数据处理上面

根据上述爬取网页的步骤,咱们可以列一下:

当然实际工作中,肯定不会那么简单,

例如自己爬取的数据在网站上格式不够统一,特殊字符比较多且比较杂没有规律,甚至数据是动态的,没有办法通过Get的方式拿到

不过上述的问题都是可以解决的,根据不同的问题,设计出不同的方案和数据的处理,相信这一点遇到的朋友一定能够解决掉,面对问题,咱们要有解决问题的决心

image

爬取图片

看了上面的例子,咱们再来试试爬取网页上的图片数据吧,例如在某度上搜索柴犬

是这样的一个页面

image

咱们把url地址栏的url复制粘贴过来,用来爬取数据

https://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=%E6%9F%B4%E7%8A%AC

由于图片比较多,咱们设置只匹配 2 张图片的数据

一起来看看 DEMO

package main

import (
   "io/ioutil"
   "log"
   "net/http"
   "regexp"
)

const (
   // 正则表达式,匹配出XL的账号密码
   reAccount = `(账号|迅雷账号)(;|:)[0-9:]+(| )密码:[0-9a-zA-Z]+`
   // 正则表达式,匹配出 图片
   rePic = `https?://[^"]+?(\.((jpg)|(png)|(jpeg)|(gif)|(bmp)))`
)

func getStr(url string)string{
   resp, err := http.Get(url)
   if err !=nil{
      log.Fatal("http.Get error : ",err)
   }
   defer resp.Body.Close()

   // 去读数据内容为 bytes
   dataBytes, err := ioutil.ReadAll(resp.Body)
   if err !=nil{
      log.Fatal("ioutil.ReadAll error : ",err)
   }

   // 字节数组 转换成 字符串
   str := string(dataBytes)
   return str
}

// 获取网站 账号密码
func GetAccountAndPwd(url string,n int) {
   str := getStr(url)
   // 过滤 XL 账号和密码
   re := regexp.MustCompile(reAccount)

   // 匹配多少次, -1 默认是全部
   results := re.FindAllStringSubmatch(str, n)

   // 输出结果
   for _, result := range results {
      log.Println(result[0])
   }
}

// 获取网站 账号密码
func GetPic(url string,n int) {

   str := getStr(url)

   // 过滤 图片
   re := regexp.MustCompile(rePic)

   // 匹配多少次, -1 默认是全部
   results := re.FindAllStringSubmatch(str, n)

   // 输出结果
   for _, result := range results {
      log.Println(result[0])
   }
}


func main() {
   // 简单设置l og 参数
   log.SetFlags(log.Lshortfile | log.LstdFlags)
   //GetAccountAndPwd("http://www.ucbug.com/jiaocheng/63149.html?_t=1582307696", -1)
   GetPic("https://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=%E6%9F%B4%E7%8A%AC",2)
}

运行上述代码,结果如下(没有做去重):

image
2021/06/xx xx:06:39 main.go:63: https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=4246005838,1103140037&fm=26&gp=0.jpg
2021/06/xx xx:06:39 main.go:63: https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=4246005838,1103140037&fm=26&gp=0.jpg
果然是我们想要的东西,可是光是打印出来,爬取的都是图片链接,肯定不能满足我们真实爬虫的需求,肯定还是要将爬取到图片下载下来,供我们所用,才是我们想要的 image

咱们这里为了演示方便,我们就在上述代码上面,加上下载文件的 小功能,咱们就下载第一张

package main

import (
   "fmt"
   "io/ioutil"
   "log"
   "net/http"
   "regexp"
   "strings"
   "time"
)

const (
   // 正则表达式,匹配出 图片
   rePic = `https?://[^"]+?(\.((jpg)|(png)|(jpeg)|(gif)|(bmp)))`
)

// 获取网页数据,且把数据转成 字符串
func getStr(url string) string {
   resp, err := http.Get(url)
   if err != nil {
      log.Fatal("http.Get error : ", err)
   }
   defer resp.Body.Close()

   // 去读数据内容为 bytes
   dataBytes, err := ioutil.ReadAll(resp.Body)
   if err != nil {
      log.Fatal("ioutil.ReadAll error : ", err)
   }

   // 字节数组 转换成 字符串
   str := string(dataBytes)
   return str
}

// 获取图片数据
func GetPic(url string, n int) {

   str := getStr(url)

   // 过滤 图片
   re := regexp.MustCompile(rePic)

   // 匹配多少次, -1 默认是全部
   results := re.FindAllStringSubmatch(str, n)

   // 输出结果
   for _, result := range results {
      // 获取具体的图片名字
      fileName := GetFilename(result[0])
     // 下载图片
      DownloadPic(result[0], fileName)
   }
}

// 获取到 文件的 名字
func GetFilename(url string) (filename string) {
   // 找到最后一个 = 的索引
   lastIndex := strings.LastIndex(url, "=")
   // 获取 / 后的字符串 ,这就是源文件名
   filename = url[lastIndex+1:]

   // 把时间戳 加 在原来名字前,拼一个新的名字
   prefix := fmt.Sprintf("%d",time.Now().Unix())
   filename = prefix + "_" + filename

   return filename
}

func DownloadPic(url string, filename string) {
   resp, err := http.Get(url)
   if err != nil {
      log.Fatal("http.Get error : ", err)
   }
   defer resp.Body.Close()

   bytes, err := ioutil.ReadAll(resp.Body)
   if err != nil {
      log.Fatal("ioutil.ReadAll error : ", err)
   }

   // 文件存放的路径
   filename = "./" + filename

   // 写文件 并设置文件权限
   err = ioutil.WriteFile(filename, bytes, 0666)
   if err != nil {
      log.Fatal("wirte failed !!", err)
   } else {
      log.Println("ioutil.WriteFile successfully , filename = ", filename)
   }
}

func main() {
   // 简单设置l og 参数
   log.SetFlags(log.Lshortfile | log.LstdFlags)
   GetPic("https://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=%E6%9F%B4%E7%8A%AC", 1)
}

上述代码,咱们加了 2 个函数,辅助我们进行图片名的修改 和 图片的下载

运行上述代码,可以看到如下效果

2021/06/xx xx:50:04 main.go:91: ioutil.WriteFile successfully , filename =  ./1624377003_0.jpg

且当前目录下,已经下载成功了一张图片,名字为 1624377003_0.jpg

image

如下是具体图片的形象照

image

有大兄弟们会说,我一个协程去下载图片太慢了,可不可以下载快一点,多个协程一起去下载呗

并发爬取咱们的小柴犬

咱们还记之前说过的 GO 通道 和 sync包 吗?GO通道和 sync 包的分享, 正好可以实践一下,这个小功能是比较简单的,说一下大体的思路,大家感兴趣的话,可以去实现一波,

怎么样,大兄弟们,小伙伴们,感兴趣的话,可以实践一波,要是对爬取动态数据有想法的话,咱们可以沟通和探讨一下,一起进步

image

总结

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

image

好了,本次就到这里,下一次 GO中 gjson 的应用和分享

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是小魔童哪吒,欢迎点赞关注收藏,下次见~

上一篇 下一篇

猜你喜欢

热点阅读