再见,洛谷博客!——下载洛谷博客文章(JavaScript)
控制台部分
在洛谷首页 F12 打开控制台,复制代码到控制台即可使用。由于技术受限,最终只能下载一个 .json 文件,文件中有所有博客的标题和内容。代码由豆包生成。
关于报错:如果报错是 Error: Cannot fetch blog ${bid}!
则一般是因为这篇文章已经被删除,可以查看 log 确认这一点;若不是这个报错,则请重新运行或向我报告。
// 定义常量
const url = "https://www.luogu.com.cn";
console.log("Warning: When the program is running, don't log out your luogu account...");
const uid = "{}"
let restCount = 0;
// 获取博客内容的函数
async function fetchBlogContent(bid) {
// 全局计数器加 1
restCount += 1;
if (restCount % 10 === 0) {
console.log("Please wait for 5 seconds...");
// 等待 5 秒,不然可能请求失败或者封号
await new Promise(resolve => setTimeout(resolve, 5000));
}
// 发送请求获取博客详情
const response = await fetch(`${url}/api/blog/detail/${bid}`);
const result = await response.json();
// 处理响应状态
if (result.status === 200) {
const data = result.data;
return {
source: `${url}/blog/_post/${bid}`,
content: data.Content,
identifier: data.Identifier,
postTime: data.PostTime,
title: data.Title,
type: data.Type
};
} else {
console.error(`Error: Cannot fetch blog ${bid}!`);
console.log(result);
return {};
}
}
files = []
// 保存博客内容的函数
async function saveBlogContent(bid) {
const result = await fetchBlogContent(bid);
if (Object.keys(result).length === 0) {
return;
}
// 格式化时间
const postTime = new Date(result.postTime * 1000).toISOString().replace('T', ' ').substring(0, 19);
const titleLine = `# ${result.title}\n`;
const metaLine = `posted on ${postTime} | under ${result.type} | [source](${result.source})\n\n`;
const contentLine = `${result.content}\n`;
files.push({
title: `${result.identifier}.md`,
content: titleLine + metaLine + contentLine
})
console.log(`Save blog ${bid} successfully...`);
}
// 获取博客列表的函数
async function getBlogLists(uid) {
const response = await fetch(`${url}/api/blog/userBlogs`);
const result = (await response.json()).blogs;
const lists = [];
const pageNumber = Math.ceil(result.count / result.perPage);
for (let i = 1; i <= pageNumber; i++) {
const pageResponse = await fetch(`${url}/api/blog/userBlogs?page=${i}`);
const pageResult = (await pageResponse.json()).blogs;
for (const blog of pageResult.result) {
lists.push(blog.id);
}
}
return lists;
}
// 主函数,用于获取博客列表并保存博客内容
async function main() {
console.log(`Now start fetching blogs of user ${uid}.`);
const blogIds = await getBlogLists(uid);
console.log(`${blogIds.length} blogs in total.`)
console.log(blogIds)
for (const bid of blogIds) {
await saveBlogContent(bid);
}
console.log(files)
// 将 files 转为 json 格式,提供给用户下载
const jsonData = JSON.stringify(files, null, 2);
const blob = new Blob([jsonData], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'blogs.json';
a.click();
URL.revokeObjectURL(url);
console.log(`Blogs of user ${uid} have already saved.`);
console.log("Thank you for using my tool. Author: Luogu @yukimianyan.");
}
// 调用主函数
main().catch(error => console.error('An error occurred:', error));
本地部分
配套使用的以下代码,将下载的 .json 文件转化为若干文件。以下代码为 python 代码,需要预先 pip install json
(也可能不需要),然后需要手动修改最后三行的文件路径。同样地,代码由豆包生成。
注意!!!专栏上线后创建的文章,其 identifier(标识符)不是人类可读的(例如有一篇 't1733148542yKpVVX9dhqj1dYRz.md' 是我的游记),对此我真是一点办法都没有。如果你动手能力比较强你可以把文件名改为标题 + .md
,但是这样会有转义字符问题,所以我没有这样做。
import json
import os
def json_to_files(json_file_path, output_directory):
# 检查输出目录是否存在,如果不存在则创建
if not os.path.exists(output_directory):
os.makedirs(output_directory)
try:
# 打开 JSON 文件并加载数据
with open(json_file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
# 遍历 JSON 数组中的每个对象
for item in data:
title = item.get('title')
content = item.get('content')
if title and content:
# 构建文件的完整路径
file_path = os.path.join(output_directory, title)
# 打开文件并写入内容
with open(file_path, 'w', encoding='utf-8') as output_file:
output_file.write(content)
print(f"文件 {title} 已成功创建。")
else:
print("跳过无效的对象,缺少 'title' 或 'content' 属性。")
except FileNotFoundError:
print(f"未找到 JSON 文件: {json_file_path}")
except json.JSONDecodeError:
print(f"JSON 文件格式错误: {json_file_path}")
# 示例用法
if __name__ == "__main__":
json_file_path = "blogs.json" # 替换为实际的 JSON 文件路径
output_directory = "./blogs" # 替换为实际的输出目录
json_to_files(json_file_path, output_directory)
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18706277
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!