GoLang—爬虫—解析JSON数据_golang 爬虫json解析-程序员宅基地

技术标签: 网络爬虫  爬虫  JSON  GoLand  数据处理  GoLang  

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

标准库encoding/json

回顾GoLang—爬虫入门基础—数据清洗(goquery),我们将HTTP发起请求封装在函数SendHttp,主函数main实现函数SendHttp调用和响应内容的数据处理。本文继续沿用上一节的功能代码,将发送HTTP的网址改为12306的余票查询,当我们在网页上输入查询信息并点击查询按钮即触发AJAX请求,如图所示。
在这里插入图片描述
图上的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])
}


运行上述代码,其运行结果如图所示。
在这里插入图片描述
除了可以使用Unmarshal函数来解封 JSON,还可以使用Decoder手动地将 JSON 数据解码到结构里面,以此来处理流式的 JSON 数据(即JSON数据过大的时候),如图所示。
在这里插入图片描述
通过调用NewDecoder并传入一个包含 JSON 数据的io.Reader,程序创建出了一个新的解码器。在把指向Post结构的引用传递给解码器的Decode方法之后,被传入的结构就会填充上相应的数据,然后这些数据就可以为程序所用了。当所有 JSON 数据都被解码完毕时,Decode方法将会返回一个EOF,而程序则会在检测到这个EOF之后退出for循环。

在面对 JSON 数据时,我们可以根据输入决定使用Decoder还是Unmarshal:如果 JSON 数据来源于io.Reader流,如http.Request的Body,那么使用Decoder更好;如果 JSON 数据来源于字符串或者内存的某个地方,那么使用Unmarshal更好。

**除此之外,标准库encoding/json还可以调用函数Marshal或MarshalIndent(MarshalIndent将JSON数据格式化输出,会将数据自动分段分行处理),将特定的数据转化成JSON数据。此外还可以使用Decoder,代码如下。
在这里插入图片描述
程序会创建一个用于存储 JSON 数据的 JSON 文件,并通过把这个文件传递给NewEncoder函数来创建一个编码器。接着,程序会调用编码器的Encode方法,并向其传递一个指向Post结构的引用。在此之后,Encode方法会从结构里面提取数据并将其编码为 JSON 数据,然后把这些 JSON 数据写入创建编码器时给定的 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数据,下一节将讲述如何将爬取的数据进行入库处理。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/HuangZhang_123/article/details/100512207

智能推荐

box-shadow 与 filter:drop-shadow 详解及技巧-程序员宅基地

文章浏览阅读88次。box-shadow 在前端的 CSS 编写工作想必十分常见。但是 box-shadow 除去它的常规用法,其实还存在许多不为人知的奇技淫巧。喜欢 markdown 版本的可以戳这里。box-shadow 常规用法说到 box-shadow ,首先想到的必然是它能够生成阴影,所以称之为 shaodow ,简单看看它的语法:基础属性语法box-sha..._filter: drop-shadow(100px 0 0 $bg-info);

VS2019/VS2017安装源离线下载,更新,清理,企业版与论坛版重复下载-程序员宅基地

文章浏览阅读959次。VS2019.NET Framework 4.8 SDKhttps://dotnet.microsoft.com/download/thank-you/net48-developer-pack.NET Core 3.0https://dotnet.microsoft.com/download/dotnet-core/3.0预览版需要在Options中的Environment..._vs2017安装下载缓存怎么清除

互联网大脑的情绪,智商和梦境-互联网神经学系列第四篇_"互联网大脑如何产生\"梦境\"并形成元宇宙"-程序员宅基地

文章浏览阅读1.3k次。既然互联网正在形成与人类大脑高度相似的组织结构,那么互联网也应该具备心理学现象,显示出喜怒哀乐情绪,智商,知觉、认知,智商等现象。互联网神经心理学(Internet neuropsychology)就是从互联网的类神经结构角度分析互联网大脑的心理学问题,研究互联网是如何反映现实世界信息,如何反映社会关系,如何产生属于互联网大脑的类心理活动。_"互联网大脑如何产生\"梦境\"并形成元宇宙"

安装成功了的ros系统,突然提示未安装ros_catkin : 依赖: python-catkin-pkg 但是它将不会被安装 e: 无法修正错误-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏18次。之前一直用的好好的ros-kinetic,今天输入roscore..提示未安装,试了其他指令,也是未安装 百度了一下没找到同样的问题,记录一下ada@ada-HP-Spectre-x360-Convertible-13-ae0xx:~$ roscore程序“roscore”尚未安装。 您可以使用以下命令安装:sudo apt install python-roslaunch首先想..._catkin : 依赖: python-catkin-pkg 但是它将不会被安装 e: 无法修正错误,因为您要

