Golang爬虫学习

2023年将会持续于B站、CSDN等各大平台更新,可加入粉丝群与博主交流:838681355,为了老板大G共同努力。
【商务合作请私信或进群联系群主】

一、golang-net/http包(正则)

1.1 简介和示例

导包:
import(
    "fmt"
    "io/ioutil"
    "net/http"
)

创建请求:
	client := &http.Client{} 
	req,_ := http.NewRequest("GET",url,nil)
示例:
import (
	"fmt"
	"io/ioutil"
	"net/http"
)
func pachong(url string) string{ // 设置一个变量名为Url,类型为string
	// Get请求服务
	client := &http.Client{} 
	req,_ := http.NewRequest("GET",url,nil)
	// 设置ua头,cookie等,是为了绕过一些爬虫机制
	req.Header.Set("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0")
	req.Header.Add("Cookie","buvid3=65BAA442-C9DA-443F-9A21-DD07C777480C34756infoc;")
	// 请求处理
	resp,err := client.Do(req)
	if err != nil{
		fmt.Println("Http get err:",err)
		return ""
	}
	if resp.StatusCode != 200{
		fmt.Println("Htpp status code:",resp.StatusCode)
		return ""
	}
	// 处理完毕后关掉连接
	defer resp.Body.Close() 
	body,err := ioutil.ReadAll(resp.Body)
	if err != nil{
		fmt.Println("Read error",err)
		return ""
	}
	return string(body)
}
func main(){
	url := "https://www.baidu.com" //付给变量url地址
	s := pachong(url) //用方法引用该变量url,付给s
	fmt.Printf(s) // 打印输出
}

1.2 爬虫解析页面

导包:
import(
    "fmt"
    "io/ioutil"
    "net/http"
    "regexp"
    "strings"
)

