热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JavaScript中的JSON转为Python可读取

本文主要介绍了JavaScript中的JSON转为Python可读取,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的

创作背景

最近本菜鸡在爬一个网站的时候,意外发现所需 JSON 数据在页面前端,但是不易提取,写下此篇博客以记录解决方案。

问题再现

数据是通过 JS 代码传递的,大致格式(仅 作举例说明 ,方便查看层次,实际 在同一行 )如下:

function (a, b, c, d){
    return {
        title: a,
        data: [
            {
            	data: b
        	},
            {
                data: c
            },
            {
                data: d
            }
    	]
    }
}("title", 2, 3, 4)

我要提取的是整个 JSON 格式的数据。

如果要直接提取,可以使用

re.findall("return ({.*?})}(", content)

得到结果,但如果要解析数据,会报以下的错:

请添加图片描述

意思是:键值对中的键需要被双引号包含

所以我们要完成任务的话,需要解决以下问题:

  • 键需要用 "" 包含。
  • 需要将形式参数 a, b, c, d 转化为实际参数 "title", 2, 3, 4

解决办法

形参与实参的对应关系容易解决,所以先解决这个问题。

形参与实参对应关系

可以使用以下代码得到 形式参数

"".join(re.findall("function((.*?)){", content)).split(",")

使用下述代码获得 实际参数

"".join(re.findall("}((.*?))", content)).split(",")

因为 形式参数实际参数个数 一样,所以可以根据 列表索引 建立对应关系,使用 np.c_ 可以进行 列表横向合并

代码如下:

# 获得实际参数Argument = "".join(re.findall("}((.*?))", content)).split(",")# 获得形式参数Formal_parameter = "".join(re.findall("function((.*?)){", content)).split(",")# 建立对应关系mapping = pd.DataFrame(np.c_[Formal_parameter, Argument])# 以形参作为索引mapping.set_index(0, drop=True, inplace=True)

结果如下:

请添加图片描述

格式化 JSON

要解决这个问题,我们需要先提取出 JSON 字符串,代码如下:

string = "".join(re.findall("return ({.*?})}(", content))

结果如下:

请添加图片描述

