current position:Home>[Python crawler] 7. JSON and JsonPATH for structured data extraction

[Python crawler] 7. JSON and JsonPATH for structured data extraction

2022-11-08 09:32:17Deng Dashuai


往期内容提要:


一、非结构化数据与结构化数据

一般来讲对我们而言,需要抓取的是某个网站或者某个应用的内容,提取有用的价值.内容一般分为两部分,非结构化的数据 和 结构化的数据.

  • 非结构化数据:先有数据,再有结构.
  • 结构化数据:先有结构、再有数据.
  • 不同类型的数据,我们需要采用不同的方式来处理.
处理方式非结构化数据结构化数据
正则表达式文本、电话号码、邮箱地址、HTML 文件XML 文件
XPathHTML 文件XML 文件
CSS选择器HTML 文件XML 文件
JSON PathJSON 文件
转化成Python类型JSON 文件(json类)、XML 文件(xmltodict)

After introducing regular expressions、XPath、CSS选择器后,We finally learn about structured data extraction in the data extraction sectionJSON与JsonPATH.

二、了解JSON

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写.同时也方便了机器进行解析和生成.适用于进行数据交互的场景,比如网站前台与后台之间的数据交互.

JSON和XML的比较可谓不相上下.

Python 2.7中自带了JSON模块,直接import json就可以使用了.

官方文档:http://docs.python.org/library/json.html

json简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构

  1. 对象:对象在js中表示为{ }括起来的内容,数据结构为 { key:value, key:value, ... }的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象这几种.

  2. 数组:数组在js中是中括号[ ]括起来的内容,数据结构为 ["Python", "javascript", "C++", ...],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种.

import-jsonjson 模块提供了四个功能:dumpsdumploadsload,用于字符串 和 python数据类型间进行转换.

在这里插入图片描述

方法功能
json.loads把Json格式字符串解码转换成Python对象
json.dumps实现python类型转化为json字符串,返回一个str对象 把一个Python对象编码转换成Json字符串
json.load读取文件中json形式的字符串元素 转化成python类型
json.dump将Python内置类型序列化为json对象后写入文件

(1) json.loads()

把Json格式字符串解码转换成Python对象

# json_loads.py

import json

strList = '[1, 2, 3, 4]'

strDict = '{"city": "北京", "name": "大猫"}'

json.loads(strList)
# [1, 2, 3, 4]

json.loads(strDict) # json数据自动按Unicode存储
# {u'city': u'\u5317\u4eac', u'name': u'\u5927\u732b'}

(2) json.dumps()

实现python类型转化为json字符串,返回一个str对象把一个Python对象编码转换成Json字符串

# json_dumps.py

import json
import chardet

listStr = [1, 2, 3, 4]
tupleStr = (1, 2, 3, 4)
dictStr = {
    "city": "北京", "name": "大猫"}

json.dumps(listStr)
# '[1, 2, 3, 4]'
json.dumps(tupleStr)
# '[1, 2, 3, 4]'

# 注意:json.dumps() 序列化时默认使用的ascii编码
# 添加参数 ensure_ascii=False 禁用ascii编码,按utf-8编码
# chardet.detect()返回字典, 其中confidence是检测精确度

json.dumps(dictStr)
# '{"city": "\\u5317\\u4eac", "name": "\\u5927\\u5218"}'

chardet.detect(json.dumps(dictStr))
# {'confidence': 1.0, 'encoding': 'ascii'}

print json.dumps(dictStr, ensure_ascii=False)
# {"city": "北京", "name": "大刘"}

chardet.detect(json.dumps(dictStr, ensure_ascii=False))
# {'confidence': 0.99, 'encoding': 'utf-8'}

chardet是一个非常优秀的编码识别模块,可通过pip安装

(3) json.load()

读取文件中json形式的字符串元素 转化成python类型

# json_load.py

import json

strList = json.load(open("listStr.json"))
print strList

# [{u'city': u'\u5317\u4eac'}, {u'name': u'\u5927\u5218'}]

strDict = json.load(open("dictStr.json"))
print strDict
# {u'city': u'\u5317\u4eac', u'name': u'\u5927\u5218'}

(4) json.dump()

将Python内置类型序列化为json对象后写入文件

# json_dump.py

import json

listStr = [{
    "city": "北京"}, {
    "name": "大刘"}]
json.dump(listStr, open("listStr.json","w"), ensure_ascii=False)

