自定义 JSON 编码器引发 "Object not JSON serializable" 错误

Custom JSON Encoder raises "Object not JSON serializable" error

我正在尝试为我的 class 之一创建自定义 JSON 编码器。 我创建了一个 simplified version 来尝试该方法并且它有效,但是当我在我的项目中应用该方法时它不断抛出错误:

    json.dump(obj=self.tree, fp=f, cls=BookmarkEncoder, ensure_ascii=False)
  File "/usr/lib/python3.8/json/__init__.py", line 179, in dump
    for chunk in iterable:
  File "/usr/lib/python3.8/json/encoder.py", line 438, in _iterencode
    o = _default(o)
  File "/usr/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type HTMLBookmark is not JSON serializable

我要转换的对象是BeautifulSoupTagclass的修改版本,class的代码如下:

class HTMLBookmark(Tag, Node):
    """TreeBuilder class, used to add additional functionality to the
    BeautifulSoup Tag class. The following functionality is added:

    - add id to each folder("h3")/url("a") being imported
    - add property access to the Tag class' attributes
      (date_added, icon, icon_uri, id, index, title, type and url)
      which are usually found in the 'self.attrs' dictionary.
    - add a setter for (id, index and title)
    - redirect the self.children from an iterator iter(self.contents)
    to a list (self.contents) directly"""

    counter = itertools.count(start=2)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.name in ("a", "h3"):
            if not self.attrs.get("id"):
                self.attrs["id"] = next(__class__.counter)

    @property
    def date_added(self):
        date_added = self.attrs.get("add_date")
        if not date_added:
            date_added = round(time.time() * 1000)
        return int(date_added)

    @property
    def icon(self):
        return self.attrs.get("icon")

    @property
    def icon_uri(self):
        return self.attrs.get("iconuri")

    @property
    def id(self):
        return self.attrs.get("id")

    @id.setter
    def id(self, new_id):
        self.attrs["id"] = new_id

    @property
    def index(self):
        return self.attrs.get("index")

    @index.setter
    def index(self, new_index):
        self.attrs["index"] = new_index

    @property
    def title(self):
        return self.attrs.get("title")

    @title.setter
    def title(self, new_title):
        self.attrs["title"] = new_title

    @property
    def type(self):
        if self.name == "h3":
            return "folder"
        elif self.name == "a":
            return "url"

    @property
    def url(self):
        return self.attrs.get("href")

    @property
    def children(self):
        """To standardize the access of children amongst the different
        classes."""
        return self.contents

HTML书签class继承自节点:

class Node:
    def create_folder_as_json(self):
        folder = {
            "type": self.type,
            "id": self.id,
            "index": self.index,
            "parent_id": self.parent_id,
            "title": self.title,
            "date_added": self.date_added,
            "children": [],
        }
        return folder

    def create_url_as_json(self):
        url = {
            "type": self.type,
            "id": self.id,
            "index": self.index,
            "parent_id": self.parent_id,
            "title": self.title,
            "date_added": self.date_added,
            "url": self.url,
            "icon": self.icon,
            "iconuri": self.icon_uri,
            "tags": self.tags,
        }
        return url

    def __repr__(self):
        return f"{self.title} - {self.type} - id: {self.id}"

这是我的自定义编码器

class BookmarkEncoder(json.JSONEncoder):
    def defaut(self, o):
        if isinstance(o, HTMLBookmark):
            if o.type == "folder":
                return o.create_folder_as_json()
            elif o.type == "url":
                return o.create_url_as_json()
        return json.JSONEncoder.default(self, o)

最后是触发错误的代码:

with open(output_file, "w", encoding="Utf-8") as f:
    json.dump(obj=self.tree, fp=f, cls=BookmarkEncoder, ensure_ascii=False)

其中 self.tree 是通过使用 BeautifulSoup.

导入 HTML 文件创建的 HTMLBookmark 对象

如果需要任何进一步的信息,请告诉我,谢谢 :)。

编辑:

这是@Ulrich Eckhardt 在评论中建议的 link 到工作 code sample and html input

你好像打错了:def defaut(self, o): 应该是 def default(self, o):