之前的内容已经写好了获取网站内容的函数fetch,爬取第一层城市列表的解析器ParseCityList函数,以及实际爬取的函数Run(传入种子,包含url和解析器,根据url,调用解析器解析)
基本的框架就是这样,后面只需要再分别写不同的解析器就好了
//首先写好匹配的正则表达式
citys := `([^<]+)`
func ParseCity(content []byte) engine.ParseResult{
cityRe := regexp.Compile(citys)
var result = engine.ParseResult{}
b := cityRe.FindAllStringSubmatch(string(content),-1)
for bb := range b{
result.Item = append(result.Item,bb[1])
//这里ParseProfile是下一层的解析器,实际上之前城市列表解析器的这里应该改成该解析器ParseCity
result.Requests = append(result.Requests,engine.Request{URL:bb[0] PaserFunc:ParseProfile})
}
return result
}
因为用户的信息是我们爬取信息的根本目的,信息比较丰富,所以我们需要单独定义一个结构体来存储用户的信息
package models
type Profiles struct {
Name string
Age int
Height int
Weight int
Income string
MerrageState string
EducationSituation string
Profession string
JiGuan string
Sex string
Xingzuo string
Housing string
Caring string
ExpectSize string
}
具体的用户解析器
//因为要解析的内容比较多,先将*regexp赋好值
var ageRe := regexp.Compile(`年龄:([0-9]+)岁 `)
var heightRe, _ = regexp.Compile(`身高:([0-9^C]+)CM `)
var weightRe, _ = regexp.Compile(`体重:([0-9^K]+)KG `)
var incomeRe, _ = regexp.Compile(`月收入:([^<]+) `)
var merrageStateRe, _ = regexp.Compile(`婚况:([^<]+) `)
var educationSituationRe, _ = regexp.Compile(`学历:([^<]+) `)
var xingzuoRe, _ = regexp.Compile(`星座:([^<]+) `)
var professionRe, _ = regexp.Compile(`职业:([^<]+) `)
var jiGuanRe, _ = regexp.Compile(`籍贯:([^<]+) `)
var sexRe, _ = regexp.Compile(`性别:([^<]+) `)
var housingRe, _ = regexp.Compile(`住房条件:([^<]+) `)
var caringRe, _ = regexp.Compile(`是否购车:([^<]+) `)
var expectSizeRe, _ = regexp.Compile(`体型:([^<]+) `)
//直接定义一个函数返回匹配到的内容
func Get(reg *regexp.Regexp,content []byte) string{
//因为只取一个值,所以不使用findall函数了
m := reg.FindStringSubmatch(content)
if len(m) >= 1{
//m[0]匹配到的是整个内容,m[1]是括起来的内容,也就是具体的用户信息
return m[1]
}else{
return ""
}
}
//解析器
//这里多出一个参数,接收上一层传过来的名字,但就不符合定义好的解析器函数类型了
//所以在上一层解析器中需要修改一下,创建一个匿名函数,然后在其中调用该函数
func ParseProfile(content []byte,name string)engine.ParseResult{
//定义一个实体用来接收数据
var profile models.Profiles
//对于想要整数型的数据,转一下类型
age,err := strconv.Atoi(Get(content,ageRe))
if err != nil{
age = 0
}
height,err := strconv.Atoi(Get(content,heightRe))
if err != nil{
height = 0
}
weight, err := strconv.Atoi(Get(weightRe, content))
if err != nil {
weight = 0
}
profile.Name = name
profile.Age = age
profile.Height = height
profile.Weight = weight
profile.Income = Get(incomeRe, content)
profile.MerrageState = Get(merrageStateRe, content)
profile.EducationSituation = Get(educationSituationRe, content)
profile.Xingzuo = Get(xingzuoRe, content)
profile.Profession = Get(professionRe, content)
profile.JiGuan = Get(jiGuanRe, content)
profile.Sex = Get(sexRe, content)
profile.Housing = Get(housingRe, content)
profile.Caring = Get(caringRe, content)
profile.ExpectSize = GetSecondTixing(expectSizeRe, content)
var result engine.ParseResult
result.Item = append(result.Item, profile)
return result
}
//对于有多个相似内容的情况下,想要只取最后一个,新定义一个函数
func GetSecondTixing(reg *regexp.Regexp, content []byte) string {
m := reg.FindAllStringSubmatch(string(content), -1)
if len(m) >= 2 {
if len(m[len(m)-1]) >= 2 {
return m[len(m)-1][1]
}
return ""
} else {
return ""
}
}
//修改一下上层解析器
citys := `([^<]+)`
func ParseCity(content []byte) engine.ParseResult{
cityRe := regexp.Compile(citys)
var result = engine.ParseResult{}
b := cityRe.FindAllStringSubmatch(string(content),-1)
for bb := range b{
result.Item = append(result.Item,bb[1])
//这里修改了一下,创建了个匿名函数,里面调用用户解析器的函数
result.Requests = append(result.Requests,engine.Request{URL:bb[0] PaserFunc:func(content []byte)engine.ParseResult{return ParseProfile(content,bb[1])}})
}
return result
}
至此,简单的爬取网站就基本实现了。