Chapter 14 JSON与CSV
json和csv是我们经常打交道的两种数据格式,girlfriend提供了内置插件对它们进行了读写支持。
JSON
读取不同格式的json文件
json格式的用途五花八门,有时候用来做配置文件,有时候用来做序列化。因为用途广泛,所以表现形式往往很多,girlfriend提供了read_json
插件来作为读取json的工具,read_json
可以支持本地文件和从web地址读取两种方式,同时它还支持许多常见的json表现形式。
按行读取
如果你的json文件是一行一个对象的形式,比如:
{"id": 1, "name": "Sam", "gender": "male"}
{"id": 2, "name": "Jack", "gender": "female"}
{"id": 3, "name": "James", "gender": "male"}
...
这种形式就可以使用按行读取的方式进行操作:
from girlfriend.plugin.json import JSONR
...
Job(
name="read_json",
args=[
JSONR(
path="jsonfile.json",
style="line",
),
]
)
或者
from girlfriend.plugin.json import JSONR
...
Job(
name="read_json",
args=[
JSONR(
path="http://www.hehe.com/jsonfile.json",
style="line",
),
]
)
read_json
插件接受一组JSONR对象作为参数,每个JSONR代表了一个要解析的JSON文件或URL地址,style表示json的形式,line表示每行都是一个json对象,解析后的结果为一个list,其中的元素就是每行解析后的字典对象。
如果你不想要字典对象,而是想包装成为自定义的对象,那么你可以指定record_handler参数,该参数接受一个函数,在该函数中将字典转换为目标对象后返回即可。
如果你想过滤掉其中的一些记录不加入到最终的分析结果,那么可以使用record_filter,比如,只保留男性:
Job(
name="read_json",
args=[
JSONR(
path="http://www.hehe.com/jsonfile.json",
style="line",
record_filter=lambda record: record["gender"] == "male",
record_handler=mapper
),
]
)
当你要处理的json数据非常的庞大时,按行解析是最好的方式,因为这种解析方式不会将整个json数据加载到内存,你可以筛选整理出自己所需要的。其它的文件格式则不保证这一点。
按块读取
这种情况通常用于配置文件,为了美观,我们会将一个json对象散布到多行,比如:
# id 1
{
"id": 1,
"name": {
"first": "Sam",
"last": "Chi"
}
}
# id 2
{
"id": 2,
"name": {
"first": "Bill",
"last": "Gates",
}
}
通过将style参数设置为block可以支持这种json文件格式,read_json
会去尝试匹配一个最完整的json块作为一条记录。中间无关的字符串如"# id 1 # id 2"也会被自动忽略。
按数组读取
如果你的json文件是一个数组,那么通过将style设置成array可以使得数组中每个元素作为一条记录来被处理。
[
{
"id": 1,
"name": {
"first": "Sam",
"last": "Chi"
}
},
{
"id": 2,
"name": {
"first": "Bill",
"last": "Gates",
}
}
]
提取属性
如果你要处理的部分是json对象中的某个属性,那么你可以将style指定为extract:property_name。
{
"id": 1,
"name": "SamChi",
"fav_books": {
"total": 2,
"books": [
{
"title": u"白夜行",
"author": u"东野圭吾"
},
{
"title": u"陆小凤传奇"
"author": u"古龙"
}
]
}
}
如果我们只是要分析最内层的books这个列表,那么只需要将style指定为extract:fav_books.books
即可。
按不同格式写入JSON文件
使用write_json
插件可以将上下文中的对象以数组、json对象或者按行的方式去写入。
from girlfriend.plugin.json import JSONW
...
Job(
name="write_json",
args=[
JSONW(
path="输出文件路径,如果指定了variable,那么该参数可以不指定",
style="line", # 还可以是object或者array
object="要写入的对象或者上下文变量名",
variable="将json序列化结果同时保存到上下文指定变量。"
)
]
)