sql中如何计算百分比 ,并保留两位小数_sql计算百分比保留两位小数-程序员宅基地

文章浏览阅读5.9w次,点赞3次,收藏24次。SELECT CONCAT(CONVERT(COUNT(DISTINCT a)*100/COUNT(DISTINCT b),DECIMAL(18,2)),'%') AS [百分比] FROM 表名CONCAT('a/b','%')代表拼接%decimal(18, 2) 代表截取两位位小数_sql计算百分比保留两位小数

空间几何变换与摄像机模型_如果平面内有一线束的四直线被任一直线所截,则截点列的交比和线束的交比相等。-程序员宅基地

文章浏览阅读778次。空间几何变换:一 1.齐次坐标:由n+1维矢量表示一个n维矢量,用齐次坐标表示的优越性主要有两点,一 提供了用矩阵运算把二维,三维甚至高维空间中的一个点集从一个坐标系变换到另一个坐标系的有效方法。二可以表示无穷远点。2.射影变换是一个最为广义的线性变换,n维射影空间的射影变换可以用代数表示为py = Tpx,其中p为一比例因子,x与y分别为变换前后空间点的齐次坐标,x=(x1,x2........._如果平面内有一线束的四直线被任一直线所截,则截点列的交比和线束的交比相等。

随便推点

web开发中,后台数据获取到了,前端显示不出来_java-web能拿到数据库内的数据但是不能显示在前端-程序员宅基地

文章浏览阅读2.3w次,点赞12次,收藏13次。一开始我以为是后台没有获取到数据,写了几个输出语句测试发现数据是能获取到的,那就是显示的问题,检查了各个属性发现都是对的,后来突然发现我的遍历显示的地方出现了警告,这才注意到,忘记加<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>加了之后立马就显示正常了。..._java-web能拿到数据库内的数据但是不能显示在前端

【渝粤教育】广东开放大学 中国文化文学通论 形成性考核 (25)_《采薇》曾被古人视为《诗经》中最好的篇章。-程序员宅基地

文章浏览阅读341次。选择题题目:《楚辞》是《诗经》以外先秦诗歌的另一部总集。题目:知我者,回答题目:《采薇》曾被古人视为《诗经》中最好的篇章。题目:“楚辞”是战国时期产生于蜀地的一种诗歌样式。题目:《颂》诗包括《周颂》、《鲁颂》和《齐颂》。题目:若有人兮山之阿,回答题目:身既死兮神以灵,回答题目:回答题目:回答题目:《楚辞》是我国古代第一部诗歌总集。题目:“楚辞”最为明显的特征是带有“兮”字的三字句或四字句。题目:宋玉是除屈原以外创作成就最高的“楚辞”作家。题目:回答题目:《诗经》分为《风》、《雅》_《采薇》曾被古人视为《诗经》中最好的篇章。

Solaris 初步设置(转)-程序员宅基地

文章浏览阅读1.3k次。Solaris 初步设置(转)  简介  这篇文档包含了你用solaris和Sun平台工作时所需要的最重要的20%的技术。它能处理你所遇到的80%的问题。  这篇文档并不打算覆盖Solaris处理环境的细节,也不会包..._solaris11 dev/dsk

常见经典目标检测算法-程序员宅基地

文章浏览阅读1.1k次,点赞41次,收藏9次。R-CNN大大提升了目标检测的精度,但速度很慢。此后,Fast R-CNN和Faster R-CNN对原始R-CNN进行了改进,Faster R-CNN通过RPN网络学习提取候选区域,实现了端到端的目标检测。近年来,目标检测技术不断进步,涌现出了许多新的算法和模型,如RetinaNet、RefineDet、CenterNet等,进一步提升了目标检测的精度和效率,使得目标检测在越来越多的应用场景中得到应用。多年来,研究者们提出了许多经典的目标检测算法,下面我们就来介绍几种常见的经典目标检测算法。

vue 事件修饰符_v-on:submit.prevent-程序员宅基地

文章浏览阅读125次。事件修饰符在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。为了解决这个问题, Vue.js 为 v-on 提供了 事件修饰符。通过由点(.)表示的指令后缀来调用修饰符。..._v-on:submit.prevent

多线程情况下保证数据一致的方法_多线程如何保证数据一致性-程序员宅基地

文章浏览阅读1.2w次。多线程情况下,怎样确保对同一变量的改变出现一致性问题 使用synchronized关键字 比如:对num变量进行操作,如果没有synchronized 关键字,即使是使用volatile修饰变量,输出的值也会小于100000,因为volatile虽然能够保证可见性及顺序性,但是不能保证变量的原子性。 private static int num = ..._多线程如何保证数据一致性

推荐文章

热门文章

相关标签