Go语言进阶第10天(爬虫与标签页正则)

1.贴吧爬虫

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"
	"time"
)

func HttpGet(url string) (result string, err error) {
	resp, err1 := http.Get(url)
	if err1 != nil {
		err = err1 // 将封装函数内部的错误,传出给调用者。
		return
	}
	defer resp.Body.Close()

	time.Sleep(time.Second)

	// 循环读取 网页数据, 传出给调用者
	buf := make([]byte, 4096)
	for {
		n, err2 := resp.Body.Read(buf)
		if n == 0 {
			fmt.Println("读取网页完成")
			break
		}
		if err2 != nil && err2 != io.EOF {
			err = err2
			return
		}
		// 累加每一次循环读到的 buf 数据,存入result 一次性返回。
		result += string(buf[:n])
	}
	return
}

// 爬取页面操作。
func working(start, end int) {
	fmt.Printf("正在爬取第%d页到%d页....\n", start, end)

	// 循环爬取每一页数据
	for i := start; i <= end; i++ {
		url := "https://tieba.baidu.com/f?kw=%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9F&ie=utf-8&pn=" + strconv.Itoa((i-1)*50)
		result, err := HttpGet(url)
		if err != nil {
			fmt.Println("HttpGet err:", err)
			continue
		}
		//fmt.Println("result=", result)
		// 将读到的整网页数据,保存成一个文件
		f, err := os.Create("第 " + strconv.Itoa(i) + " 页" + ".html")
		if err != nil {
			fmt.Println("Create err:", err)
			continue
		}
		f.WriteString(result)
		f.Close() // 保存好一个文件,关闭一个文件。
	}
}

func main01() {
	// 指定爬取起始、终止页
	var start, end int
	fmt.Print("请输入爬取的起始页(>=1):")
	fmt.Scan(&start)
	fmt.Print("请输入爬取的终止页(>=start):")
	fmt.Scan(&end)

	working(start, end)
}

2.贴吧并发式爬虫

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"
	"time"
)

func HttpGet2(url string) (result string, err error) {
	resp, err1 := http.Get(url)
	if err1 != nil {
		err = err1 // 将封装函数内部的错误,传出给调用者。
		return
	}
	defer resp.Body.Close()

	time.Sleep(time.Second)

	// 循环读取 网页数据, 传出给调用者
	buf := make([]byte, 4096)
	for {
		n, err2 := resp.Body.Read(buf)
		if n == 0 {
			fmt.Println("读取网页完成")
			break
		}
		if err2 != nil && err2 != io.EOF {
			err = err2
			return
		}
		// 累加每一次循环读到的 buf 数据,存入result 一次性返回。
		result += string(buf[:n])
	}
	return
}

// 爬取单个页面的函数
func SpiderPage(i int, page chan int) {
	url := "https://tieba.baidu.com/f?kw=%E7%BB%9D%E5%9C%B0%E6%B1%82%E7%94%9F&ie=utf-8&pn=" + strconv.Itoa((i-1)*50)
	result, err := HttpGet2(url)
	if err != nil {
		fmt.Println("HttpGet err:", err)
		return
	}
	//fmt.Println("result=", result)
	// 将读到的整网页数据,保存成一个文件
	f, err := os.Create("第 " + strconv.Itoa(i) + " 页" + ".html")
	if err != nil {
		fmt.Println("Create err:", err)
		return
	}
	f.WriteString(result)
	f.Close() // 保存好一个文件,关闭一个文件。

	page <- i // 与主go程完成同步。
}

// 爬取页面操作。
func working2(start, end int) {
	fmt.Printf("正在爬取第%d页到%d页....\n", start, end)

	page := make(chan int)

	// 循环爬取每一页数据
	for i := start; i <= end; i++ {
		go SpiderPage(i, page)
	}

	for i := start; i <= end; i++ {
		fmt.Printf("第 %d 个页面爬取完成\n", <-page)
	}
}

func main02() {
	// 指定爬取起始、终止页
	var start, end int
	fmt.Print("请输入爬取的起始页(>=1):")
	fmt.Scan(&start)
	fmt.Print("请输入爬取的终止页(>=start):")
	fmt.Scan(&end)

	working2(start, end)
}

3.正则-字符

package main

import (
	"fmt"
	"regexp"
)

func main() {

	str := "abc a7c mfc cat aMc azc cba"
	// 解析、编译正则表达式
	//ret := regexp.MustCompile(`a.c`)  	// `` : 表示使用原生字符串
	ret := regexp.MustCompile(`a[^0-9a-z]c`) // `` : 表示使用原生字符串

	// 提取需要信息
	alls := ret.FindAllStringSubmatch(str, -1)
	fmt.Println("alls:", alls)

}

4.正则-小数

package main

