json.load读取JSON报JSONDecodeError 嵌套字典存储后读取出错如何解决
错误原因
- r+模式读写逻辑错误:你使用
r+模式打开文件,调用json.load()读取完全部内容后,文件指针会移动到文件末尾,此时直接执行json.dump()不会覆盖原有内容,而是将新的JSON内容追加到原内容之后。下一次读取时,整个文件是多段JSON拼接的非法结构,若某次写入过程中程序异常中断,还会出现空文件,直接触发你遇到的line 1 column 1 (char 0)空内容解析错误。 - JSON不兼容Python元组类型:你将
(title_news, date_news)元组直接存入字典写入JSON,虽然json模块会自动将元组转为列表不会直接触发当前报错,但属于隐藏问题,后续读取出来的结构是列表而非元组,可能导致后续业务逻辑异常。
修复方案
核心修改点
- 拆分读写逻辑:放弃
r+模式,读操作使用r只读模式,读完直接关闭文件;写操作使用w只写模式,写入前会自动清空原有内容,避免内容追加导致结构异常。 - 调整文件操作位置:将文件读写从循环内移到外层,避免每爬一条新闻就频繁读写磁盘,同时降低IO异常概率。
- 增加异常兼容:捕获文件不存在、结构损坏的异常,自动初始化字典,避免程序直接崩溃。
修正后代码示例
@tasks.loop(minutes=30) async def get_gamesnews(): sites = ['https://multiplayer.it/articoli/notizie/'] # 程序启动时一次性读取现有数据 try: with open('dictionary_news.json', 'r') as f: dict_news = json.load(f) except (json.JSONDecodeError, FileNotFoundError): # 文件损坏/不存在时自动初始化 dict_news = {'multiplayer.it': {}} dictvalues_news = dict_news.get('multiplayer.it', {}) new_news = [] # 存储需要推送的新新闻 for site in sites: async with aiohttp.ClientSession() as ses: async with ses.get(site) as response: if response.status == 200: text = await response.text() soup = BeautifulSoup(text, 'lxml') if site == 'https://multiplayer.it/articoli/notizie/': div_news = soup.find_all('div', class_='media-body') for news in div_news: titles = news.find_all('a', class_='text-decoration-none') for title in titles: title_news = title.text.strip() link_news = 'https://multiplayer.it' + title['href'] if link_news not in dictvalues_news: date_news = datetime.date.today().strftime('%Y-%m-%d') # 转为列表存储,符合JSON格式规范 dict_news['multiplayer.it'][link_news] = [title_news, date_news] new_news.append((title_news, link_news)) # 所有新闻处理完成后一次性写入文件 with open('dictionary_news.json', 'w') as f: json.dump(dict_news, f, ensure_ascii=False, indent=2) # 批量推送新新闻 channel = client.get_channel(855220263917191228) for title, link in new_news: print((title, link, date_news)) await channel.send(f'{title} {link}')
内容的提问来源于stack exchange,提问作者Nobodyet
相关产品推荐
相关产品推荐