如何解析到想要的数据:
1.替换空格,去除空格
2.找到标签,找到页面内容`<div class="article">(.*?)</div>`
3.找到标题(`<h1 class="article-title" itemprop="name">(.*?)</h1>`)
4.找到页面内容
5.切片
1.2.1 解析链接页面
func parse(html string){ // 解析链接页面,主要采用正则表达式
	// 替换掉空格
	html = strings.Replace(html,"\n","",-1)
	// 边栏内容正则
	re_sidebar := regexp.MustCompile(`<aside id="sidebar" role="navigation">(.*?)</aside>`) // (.*?)任意匹配
	// 找到边栏内容块
	sidebar := re_sidebar.FindString(html) // 意思是在html里头找re_sidebar正则匹配的内容
	// 链接正则
	re_link := regexp.MustCompile(`href="(.*?)"`)
	// 找到所有链接
	links := re_link.FindAllString(sidebar,-1)

	base_url := "https://gorm.io/zh_CN/docs/"
	for _, v := range links{
		fmt.Printf("v: %v\n", v)
		s := v[6:len(v)-1] // 抓取到的切片取从第六位开始,到最后一位减一,href="index.html"
		url := base_url + s
		fmt.Printf("url:%v\n",url) // 做字符串链接
	}
}
1.2.2 解析内容页面
func parse2(body string){
		// 替换掉空格
		body = strings.Replace(body,"\n","",-1)
		// 内容正则
		re_content := regexp.MustCompile(`<div class="article">(.*?)</div>`) // (.*?)任意匹配
		// 找到页面内容
		content := re_content.FindString(body) // 意思是body里头找re_sidebar正则匹配的内容
		// 标题
		re_title := regexp.MustCompile(`<h1 class="article-title" itemprop="name">(.*?)</h1>`)
		// 找到页面内容
		title := re_title.FindString(content)
		fmt.Printf("title: %v\n", title)
		// 切片
		title = title[42 : len(title)-5]
		fmt.Printf("title: %v\n", title)
}
1.2.3 代码实例
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp" // 正则标准库
	"strings"
)
func pachong(url string) string{ // 设置一个变量名为Url,类型为string
	// Get请求服务
	client := &http.Client{} 
	req,_ := http.NewRequest("GET",url,nil)
	// 设置ua头,cookie等,是为了绕过一些爬虫机制
	req.Header.Set("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0")
	req.Header.Add("Cookie","buvid3=65BAA442-C9DA-443F-9A21-DD07C777480C34756infoc; CURRENT_FNVAL=4048; PVID=1; CURRENT_QUALITY=0; blackside_state=0; fingerprint=d51052e7d692cb696b50a17a3078c108; buvid_fp=2a41143fc6b7358421c5668cd60fe1cb; LIVE_BUVID=AUTO9116241867606956; b_ut=5; i-wanna-go-back=-1; CURRENT_BLACKGAP=0; buvid4=57E262C3-373B-0C43-11A2-EFB150BEE9EC87880-022012716-c8mC4VtaIp9z9jT1JvXl9w%3D%3D; nostalgia_conf=-1; bp_video_offset_494577303=746190708927365100; hit-dyn-v2=1; _uuid=2F10DDA24-1772-D10C4-8D76-B108D105E7E78981241infoc; buvid_fp_plain=undefined; fingerprint3=4ac7728b721e19742b1f93d7585c875d; b_nut=100; sid=5axxdv1c; SESSDATA=da784f22%2C1680100070%2C110b4%2A91; bili_jct=9e665d59c5d2c8f6fddecad47c65e920; DedeUserID=494577303; DedeUserID__ckMd5=92cd12f6622dfb59; rpdid=|(JYYRlYR))u0J'uYY)~~lJ|R; innersign=1; b_lsid=EB4EB6E9_1857603661D; theme_style=ligh")
	// 请求处理
	resp,err := client.Do(req)
	if err != nil{
		fmt.Println("Http get err:",err)
		return ""
	}
	if resp.StatusCode != 200{
		fmt.Println("Htpp status code:",resp.StatusCode)
		return ""
	}
	// 处理完毕后关掉连接
	defer resp.Body.Close() 
	body,err := ioutil.ReadAll(resp.Body)
	if err != nil{
		fmt.Println("Read error",err)
		return ""
	}
	return string(body)
}
func parse(html string){ // 解析链接页面,主要采用正则表达式
	// 替换掉空格
	html = strings.Replace(html,"\n","",-1)
	// 边栏内容正则
	re_sidebar := regexp.MustCompile(`<aside id="sidebar" role="navigation">(.*?)</aside>`) // (.*?)任意匹配
	// 找到边栏内容块
	sidebar := re_sidebar.FindString(html) // 意思是在html里头找re_sidebar正则匹配的内容
	// 链接正则
	re_link := regexp.MustCompile(`href="(.*?)"`)
	// 找到所有链接
	links := re_link.FindAllString(sidebar,-1)

	base_url := "https://gorm.io/zh_CN/docs/"
	for _, v := range links{
		fmt.Printf("v: %v\n", v)
		s := v[6:len(v)-1] // 抓取到的切片取从第六位开始,到最后一位减一,href="index.html"
		url := base_url + s
		fmt.Printf("url:%v\n",url) // 做字符串链接
		
		body := pachong(url)
		go parse2(body) // 启动另外一个线程处理
	}
}
func parse2(body string){
		// 替换掉空格
		body = strings.Replace(body,"\n","",-1)
		// 内容正则
		re_content := regexp.MustCompile(`<div class="article">(.*?)</div>`) // (.*?)任意匹配
		// 找到页面内容
		content := re_content.FindString(body) // 意思是body里头找re_sidebar正则匹配的内容
		// 标题
		re_title := regexp.MustCompile(`<h1 class="article-title" itemprop="name">(.*?)</h1>`)
		// 找到页面内容
		title := re_title.FindString(content)
		fmt.Printf("title: %v\n", title)
		// 切片
		title = title[42 : len(title)-5]
		fmt.Printf("title: %v\n", title)
}
func main(){
	url := "https://gorm.io/zh_CN/docs" //付给变量url地址
	s := pachong(url) //用方法引用该变量url,付给s
	//fmt.Printf(s) // 打印输出
	parse(s)
}

1.3 保存至文件

func save(title string,content string){
    err := os.WriteFile("./"+title+".html",[]byte(content),0644)
    if err != nil{
        panic(err)
    }
}

1.4 保存至数据库

安装库:
go get xorm.io/xorm
go get github.com/go-sql-driver/mysql

导包:
import(
    "fmt"
    "io/ioutil"
    "net/http"
    "regexp"
    "strings"
    "xorm.io/xorm"
    "github.com/go-sql-driver/mysql"
)

连接数据库:
var engine *xorm.Engine
var err error

func init(){
    engine,err = xorm.NewEngine("mysql","root:123456@/test_xorm?charset=utf8")
    if err != nil{
        fmt.Printf("err:%v\n",err)
    }else{
        err2 := engine.Ping()
        if err2 != nil{
            fmt.Printf("err2:%v\n",err2)
        }else{
            print("连接成功!")
        }
    }
}

创建结构体:
type GormPage struct{
    Id int64
    Title string
    Content string `xorm:"text"`
    Created time.Time `xorm:"created"`
    Updated time.Time `xorm:"updated"`
}

保存数据到数据库:
func saveToDB(title string,content string){
    engine.Sync(new(GormPage)) // 创建的数据库表名为gorm_page
    page := GormPage{
        Title:title,
        Content:content,
    }
    affected,err := engine.Insert(&page)
    if err != nil{
        fmt.Printf("err:%v\n",err)
    }
    fmt.Println("save:"+string(affected))
}
解析内容中加入:saveToDB(title,content)