import (
	"fmt"
	"regexp"
)

func main04() {
	str := "3.14 123.123 .68 haha 1.0 abc 7. ab.3 66.6 123."

	// 解析、编译正则表达式
	//ret := regexp.MustCompile(`[0-9]+\.[0-9]+`)
	//ret := regexp.MustCompile(`\d+\.\d+`)
	ret := regexp.MustCompile(`\d\.\d`)

	// 提取需要的信息
	alls := ret.FindAllStringSubmatch(str, -1)
	fmt.Println("alls:", alls)
}

5.正则-标签

package main

import (
	"fmt"
	"regexp"
)

func main05() {
	str := `

	Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国
	
	
	
	
	
	
	
	

	

	
hello regexp
hello 2
hello 890
hello 664
2块钱啥时候还? 过了年再说吧! 刚买了车,没钱。。。
身体 `
// 解析、编译正则表达式 //ret := regexp.MustCompile(`
(.*)
`)
ret := regexp.MustCompile(`
(?s:(.*?))
`
) // 提取需要的信息 alls := ret.FindAllStringSubmatch(str, -1) fmt.Println("alls:", alls) for _, one := range alls { fmt.Println("one[0]=", one[0]) fmt.Println("one[1]=", one[1]) } }

6.并发提取爬虫

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"regexp"
	"strconv"
)

// 爬取指定url 的页面,返回 result
func HttpGetDB(url string) (result string, err error) {

	resp, err1 := http.Get(url)
	if err1 != nil {
		err = err1
		return
	}
	defer resp.Body.Close()

	buf := make([]byte, 4096)
	// 循环爬取整页数据
	for {
		n, err2 := resp.Body.Read(buf)
		if n == 0 {
			break
		}
		if err2 != nil && err2 != io.EOF {
			err = err2
			return
		}
		result += string(buf[:n])
	}
	return
}

func Save2file(idx int, filmName, filmScore, peopleNum [][]string) {
	path := "C:/itcast/" + "第 " + strconv.Itoa(idx) + " 页.txt"
	f, err := os.Create(path)
	if err != nil {
		fmt.Println("os.Create err:", err)
		return
	}
	defer f.Close()

	n := len(filmName) // 得到 条目数。 应该是 25
	// 先打印 抬头  电影名称        评分         评分人数
	f.WriteString("电影名称" + "\t\t\t" + "评分" + "\t\t" + "评分人数" + "\n")
	for i := 0; i < n; i++ {
		f.WriteString(filmName[i][1] + "\t\t\t" + filmScore[i][1] + "\t\t" + peopleNum[i][1] + "\n")
	}
}

// 爬取一个豆瓣页面数据信息
func SpiderPageDB(idx int, page chan int) {
	// 获取 url
	url := "https://movie.douban.com/top250?start=" + strconv.Itoa((idx-1)*25) + "&filter="

	// 封装 HttpGet2 爬取 url 对应页面
	result, err := HttpGetDB(url)
	if err != nil {
		fmt.Println("HttpGet2 err:", err)
		return
	}
	//fmt.Println("result=", result)
	// 解析、编译正则表达式 —— 电影名称:
	ret1 := regexp.MustCompile(`(?s:(.*?)))
	// 提取需要信息
	filmName := ret1.FindAllStringSubmatch(result, -1)

	// 解析、编译正则表达式 —— 分数:
	pattern := `(?s:(.*?))`
	ret2 := regexp.MustCompile(pattern)
	// 提取需要信息
	filmScore := ret2.FindAllStringSubmatch(result, -1)

	// 解析、编译正则表达式 —— 评分人数:
	ret3 := regexp.MustCompile(`(?s:(\d*?))人评价`)
	//ret3 := regexp.MustCompile(`(.*?)人评价`)

	// 提取需要信息
	peopleNum := ret3.FindAllStringSubmatch(result, -1)

	// 将提取的有用信息,封装到文件中。
	Save2file(idx, filmName, filmScore, peopleNum)

	// 与主go程配合 完成同步
	page <- idx
}

func toWork(start, end int) {
	fmt.Printf("正在爬取 %d 到 %d 页...\n", start, end)

	page := make(chan int) //防止主go 程提前结束

	for i := start; i <= end; i++ {
		go SpiderPageDB(i, page)
	}

	for i := start; i <= end; i++ {
		fmt.Printf("第 %d 页爬取完毕\n", <-page)
	}
}

func main06() {
	// 指定爬取起始、终止页
	var start, end int
	fmt.Print("请输入爬取的起始页(>=1):")
	fmt.Scan(&start)
	fmt.Print("请输入爬取的终止页(>=start):")
	fmt.Scan(&end)

	toWork(start, end)
}

你可能感兴趣的:(go架构师,golang,爬虫)