GoLang—爬虫—解析JSON数据

JSON作为一种重要的数据格式,具有良好的可读性以及自描述性,广泛地应用在各种数据传输场景中。在网络爬虫中,当网页采用AJAX方式渲染数据时,我们必须找出AJAX的异步请求方式,并且模拟发送AJAX,从中获取数据内容,AJAX的响应数据大部分采用JSON格式表示。
GoLang可以使用标准库encoding/json解析JSON数据,此外还有第三方包ffjson、easyjson、jsoniter和jsonparser等等。在性能上,第三方包完胜标准库encoding/json,本文将分别讲述标准库encoding/json和第三包jsoniter的使用。

标准库encoding/json

回顾GoLang—爬虫入门基础—数据清洗(goquery),我们将HTTP发起请求封装在函数SendHttp,主函数main实现函数SendHttp调用和响应内容的数据处理。本文继续沿用上一节的功能代码,将发送HTTP的网址改为12306的余票查询,当我们在网页上输入查询信息并点击查询按钮即触发AJAX请求,如图所示。
GoLang—爬虫—解析JSON数据_第1张图片
图上的AJAX请求的响应内容为JSON格式,标准库encoding/json解析JSON有两种方式:根据JSON内容格式定义对应的结构体(struct)、使用map[string]interface{}加载JSON数据。
实际工作中,个人不建议采用根据JSON内容格式定义对应的结构体(struct),当JSON内容格式过于复杂的时候,对应的结构体(struct)会随之增加,这样会增加大量的代码。我们采用使用map[string]interface{}加载JSON数据,实现代码如下。

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)


// 使用映射传递函数参数,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)
	return string(body)

}

func main() {
	urls := "https://kyfw.12306.cn/otn/leftTicket/queryT?leftTicketDTO.train_date=2019-09-17&leftTicketDTO.from_station=SHH&leftTicketDTO.to_station=GZQ&purpose_codes=ADULT"
	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)

	// 定义make(map[string]interface{})
	r := make(map[string]interface{})
	fmt.Println([]byte(result))
	// 调用标准库encoding/json的Unmarshal
	// 将JSON数据(JSON以字符串形式表示)转换成[]byte,并将数据加载到对象r的内存地址
	json.Unmarshal([]byte(result), &r)
	// r["data"]是读取JSON最外层的key
	// 如果嵌套JSON数据,则使用map[string]interface{}读取下一层的JSON数据
	// 如读取key为data里面嵌套的result:r["data"].(map[string]interface{})["result"]
	// 如果JSON的某个key的数据以数组表示,则使用([]interface{})[index]读取数组中某个数据。
	// 如读取key为result的第四个数据:r["data"].(map[string]interface{})["result"].([]interface{})[3]
	fmt.Println(r["data"].(map[string]interface{})["result"].([]interface{})[3])
}


运行上述代码,其运行结果如图所示。
GoLang—爬虫—解析JSON数据_第2张图片
除此之外,标准库encoding/json还可以调用函数Marshal,将特定的数据转化成JSON数据,详细教程参考:请点击

第三包jsoniter

第三包jsoniter是100% 兼容原生库,但是性能超级好,预先缓存了对应struct的decoder实例,然后unsafe.Pointer省掉了一些interface{}的开销,还有一些文本解析上的优化。
首先在CMD里输入第三包jsoniter的安装指令,如下所示:

go get github.com/json-iterator/go

jsoniter的使用方式也相对简单,只需定义ConfigCompatibleWithStandardLibrary对象即可,由该对象调用Unmarshal或Marshal函数即可实现JSON的解析和转换,比如上述代码中,我们只需修改包的引入和定义ConfigCompatibleWithStandardLibrary即可,代码如下

import (
	"fmt"
	"github.com/json-iterator/go"
	"io/ioutil"
	"net/http"
	"net/url"
	"time"
)
……………………(省略相同代码)
func main() {
	……………………(省略相同代码)
	// 定义make(map[string]interface{})
	r := make(map[string]interface{})
	var json = jsoniter.ConfigCompatibleWithStandardLibrary
	json.Unmarshal([]byte(result), &r)
	fmt.Println(r["data"].(map[string]interface{})["result"].([]interface{})[3])
}

如果想要了解第三包jsoniter的实现原理,可以参考官方的Github地址:jsoniter

综合上述,本博文只简单讲述了标准库encoding/json和第三包jsoniter如何解析JSON数据,下一节将讲述如何将爬取的数据进行入库处理。

你可能感兴趣的:(GoLand,爬虫,网络爬虫,JSON,爬虫,数据处理,GoLang)