然后,我们需要有个思路,如下:

  • {, 后边,: 之前的部分是 ,需要加上双引号。
  • :[{ 后边,], 之前的部分都是 ,需要识别且替换。

给键加上双引号

因为涉及到 插入元素Python 中只有 列表 能担此重任,所以我们需要先 将字符串转为列表 ,代码如下:

string = list("".join(re.findall("return ({.*?})}(", content)))

然后,我们需要设置一个变量,当识别出是 的时候就 1 ,否则为 0

key_flag = 0

如果我们按照上文中的规则识别出 ,就要从当前位开始,一直到 : 之前的这部分都用 双引号 包含。

还有些特殊情况,比如

  • 嵌套字典 ,比如一个列表中值均为字典 。
  • 空字典{ 后边是 }

考虑到特殊情况,代码如下:

index = 0

while True:
    # 如果索引超出范围,就跳出循环
    if index >= len(string):
        break
    # 给键加双引号
    if key_flag:
        # 在当前位插入一个双引号
        string.insert(index, """)
        index += 1
        # 循环读取 
        while True:
            # 直到出现 ":",循环读取的部分为 键
            # 在 键 的最后添加一个双引号
            if string[index] == ":":
                string.insert(index, """)
                # 重置 key_flag
                key_flag = 0
                # 终止循环
                break
            # 读取下一位
            index += 1
    # 当前字符为 "{" 或 ",",则后边的为 键
    if string[index] in "{,":
        key_flag = 1
        # 嵌套时,则将索引移向下一位
        if string[index+1] in "{":
            index += 1
        # 如果为空字典,则重置 key_value
        if string[index+1] in "}":
            key_flag = 0
    
    index += 1

结果如下(因篇幅限制,代码无法截全):

请添加图片描述

可以看到,已经将所有的键用双引号包含。

识别且替换值

这一部分还是小有难度的。

首先,和上边一样,我们还是需要一个变量,记录当前识别 的状态,1 代表识别出来了,0 代表没有。

value_flag = 0

不过也是有特殊情况:

  • 值已经是字符串 ,但 字符串中有 :
  • 值是 js 语句 ,不过其不是我们要提取的数据。

考虑到特殊情况,代码如下:

while True:
    
    if index >= len(string):
        break
    # 检测到 值
    if value_flag:
        # 取出当前字符
        value = string.pop(index)
        # 如果字符是数字、"[" 和 "{" 或者已经是字符串
        if value in ""1234567890[{" or is_value:
            value_flag = 0
            string.insert(index, value)
            index += is_value
        # 不符合上述情况
        else:
            # 循环取出 值 字符串
            while True:
                # 如果为 "," 或 "}",则代表已取完
                if string[index] in ",}":
                    break
                value += string.pop(index)
            # 如果 值 字符串在对应关系中,就替换
            if value in mapping.index:
                # 因为是在当前位不断插入,所以要将数据反向
                trans = mapping.loc[value][::-1]
            # 如果不在,则直接替换成空字符串
            else:
                trans = """"
            # 计算索引要移动几位
            length = len(trans)
            # 插入对应的数据
            for c in trans:
                string.insert(index, c)
            # 索引移动
            index += length
            
            value_flag = 0
            
            continue
    # 如果识别到 ":" 且该 ":" 不在值字符串中
    if string[index] in ":" and not is_value:
        value_flag = 1
        # 如果是值是字符串,则设置 is_value
        if string[index+1] in """:
            is_value = 1
    # 识别值字符串结束,并重置 is_value
    elif string[index] in """ and is_value:
        is_value = 0

    index += 1

结果如下:

请添加图片描述

可以看到,转换的还是挺成功的。

总代码

cOntent= """
function(a,b,c,d){return {title:a,data:[{data:b},{data:c},{data:d}]}}("title",2,3,4)
"""

string = list("".join(re.findall("return ({.*?})}(", content)))

is_value = 0
key_flag = 0
value_flag = 0

index = 0

while True:
    
    if index >= len(string):
        break
    
    if key_flag:
        
        string.insert(index, """)
        index += 1
        
        while True:
            if string[index] == ":":
                string.insert(index, """)
                key_flag = 0
                break
            index += 1
            
    elif value_flag:
        
        value = string.pop(index)
        
        if value in ""1234567890[{" or is_value:
            value_flag = 0
            string.insert(index, value)
            index += is_value
        else:
            
            storage = index
            
            while True:
                if string[index] in ",}":
                    break
                value += string.pop(index)
            
            if value in mapping.index:
                trans = mapping.loc[value][::-1]
            else:
                trans = """"
            length = len(trans)

            for c in trans:
                string.insert(index, c)

            index += length
            
            value_flag = 0
            
            continue
    
    if string[index] in "{,":
        key_flag = 1
        if string[index+1] in "{":
            index += 1
        if string[index+1] in "}":
            key_flag = 0

    elif string[index] in ":" and not is_value:
        value_flag = 1
        if string[index+1] in """:
            is_value = 1
    
    elif string[index] in """ and is_value:
        is_value = 0

    index += 1
    
"".join(string)

结果如下:

请添加图片描述

这时候就可以使用 json.loads 来提取数据了。

结果如下:

请添加图片描述

不足

其实上述代码是有不足的地方的。因为这段 js 代码是特殊的,是 在一行 ,且 没有多余的空格

不过也是有解决办法的:

如果 有空格 怎么办? —> 在 提取形参使用形参转换实参 时使用 strip 去除两侧的空格即可。

代码不在一行 怎么办? —> 使用 .replace(' ', '').replace(' ', '') 去除 换行符制表符 ,然后再进行格式化工作。

其实如果只是 代码不在一行 的问题的话,js.loads 会帮我们去除 之类的,直接提取重要部分。

不过如果要使用我的代码的话,目前只支持 在一行js 代码。

还有就是有些 将键值对的值设置成逻辑运算式 ,比如 a || "" 这种,也不太好提取,还得根据问题调整。

这些都只是思路,大家可以自行尝试,如果有问题也及时提出来。

到此这篇关于Javascript中的JSON转为Python可读取的文章就介绍到这了,更多相关Javascript JSON转为Python内容请搜索编程笔记以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程笔记!


推荐阅读
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 006_Redis的List数据类型
    1.List类型是一个链表结构的集合,主要功能有push,pop,获取元素等。List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,List的设 ... [详细]
  • Python的参数解析argparse模块的学习
    本文介绍了Python中参数解析的重要模块argparse的学习内容。包括位置参数和可选参数的定义和使用方式,以及add_argument()函数的详细参数关键字解释。同时还介绍了命令行参数的操作和可接受数量的设置,其中包括整数类型的参数。通过学习本文内容,可以更好地理解和使用argparse模块进行参数解析。 ... [详细]
  • 本文介绍了使用C++Builder实现获取USB优盘序列号的方法,包括相关的代码和说明。通过该方法,可以获取指定盘符的USB优盘序列号,并将其存放在缓冲中。该方法可以在Windows系统中有效地获取USB优盘序列号,并且适用于C++Builder开发环境。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • Java学习笔记之使用反射+泛型构建通用DAO
    本文介绍了使用反射和泛型构建通用DAO的方法,通过减少代码冗余度来提高开发效率。通过示例说明了如何使用反射和泛型来实现对不同表的相同操作,从而避免重复编写相似的代码。该方法可以在Java学习中起到较大的帮助作用。 ... [详细]
  • 本文介绍了在使用Laravel和sqlsrv连接到SQL Server 2016时,如何在插入查询中使用输出子句,并返回所需的值。同时讨论了使用CreatedOn字段返回最近创建的行的解决方法以及使用Eloquent模型创建后,值正确插入数据库但没有返回uniqueidentifier字段的问题。最后给出了一个示例代码。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • {moduleinfo:{card_count:[{count_phone:1,count:1}],search_count:[{count_phone:4 ... [详细]
  • 工作经验谈之-让百度地图API调用数据库内容 及详解
    这段时间,所在项目中要用到的一个模块,就是让数据库中的内容在百度地图上展现出来,如经纬度。主要实现以下几点功能:1.读取数据库中的经纬度值在百度上标注出来。2.点击标注弹出对应信息。3 ... [详细]
  • 获取时间的函数js代码,js获取时区代码
    本文目录一览:1、js获取服务器时间(动态)2 ... [详细]
  • mapreduce源码分析总结
    这篇文章总结的非常到位,故而转之一MapReduce概述MapReduce是一个用于大规模数据处理的分布式计算模型,它最初是由Google工程师设计并实现的ÿ ... [详细]
author-avatar
ljp3044544
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有