dictStr = {
    "city": "北京", "name": "大刘"}
json.dump(dictStr, open("dictStr.json","w"), ensure_ascii=False)

(5) Json豆瓣爬虫

# coding=utf-8
import requests
import json

class DoubanSpider:
    def __init__(self):
        self.url_temp_list = [
            {
    
                "url_temp": "https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_american_hot/items?start={}&count=18&loc_id=108288",
                "country": "US"
            },
            {
    
                "url_temp": "https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_english_hot/items?start={}&count=18&loc_id=108288",
                "country": "UK"
            },
            {
    
                "url_temp": "https://m.douban.com/rexxar/api/v2/subject_collection/filter_tv_domestic_hot/items?start={}&count=18&loc_id=108288",
                "country": "CN"
            }
        ]
        self.headers = {
    
            "User-Agent": "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Mobile Safari/537.36"}

    def parse_url(self, url):  # 发送请求,获取响应
        print(url)
        response = requests.get(url, headers=self.headers)
        return response.content.decode()

    def get_content_list(self, json_str):  # 提取是数据
        dict_ret = json.loads(json_str)    # 将json文件转化为Python文件
        content_list = dict_ret["subject_collection_items"]
        total = dict_ret["total"]
        return content_list, total

    def save_content_list(self, content_list,country):  # 保存
        with open("douban.txt", "a", encoding="utf-8") as f:
            for content in content_list:
                content["country"] = country
                f.write(json.dumps(content, ensure_ascii=False))
                f.write("\n")  # 写入换行符,进行换行
        print("保存成功")

    def run(self):  # 实现主要逻辑
        for url_temp in self.url_temp_list:
            num = 0
            total = 100  # 假设有第一页
            while num < total + 18:
                # 1.start_url
                url = url_temp["url_temp"].format(num)
                # 2.发送请求,获取响应
                json_str = self.parse_url(url)
                # 3.提取是数据
                content_list, total = self.get_content_list(json_str)

                # 4.保存
                self.save_content_list(content_list,url_temp["country"])
                # if len(content_list)<18:
                # break
                # 5.构造下一页的url地址,进入循环
                num += 18

if __name__ == '__main__':
    douban_spider = DoubanSpider()
    douban_spider.run()
    

三、JsonPath

JsonPath 是一种信息抽取类库,是从JSON文档中抽取指定信息的工具,提供多种语言实现版本,包括:Javascript, Python, PHP 和 Java.

JsonPath 对于 JSON 来说,相当于 XPATH 对于 XML.

下载地址:https://pypi.python.org/pypi/jsonpath

安装方法:点击Download URL链接下载jsonpath,解压之后执行python setup.py install

官方文档:http://goessner.net/articles/JsonPath

(1) JsonPath与XPath语法对比:

Json结构清晰,可读性高,复杂度低,非常容易匹配,下表中对应了XPath的用法.

XPathJSONPath描述
/$根节点
.@现行节点
/.or[]取子节点
..n/a取父节点,Jsonpath未支持
//..就是不管位置,选择所有符合条件的条件
**匹配所有元素节点
@n/a根据属性访问,Json不支持,因为Json是个Key-value递归结构,不需要.
[][]迭代器标示(可以在里边做简单的迭代操作,如数组下标,根据内容选值等)
|[,]支持迭代器中做多选.
[]?()支持过滤操作.
n/a()支持表达式计算
()n/a分组,JsonPath不支持

(2) 示例:

我们以Lagou net cityJSON文件 为例,获取所有城市.

# jsonpath_lagou.py

import requests
import jsonpath
import json
import chardet

url = 'http://www.lagou.com/lbs/getAllCitySearchLabels.json'
response = equests.get(url)
html = response.text

# 把json格式字符串转换成python对象
jsonobj = json.loads(html)

# 从根节点开始,匹配name节点
citylist = jsonpath.jsonpath(jsonobj,'$..name')

print citylist
print type(citylist)
fp = open('city.json','w')

content = json.dumps(citylist, ensure_ascii=False)
print content

fp.write(content.encode('utf-8'))
fp.close()

后期内容提要:


如果您有任何疑问或者好的建议,期待你的留言与评论!

copyright notice
author[Deng Dashuai],Please bring the original link to reprint, thank you.
https://en.pythonmana.com/2022/312/202211080910333640.html

Random recommended