1. 项目背景与需求分析
去年我开始尝试用Python脚本自动发布CSDN博客时,原本以为是个简单的HTTP请求模拟,结果在Cookie处理、Markdown渲染、接口调用等环节踩了无数坑。这个项目源于我每周需要同步3-4篇技术笔记到CSDN,手动复制粘贴不仅效率低下,还经常出现格式错乱的问题。
CSDN的Markdown编辑器虽然支持CommonMark标准语法,但在自动发布场景下存在诸多特殊限制:
- 图片上传必须通过其专用接口
- 数学公式需要额外包裹
$$符号 - 表格宽度在移动端显示异常
- 代码块语言标识符区分大小写
更棘手的是其登录态验证机制:常规的账号密码登录会触发极验验证码,而直接使用Cookie又面临有效期问题。通过抓包分析发现,CSDN的发布接口实际有3个关键端点:
/api/v3/editor/upload处理图片资源/api/v3/editor/save保存草稿/api/v3/blog/submit最终发布
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心问题定位与解决方案
2.1 Cookie失效与自动续期方案
CSDN的登录Cookie(特别是UserToken和UserName)通常24小时就会失效。最初我尝试用selenium自动登录获取Cookie,但极验滑动验证码的识别成功率不足30%。后来改用以下方案:
python复制def refresh_cookie():
session = requests.Session()
# 先访问首页获取初始Cookie
session.get("https://passport.csdn.net/login")
# 通过扫码登录API获取二维码(需人工扫码)
qr_resp = session.post("https://passport.csdn.net/v1/qrcode/ticket")
ticket_id = qr_resp.json()['data']['ticket']
# 轮询扫码状态
while True:
status_resp = session.get(f"https://passport.csdn.net/v1/qrcode/query?ticket={ticket_id}")
if status_resp.json()['data']['status'] == 1:
break
time.sleep(2)
# 提取有效Cookie
return session.cookies.get_dict()
关键点:扫码登录比账号密码登录更稳定,且不会触发风控。获取的Cookie需要保存在本地文件,每次发布前检查有效期。
2.2 Markdown内容预处理
CSDN的Markdown解析器对以下语法需要特殊处理:
-
表格兼容性:必须在表头下方添加对齐线,否则移动端显示异常
markdown复制
| 参数 | 类型 | 说明 | |:----|:----|:-----| | timeout | int | 超时时间 | -
数学公式:需要双重转义
markdown复制
$$ \begin{cases} x = r \cos \theta \\ y = r \sin \theta \end{cases} $$ -
代码块:语言标识必须小写
markdown复制```python # 正确 ```Python # 错误
我开发了预处理函数自动修正这些问题:
python复制def preprocess_md(content):
# 标准化代码块语言标识
content = re.sub(r'```([A-Z][a-z]+)', lambda m: f'```{m.group(1).lower()}', content)
# 为没有对齐线的表格添加默认对齐
content = re.sub(r'(\|.+\|\n)(?!\|[-:]+)', r'\1|:---|\n', content)
return content
3. 图片上传的特殊处理
CSDN不允许直接使用外链图片,必须通过其接口上传。实测发现其图片接口有这些限制:
- 单文件不超过10MB
- 支持格式:jpg/png/gif
- 需要附带
blogId参数(可从个人主页URL获取)
上传脚本示例:
python复制def upload_image(cookie, image_path):
headers = {
'Cookie': '; '.join([f'{k}={v}' for k,v in cookie.items()]),
'Referer': 'https://mp.csdn.net/'
}
files = {'file': (os.path.basename(image_path), open(image_path,'rb'))}
resp = requests.post(
'https://mp.csdn.net/api/v3/editor/upload',
files=files,
headers=headers,
data={'blogId': '你的博客ID'}
)
return resp.json()['data']['url']
踩坑记录:必须设置正确的Referer,否则会返回403错误。图片URL需要替换为
![]()格式的Markdown语法。
4. 完整发布流程实现
结合上述模块,最终发布函数如下:
python复制def publish_to_csdn(md_file, cover_img=None):
# 1. 检查Cookie有效性
if not check_cookie_valid():
cookie = refresh_cookie()
save_cookie(cookie)
# 2. 预处理Markdown
with open(md_file, 'r', encoding='utf-8') as f:
md_content = preprocess_md(f.read())
# 3. 上传封面图
cover_url = upload_image(cookie, cover_img) if cover_img else ''
# 4. 保存草稿
draft_id = save_draft(
title=extract_title(md_content),
content=md_content,
cover=cover_url
)
# 5. 正式发布
result = submit_blog(draft_id)
print(f"发布成功:{result['url']}")
关键参数说明:
save_draft需要传递content_type=2表示Markdown格式- 分类ID需要通过接口
/api/v3/column/list提前查询 - 标签最多设置5个,需用英文逗号分隔
5. 异常处理与监控
在持续运行中发现了几个典型问题:
-
429 Too Many Requests:解决方案是添加随机延迟
python复制time.sleep(random.uniform(1, 3)) -
HTML实体编码问题:CSDN接口对
<和>有严格过滤python复制content = content.replace('<', '<').replace('>', '>') -
移动端预览异常:需要在发布后手动访问一次页面触发CDN缓存更新
建议添加邮件通知功能:
python复制def send_alert(subject, content):
import smtplib
from email.mime.text import MIMEText
msg = MIMEText(content)
msg['Subject'] = subject
smtp = smtplib.SMTP('smtp.example.com')
smtp.sendmail('from@example.com', 'to@example.com', msg.as_string())
6. 效率优化技巧
经过三个月持续优化,总结出以下经验:
- 批量处理:先本地生成所有草稿,再集中发布(间隔10分钟以上)
- 封面图缓存:重复使用的图片URL存入本地数据库
- 失败重试:对网络错误实现指数退避重试机制
- 流量伪装:随机UserAgent和操作间隔模拟人工行为
最终实现的发布脚本平均耗时从最初的2分钟/篇优化到20秒/篇,成功率从65%提升至98%。这个过程中最深刻的体会是:自动化工具必须充分考虑目标平台的反爬策略,在合规前提下实现人机友好的交互方式。
