Golang爬虫学习

news/2024/7/19 11:32:05 标签: golang, 爬虫, 学习

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

golangnethttp_3">一、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)

golanggoquery_280">二、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/")
}

http://www.niftyadmin.cn/n/982923.html

相关文章

python pyenv_使用pyenv管理多个Python版本

python pyenvHave you ever wanted to contribute to a project that supports multiple versions of Python but aren’t sure how you would easily test all the versions? Are you ever curious about the latest and greatest versions of Python? Maybe you’d like to…

HttpSessionBindingListener和HttpSessionAttributeListener区别

HttpSessionBindingListener和HttpSessionAttributeListener是两个经常让初学者弄混的监听器,其实它们有很大的区别。这2个监听器在文章中简称为BindingListener和AttributeListener. 1.BindingListener有2个方法,valueBound(HttpSessinBindingEvent)和valueUnbount(HttpSessio…

四大亮点不容错过,TDengine 开发者大会全议程公布!

如果你关注开源、关注数据技术的趋势发展&#xff0c;或者你正在为大数据处理技术的架构升级而忧心忡忡&#xff0c;抑或你只是 8 月 13 日的这个周六不想宅在家里但却还没有任何安排&#xff08;很无聊&#xff09;&#xff0c;那你为什么不选择来 TDengine 开发者大会呢&…

kerberos认证原理---讲的非常细致,易懂

前几天在给人解释Windows是如何通过Kerberos进行Authentication的时候&#xff0c;讲了半天也别把那位老兄讲明白&#xff0c;还差点把自己给绕进去。后来想想原因有以下两点&#xff1a;对于一个没有完全不了解Kerberos的人来说&#xff0c;Kerberos的整个Authentication过程确…

一次向svn中增加所有新增文件 svn add all new files【转】

以下摘自&#xff1a;《卓有成效的程序员》之自动化 转自&#xff1a;http://blog.csdn.net/spare_h/article/details/6677435 我经常会一次往Subversion里添加一批文件。在使用命令行做这件事时&#xff0c;你必须指定所有想要添加的文件名。如果文件不多的话这还不算太…

Hadoop-2.4.1学习之Map任务源代码分析(下)

在Map任务源码分析&#xff08;上&#xff09;中&#xff0c;对MAP阶段的代码进行了学习&#xff0c;这篇文章文章将学习Map任务的SORT阶段。假设Reducer的数量不为0。则还须要进行SORT阶段。但从上面的学习中并未发现与MAP阶段运行完毕调用mapPhase.complete()相似的在SORT阶段…

转弯

早上起来&#xff0c;她发现家里停电了。于是没办法用热水洗漱&#xff0c;用电吹风吹头发&#xff0c;不能热牛奶&#xff0c;烤面包&#xff0c;只好草草打理一下就出门。 刚走进电梯&#xff0c;邻居家养的小狗一下子冲进来扑住&#xff0c;上周刚买的米白长裙上顿时出现两只…

边缘盒子+时序数据库,美的数字化平台 iBUILDING 背后的技术选型

小 T 导读&#xff1a;在 2021 楼宇科技 TRUE 大会上&#xff0c;美的暖通与楼宇事业部首次发布了数字化平台 iBuilding&#xff0c;以“软驱硬核”方式赋能建筑行业。作为一个全新的项目&#xff0c;iBuilding 在数据库选型上比较谨慎&#xff0c;分别对比了多款 Database 产品…