当前位置: 首页 > news >正文

关于Windows中PyExecjs库中文乱码的解决

正文

废话不多说,直接看下面a.js中的代码

function a() {console.log("你好")return "你好";
}
a()

安装PyExecjs并使用,代码如下

import execjswith open('a.js', encoding='utf-8') as f:data = f.read()ctx = execjs.compile(data)
ret = ctx.call('a')
print(ret)

运行

结果报错,如下

  File "F:\code\Python\study-spider\.venv\Lib\site-packages\execjs\_external_runtime.py", line 88, in _exec_
    return self._extract_result(output)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "F:\code\Python\study-spider\.venv\Lib\site-packages\execjs\_external_runtime.py", line 157, in _extract_result
    output = output.replace("\r\n", "\n").replace("\r", "\n")
             ^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'replace'

笔者去搜了搜,看到一个好的解决办法

其他大佬的解决

Windows中解决execjs的乱码问题_execjs utf-8-CSDN博客https://blog.csdn.net/m0_60642470/article/details/127954981上面这位大佬给出的解决办法是——软改

import subprocess
from functools import partial #用来固定某个参数的固定值
subprocess.Popen=partial(subprocess.Popen,encoding='utf-8')

即,全部代码如下

import subprocess
from functools import partial #用来固定某个参数的固定值
subprocess.Popen=partial(subprocess.Popen,encoding='utf-8')import execjswith open('a.js', encoding='utf-8') as f:data = f.read()ctx = execjs.compile(data)
ret = ctx.call('a')
print(ret)

运行没问题

笔者的解决

首先,先对报错进行思考

AttributeError: 'NoneType' object has no attribute 'replace'

NoneType这个对象没有属性replace,说明output是None,

因此,打个断点,看看堆栈的调用

在execjs对应的文件中_extract_result函数搜索,发现有两个

            if self._tempfile:output = self._exec_with_tempfile(source)else:output = self._exec_with_pipe(source)return self._extract_result(output)

一个本身,一个是调用的地方。

可以发现这个output,来源于_exec_with_tempfile或者_exec_with_pipe

很容易发现output,来源于_exec_with_pipe,打个断点进入_exec_with_pipe函数

        def _exec_with_pipe(self, source):cmd = self._runtime._binary()p = Nonetry:p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=self._cwd, universal_newlines=True)input = self._compile(source)if six.PY2:input = input.encode(sys.getfilesystemencoding())stdoutdata, stderrdata = p.communicate(input=input)ret = p.wait()finally:del pself._fail_on_non_zero_status(ret, stdoutdata, stderrdata)return stdoutdata

如下

观察,可以发现这个cmd是node.exe的路径,而这里面有个关键的东西——Popen

而这个Popen的encoding是cp936,这就明白了

因此,笔者有两个做法,

第一种方式——在源码里面加一个encoding

p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=self._cwd, universal_newlines=True,encoding='utf-8')

运行没问题

第二种做法——直接把cp936变成utf_8

在笔者早期的博客中曾经干过这个事情

对python中open函数的偷梁换柱_mbcs' codec can't decode byte 0x91 in position 63-CSDN博客https://blog.csdn.net/qq_63401240/article/details/128665532?ops_request_misc=%257B%2522request%255Fid%2522%253A%252201ac56de0709aa67bbb1b532edbfc42b%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=01ac56de0709aa67bbb1b532edbfc42b&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-128665532-null-null.nonecase&utm_term=%E5%81%B7%E6%A2%81%E6%8D%A2%E6%9F%B1&spm=1018.2226.3001.4450Windows 系统默认的中文编码(即 GBK),即cp936,那么

全局搜索cp936,可以在如下路径

C:\Users\26644\.rye\py\cpython@3.13.2\Lib\encodings\aliases.py

笔者使用的rye,路径看个人python路径进行寻找,笔者这个只是一个参考,总之aliases.py文件。

发现如下东西

直接偷梁换柱,把cp936的右边变成utf_8,如下

直接换掉,运行是正确的,偷梁换柱。

笔者经常干这个事情,哈哈哈哈哈哈

进一步的思考

为什么console.log没有输出到终端??????????????

这不是一个bug,仅仅只是笔者希望输出到终端。

修改一下js文件

function a() {console.log("123")return "你好";
}

运行,没有输出123