二、golang-goquery

goquery是一个爬虫库,可以非常方便进行html页面分析,元素提取,类似jquery,它基于html解析库net/html和css库cascadia,提供与jquery相近的接口,go著名的爬虫框架colly就是基于goquery。

安装:go get -u github.com/PuerkitoBio/goquery

2.1 爬取示例

package main

import (
	"fmt"
	"github.com/PuerkitoBio/goquery"
)
func main() {
	url := "https://gorm.io/zh_CN/docs" //付给变量url地址
	d, _ := goquery.NewDocument(url)
	d.Find(".sidebar-link").Each(func(i int, s *goquery.Selection) { //查找class里面的包含sidebar-link所有的元素
		s2 := s.Text()
		fmt.Printf("s2:%v\n", s2)
		href, _ := s.Attr("href") // 在class大类中找到href属性,将链接爬取
		fmt.Printf("href:%v\n", href)
	})
}

2.2 Goquery Api Document

Document表示要爬取的文档。

方式一:goquery.NewDocument(url)
	url := "https://gorm.io/zh_CN/docs" //付给变量url地址
	dom , err := goquery.NewDocument(url) // 加载文档
	if err != nil{
		log.Fatalln(err)
	}

方式二:goquery.NewDocumentFromResponse(resp)
	client := &http.Client{} // 打开连接
	url := "https://gorm.io/zh_CN/docs" //付给变量url地址
	req,_ := http.NewRequest("GET",url,nil) // 连接方式GET,传递url
	resp,err := client.Do(req)
	dom,err := goquery.NewDocumentFromResponse(resp)
	if err != nil{
		log.Fatalln(err)
	}
    dom.Find() //爬虫过程

方式三:goquery.NewDocumentFromReader(strings.NewReader(html))
    func main() {
        html := `<body>
                      <div>DIV1</div>
                      <div>DIV2</div>
                      <span>SPAN</span>
                 </body>`
        dom, err := goquery.NewDocumentFromReader(strings.NewReader(html)) //本地读取html方式
        if err != nil {
            log.Fatalln(err)
        }
        dom.Find("")
    }
2.2.1 Goquery Api 选择器
Goquery选择器:类似jQuery或css选择器,常用的有元素名称选择器、ID选择器、class选择器

元素名称选择器:
func main() {
	html := `<body>
                  <div>DIV1</div>
                  <div>DIV2</div>
                  <span>SPAN</span>
             </body>`
	dom, err := goquery.NewDocumentFromReader(strings.NewReader(html))
	if err != nil {
		log.Fatalln(err)
	}
	dom.Find("div").Each(func(i int, selection *goquery.Selection) { //选择div标签,匹配所有
		fmt.Println("i", i, "select text", selection.Text())
	})
}

ID选择器:
func main() {
	html := `<body>
                  <div id="div1">DIV1</div> // 变成div id="div1"
                  <div>DIV2</div>
                  <span>SPAN</span>
             </body>`
	dom, err := goquery.NewDocumentFromReader(strings.NewReader(html))
	if err != nil {
		log.Fatalln(err)
	}
	dom.Find("#div1").Each(func(i int, selection *goquery.Selection) { // 匹配div1
		fmt.Println("i", i, "select text", selection.Text())
	})
}

class选择器:
func main() {
	html := `<body>
                  <div id="div1">DIV1</div>
                  <div class="name">DIV2</div>
                  <span>SPAN</span>
             </body>`
	dom, err := goquery.NewDocumentFromReader(strings.NewReader(html))
	if err != nil {
		log.Fatalln(err)
	}
	dom.Find(".name").Each(func(i int, selection *goquery.Selection) { // 匹配class中的name
		fmt.Println("i", i, "select text", selection.Text())
	})
}

2.3 Goquery Api Selection

select可以提取、删除、添加元素、属性内容

内容函数:
1) 类似函数的位置操作
Eq(index int) *Selection // 根据索引获取某个节点集
First() *Selection // 获取第一个子节点集
Last() *Selection // 获取最后一个子节点集
Next() *Selection // 获取下一个兄弟节点集
NextAll() *Selection // 获取后面所有兄弟节点集
Prev() *Selection // 前一个兄弟节点集
Get(index int) *html.Node // 根据索引获取一个节点
Index() int // 返回选择对象中第一个元素的位置
Slice(start,end int) *Selection // 根据起始位置获取子节点集

2) 循环遍历选择的节点
Each(f func(int, *Selection)) *Selection //遍历
EachWithBreak(f func(int,*Selection)bool) *Selection //可中断遍历
Map(f func(int,*Selection)string)(result []string) //返回字符串数组

