• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

go语言的爬取网站信息上

武飞扬头像
矮木饭
帮助1

基本流程

首先根据url,获取网站的html信息,然后提取出所需的内容

因为网页的编码方式不同,有的中文会编程乱码,所以需要转码
另外提取内容,需要使用正则表达式来匹配

转码

引用包
go get golang.org/x/text
使用transform.NewReader新建一个utf8编码的Reader,需要参数io.Reader和网页原本的编码格式
如果网页是GBK编码,可以直接转

//这里resp为使用http.Get("url地址")获取到的,resp.body为一个Reader
utf8Reader := transform.NewReader(resp.body,simplifiedchinese.GBK.NewDecoder())

但如果不知道原网页是什么编码格式,就需要识别一下
引用包
go get golang.org/x/net/html
使用charset.DetermineEncoding方法获取编码格式

//取出原本Reader的前1024个字节新建一个Reader,然后识别
r,_ := bufio.NewReader(resp.body).Peek(1024)
//当网页编码格式为GBK时,这里的e就相当于之前的simplifiedchinese.GBK
e := charset.DetermineEncoding(r,"")

正则表达式

使用regexp.Compile来匹配

格式
.代表任意字符
*代表0到多个
代表1到多个
[a-z]代表所有小写字母
[A-Z]代表所有大写字母
[0-9]代表所有数字
[^>]代表不为>的字符
[\s]代表任意空白字符

const origen string = "原始内容"
const content string = `匹配内容`
//如果能够确保匹配到,可以使用MustCompile方法
r,_ := regexp.Compile(content)
//FindAll传入的是[]byte,返回的是[][]byte,如果想要string,可以使用FindAllString
m := r.FindAll(origen,-1)

具体实现

首先需要根据url获取网页内容,可以将这一部分封装到一个包中

package fetcher
import (
	"bufio"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"

	"golang.org/x/net/html/charset"
	"golang.org/x/text/encoding"
	"golang.org/x/text/encoding/unicode"
	"golang.org/x/text/transform"
)
//获取网页内容的函数
func Fetch(url string) ([]byte,error){
	resp,err := http.Get(url)
	if err != nil{
		return nil,err
	}
	defer resp.body.Close()
	if resp.StatusCode != http.StatusOK{
		return nil,fmt.Errorf("fetch error no statusok")
	}
	//获取网页编码格式
	e := determineEncoding(resp.body)
	utf8Reader :=  transform.NewReader(resp.body,e.NewDecoder())
	b,err := ioutil.ReadAll(utf8Reader)
	if err != nil{
		return nil,err
	}
	return b,nil
}

func determineEncoding(i io.Reader) encoding.Encoding{
	//先取出前1024个自己新建一个Reader
	re,err := bufio.NewReader(i).Peek(1024)
	if err != nil{
		log.Printf("error : %v",err)
		return unicode.UTF8
	}
	//获取Reader的编码格式
	e,_,_ := charset.DetermineEncoding(re,"")
	return e
}
学新通

然后需要定义一些类型,来存储入参和出参
提取网页内容的函数返回结果是一个url和一个内容,这个url还会继续被用来爬取,但是提取方法不一样,因此可以将返回结果的属性设为一个requests和一个items,request中又包括url和具体的提取方法parseFunc

package engine

type Request struct{
	URL string
	ParseFunc func(content []byte) ParseResult
}

type ParseResult struct{
	Requests []Request
	//[]interface{}代表任意类型
	Items []interface{}
}

//这里是一个空的提取方法,因为这篇文章只会先写第一层的提取方法,所以在进行下一层提取时,先传一个空的提取方法
func NilParseFunc(content []byte) ParseResult{
	return ParseResult{}
}
学新通

第一层提取方法的实现

package parser

const con string = `<a href="https://blog.csdn.net/m0_46606984/article/details/([^"]*)"[\s][^>]*>([^<]*)`

func ParseCityList(content []byte) engine.ParseResult{
	r,_ := regexp.Compile(con)
	m := r.FindAll(content,-1)
	var result engine.ParseResult
	for _,mm := range m{
		//这里使用string(mm[2]),是为了后面打印出来直接可以用%s
		result.Items = append(result.Items,string(mm[2]))
		result.Requests = append(result.Requests,engine.Request{mm[1],engine.NilParseFunc})
	}
	return result
}

具体的运行方法

package engine

func Run(seeds ...Request){
	var requests []Request
	for s := range seeds{
		requests = append(requests,s)
	}
	for len(requests) > 0{
		r := requests[0]
		requests = requests[1:]
		b,_ := fetcher.Fetch(r.URL)
		result := r.ParseFunc(b)
		for _,m := range result.Items{
			fmt.Printf("%s\n",m)
		}
	}
}
学新通

在main函数中直接调用运行方法Run

package main

const url string = "localhost:8080/zhenai"

func main(){
	engine.Run(engine.Request{url,parser.ParserCityList})
}

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgefagb
系列文章
更多 icon
同类精品
更多 icon
继续加载