当我们成功向网站发送HTTP请求的时候,网站会给回我们响应的网页内容。网页内容以HTML代码形式表示,因此我们需要从HTML代码中提取目标数据。
数据清洗方式大致分为三种:字符串操作(截取,替换等操作)、正则表达式和HTML解析。字符串操作和正则表达式就不再详细讲述,这属于Goland的基础语法,本文重点讲述GoLand的HTML解析。
GoLand常用的HTML解析有第三包goquery,在CMD窗口输入安装指令即可。

go get github.com/PuerkitoBio/goquery

goquery定义多种方法从HTML里获取目标数据,本文只讲述最常用的数据清洗提取方法,其他的数据清洗提取方法可以参考官方文档
我们将上一节的响应内容作为源数据,详情参考:GoLand—爬虫入门基础—模拟发送HTTP请求。为了区分上一节的内容,我们将模拟发送HTTP请求改为函数SendHttp发送,数据清洗写在main函数,整段代码如下所示。

package main

import (
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/axgle/mahonia"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"time"
)

//使用第三方mahonia实现网页内容的转码
func ConvertToString(src string, srcCode string, tagCode string) string {
	srcCoder := mahonia.NewDecoder(srcCode)
	srcResult := srcCoder.ConvertString(src)
	tagCoder := mahonia.NewDecoder(tagCode)
	_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
	result := string(cdata)
	return result
}

// 使用映射传递函数参数,requestMode作为HTTP的请求方式
func SendHttp(urls string, method string, rawurl string, cookie []http.Cookie)string{
	req, _ := http.NewRequest(method ,urls, nil)
	//为请求对象NewRequest设置请求头
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36")

	//设置Cookies信息
	if cookie != nil {
		for _, v := range cookie{
			req.AddCookie(&v)
		}
	}

	//设置代理IP,代理IP必须以为fun形式表示
	client := &http.Client{}
	if rawurl != "" {
		proxy := func(_ *http.Request) (*url.URL, error) {
			return url.Parse(rawurl)
		}
		transport := &http.Transport{Proxy: proxy}
		//在Client对象设置参数Transport即可实现代理IP
		client.Transport = transport
	}

	//执行HTTP请求
	resp, _ := client.Do(req)

	//读取响应内容
	body, _ := ioutil.ReadAll(resp.Body)
	//将响应内容转换utf-8编码
	result := ConvertToString(string(body), "gbk", "utf-8")
	//输出网页内容
	return result

	//输出响应内容的Cookies信息
	//for _, v := range resp.Cookies() {
	//	fmt.Println(v)
	//}
}

func main() {
	urls := "https://search.51job.com/list/030200,000000,0000,00,9,99,python,2,1.html"
	method := "GET"
	//rawurl := "http://111.231.93.66:8888"
	rawurl := ""
	var cookie []http.Cookie
	c := http.Cookie{Name: "clientcookieid", Value: "121", Expires: time.Now().Add(111 * time.Second)}
	cookie = append(cookie, c)
	result := SendHttp(urls, method, rawurl, cookie)
	fmt.Println(result)

	// 使用第三包goquery读取HTML代码,读取方式有多种,如下所示:
	// NewDocumentFromReader:读取字符串的HTML代码
	// NewDocumentFromResponse:读取HTML代码对象,即net/http生成的响应内容resp.Body
	// NewDocument:从网址中直接读取HTML代码
	dom, _ := goquery.NewDocumentFromReader(strings.NewReader(result))

	// Find函数是查找HTML里面所有符合要求的标签。
	// 如果查找Class="t1"的标签,则Find(".t1");如果查找id="t1"的标签,则Find("#t1")
	// 如果有多个标签使用同一个Class,比如div和p标签使用Class="t1",若只需定义div标签,可以使用Find("div[class=t1]")
	dom.Find(".t1 ").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(strings.TrimSpace(selection.Text()))
	})

	// 通过多层HTML标签查找,只需在Find里面设置多层标签的Class属性即可
	// 首先查找Class="el"的标签,然后在Class="el"的标签里查找Class="t2"的标签
	// 再从Class="t2"的标签查找标签a,因此查找方式为Find(".el .t2 a"),每个标签之间使用空格隔开
	dom.Find(".el .t2 a").Each(func(i int, selection *goquery.Selection) {
		// 获取数据
		fmt.Println(strings.TrimSpace(selection.Text()))
		// 获取数据所在HTML代码
		fmt.Println(selection.Html())
		// 使用Attr获取数据所在HTML代码的href属性
		v, _ := selection.Attr("href")
		fmt.Println(v)
		// 使用AttrOr获取数据所在HTML代码的href属性
		fmt.Println(selection.AttrOr("href", ""))
	})
}


在main函数中,调用函数SendHttp,函数的返回值为result,这是网页的HTML代码,并以字符串的形式表示。然后使用goquery.NewDocumentFromReader解析网页的HTML代码,生成dom对象。最后由dom对象调用Find函数实现目标数据的定位。Find函数调用Each函数可以将符合条件的标签进行遍历,整个使用方式如下

dom.Find(".t1 ").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(strings.TrimSpace(selection.Text()))
	})

其中函数参数func(i int, selection *goquery.Selection是固定的,参数i是当前遍历的次数,参数selection是定位后的目标数据,然后由selection对象调用Text、Html、Attr或AttrOr可以获取目前数据的文本内容、HTML标签和标签属性。(selection对象还可以使用Find函数实现下一级的标签查找)
上述代码中,分别获取职位名、公司名称和公司信息页的URL地址,如图所示
GoLand—爬虫入门基础—数据清洗(goquery)-LMLPHP
本博文只简单讲述第三包goquery的使用,如果想了解详细的使用方法可以参考,下一节将讲述如何读取和解析JSON数据。

08-31 15:52