看看源码在.venv\Lib\site-packages\execjs\_external_runtime.py文件中,有下面一个函数

        def _extract_result(self,output: str):output = output.replace("\r\n", "\n").replace("\r", "\n")output_last_line = output.split("\n")[-2]ret = json.loads(output_last_line)if len(ret) == 1:ret = [ret[0], None]status, value = retif status == "ok":return valueelse:raise ProgramError(value)

说白了,这就是处理输出后的结果,而 output.split("\n")[-2],只获取倒数第二个元素

打个断点看看,output是什么

output
Out[4]: '123\n\n["ok","你好"]\n'
output.split("\n")
Out[5]: ['123', '', '["ok","你好"]', '']

可以发现倒数第二个是一个列表字符串,如果修改一下js文件

function a() {console.log("123")console.log("456")return "你好";
}

debug输出如下。

Out[1]: '123\n456\n\n["ok","你好"]\n'
output.split('\n')
Out[2]: ['123', '456', '', '["ok","你好"]', '']

看来分开之后,倒数第二个是return的结果,

除去后面三个,就是中间的输出。

尝试一下,修改js文件

function b(){console.log('66666666')return 'hello'
}
function a() {console.log("123")console.log("456")console.log(b())return "你好";
}

Out[1]: '123\n456\n66666666\nhello\n\n["ok","你好"]\n'
output.split('\n')
Out[2]: ['123', '456', '66666666', 'hello', '', '["ok","你好"]', '']

没问题,那么,修改源码

        def _extract_result(self,output: str):output = output.replace("\r\n", "\n").replace("\r", "\n")output_split= output.split("\n")# 其他输出intermediate=output_split[:-3]# 返回值output_last_line = output_split[-2]ret = json.loads(output_last_line)if len(ret) == 1:ret = [ret[0], None]status, value = retif status == "ok":return {'return_value': value,'intermediate_value': intermediate}else:raise ProgramError(value)

原来是返回最终函数调用的返回值,现在返回了一个字典,既可以获取返回值,也可以获取中间变量。哈哈哈哈哈哈,可以。

测试一下

function b(){// 对象console.log({a:1,b:2})// 数组console.log([1,2,3,4,5])// setconsole.log(new Set([1,2,3,4,5]))// mapconsole.log(new Map([['a',1],['b',2]]))return 'hello'
}
function a() {console.log("123")console.log("456")console.log(b())return "你好";
}

结果如下

{'return_value': '你好', 'intermediate_value': ['123', '456', '{ a: 1, b: 2 }', '[ 1, 2, 3, 4, 5 ]', 'Set(5) { 1, 2, 3, 4, 5 }', "Map(2) { 'a' => 1, 'b' => 2 }", 'hello']}

没问题,哈哈哈哈哈

http://www.dtcms.com/a/507765.html

相关文章:

  • 算法16.0
  • 卡码网语言基础课(Python) | 16.出现频率最高的字母
  • [优选算法专题四.前缀和——NO.28 除自身以外数组的乘积]
  • 垂直门户网站怎么做如何开设一个网站
  • 第一章 FreeRTOS简介
  • 【任务调度】DolphinScheduler钉钉告警消息格式修改
  • 医院的网站关键词定位一般是什么潜江招聘资讯网
  • 网站制作软件培训网络推广培训心得
  • YOLOv4:目标检测更亲民更精准
  • 解决Jmeter警告
  • 构建企业数字化办公核心:安全高效的内网im私有化协同平台
  • 天津建设网站的公司哪家好wordpress+手机站目录
  • 19.9 ChatPPT v2.0语音识别实战:从噪音数据到92%准确率的企业级方案
  • 看风格的网站seo是什么意思 职业
  • Tomcat核心原理与运维实战指南
  • MyBatis-Plus的分页插件
  • S4双向链表
  • h5模板是什么网站开发好什么进行界面的优化
  • 淘宝做短视频网站自学网页设计的网站
  • 【含文档+PPT+源码】基于SpringBoot+Vue的校园电子设备租赁系统
  • 渗透测试快速启动工具箱
  • 在 go-zero 中优雅使用 Google Wire 实现依赖注入
  • Springboot3.5.6 + jdk21使用第三方xjar加密
  • [go 面试] 构建高效微服务通信:选择合适的通信方式
  • 推荐营销型网站建设做电影资源网站手机版
  • 厦门网站设计排行网站建设培训费用多少
  • 哪个网站做图文素材多项目投资网
  • Python3编程之面向对象
  • 【AI4S】从直觉到人工智能:药物发现中的小分子表征演变
  • docker compose 2.33版本安装