3) 检测或获取节点属性值
Attr(),RemoveAttr(),SetAttr() //获取,移除,设置属性的值
AddClass(),HasClass(),RemoveClass(),ToggleClass()
Html() // 获取该节点的Html
Length() //返回该Selection的元素个数
Text() //获取该节点的文本值

4) 在文档书之间来回跳转(常用的查找节点方法)
Children() //返回Selection中各个节点下的孩子节点
Contents() //获取当前节点下的所有节点
Find() //查找获取当前匹配的元素
Next() //下一个元素
Prev() //上一个元素

三、爬虫框架-colly

Colly是go语言编写的Web框架,提供一个能够写任何爬虫、采集器、蜘蛛的简洁模板。

特性:
1.API清晰
2.速度快
3.管理每个域的请求延迟和最大并发数
4.自动cookie会话处理
5.同步、异步、并行抓取
6.高速缓存
7.自动处理非unicode编码
8.支持Robots.txt
9.支持google APP engine
10.通过环境变量进行配置
11.可拓展

安装:go get -u github.com/gocolly/colly

3.1 爬取示例

import (
	"fmt"
	"github.com/gocolly/colly"
)

func main() {
	c := colly.NewCollector()
	c.OnHTML(".siderbar-link", func(e *colly.HTMLElement) {
		e.Request.Visit(e.Attr("href"))
	})
	c.OnRequest(func(r *colly.Request) {
		fmt.Println("url", r.URL)
	})
	c.Visit("https://xxx/) // 爬取的URL
}

3.2 回调方法

请求之前调用:OnRequest
请求期间发生错误调用:OnError
收到响应标头后调用:OnResponseHeaders
收到响应后调用:OnResponse
OnResponse接收的内容HTML就调用:OnHTML
OnHTML接收内容是HTML或XML就调用:OnXML
回调后OnXML调用:OnScraped

示例:
    c := colly.NewCollector()
    c.OnRequest(func(r *colly.Request) {
        fmt.Println("请求前调用:OnRequest")
    })
    c.OnError(func(_*colly.Response, err error) {
        fmt.PrintIn("发生错误调用:OnError")
    })
    c.OnResponse(func(r *colly.Response) {
        fmt.PrintIn("获得响应后调用:OnResponse")
    })
    c.OnHTML("a[href]"func(e *colly.HTMLElement) {
        fmt.PrintIn("OnResponse接收的内容HTML就调用:OnHTML")
    c.OnXML("//h1"func(e *colly.XMLElement) {
        fmt.PrintIn("onResponse收到xm1内容后调用:OnXML")
    })
    c.OnScraped(func(r *colly.Response) {
        fmt.Println("结束",r.Request.URL)
    })

3.3 配置

设置UserAgent:
    c := colly.NewCollector()
    c.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0"

设置cookie:
方式一:
    c.OnRequest(func(r *colly.Request){
        r.Headers.Add("cookie","")
    })
方式二:
    siteCokkie := C.Cookies("url")
    c.SetCookies("",siteCokkie)

HTTP配置:
    c := colly.NewCollectior()
    c.WithTransport(&http.Transport{
        Proxy:http.ProxyFromEnvironment,
        DialContext:(&net.Dialer{
            Timeout: 30 * time.Second,
            KeepAlive: 30 * time.Second,
            DualStack: true,
        }).DialContext,
        MaxIdleConns: 100,
        IdleConnTimeout: 90 * time.Second,
        TLSHandshakeTimeout: 10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
    })

3.4 页面爬取和解析

页面爬取和解析重点方法是OnHTML的回调方法
    c.OnHTML("a[href]",func(e *colly.HTMLElement){
        e.Request.Visit(e.Attr("href"))
    })

3.5 框架重构爬虫应用

import (
	"fmt"
	"github.com/gocolly/colly"
)

func main() {
	c := colly.NewCollector()
	c.OnHTML(".sidebar-link", func(e *colly.HTMLElement) {
		href := e.Attr("href")
		if href != "index.html" { // 如果等于index.html则继续访问
			c.Visit(e.Request.AbsoluteURL(href))
		}
	})
	c.OnHTML(".article-title", func(h *colly.HTMLElement) { // 跳转链接后,找到ariticle-title,获取他的内容
		content, _ := h.DOM.Html()
		fmt.Printf("content:%v\n", content)
	})
	c.OnHTML(".article", func(h *colly.HTMLElement) {
		content, _ := h.DOM.Html()
		fmt.Printf("content:%v\n", content)
	})
	c.OnRequest(func(r *colly.Request) {
		fmt.Println("Visiting", r.URL.String())
	})
	c.Visit("https://gorm.io/zh_CN/docs/")
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cllmsy_K

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值