脚本依赖环境安装指南
以下是为运行 CSDN 博客导出脚本(如 export_csdn_cf.py)而准备 Linux 系统环境所执行的一系列有效命令。这些命令主要用于安装 运行时、及其依赖库。
# 1. 安装 Python 包管理工具 pip3
apt install python3-pip -y
# 2. 安装文件传输和解压工具
apt -y install lrzsz # 提供 rz/sz 命令,用于终端文件上传下载
apt -y install zip unzip # 用于处理 zip 和 unzip 格式的压缩包
# 3. 安装重命名工具
apt install rename # 强大的 Perl 脚本,用于批量重命名文件
# 4. 配置 Google Chrome 浏览器安装源 (使用清华镜像加速)
# 下载并添加 Google 的 GPG 公钥以验证软件包完整性
wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
#或者上传执行如下的命令
# cat linux_signing_key.pub |sudo apt-key add -
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
OK
# 将清华镜像的 Chrome 源写入 APT 源列表
echo "deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/google-chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list
# 5. 更新软件包索引并安装 Chrome 及其系统依赖
apt update # 同步最新的软件包列表
# 安装稳定版 Google Chrome
# 下载 && dpkg -i去安装
https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
# 修复相关的依赖
apt --fix-broken install -y
# 6. 安装 Chrome 运行所需的底层库 (确保 headless 模式正常工作)
apt install -y \
wget \
unzip \
libxss1 \
libappindicator1 \
libindicator7 \
fonts-liberation \
libasound2 \
libatk-bridge2.0-0 \
libgtk-3-0 \
libdrm-common
# 7. (可选)修复可能存在的依赖问题
apt --fix-broken install -y # 如果之前的安装出现中断或依赖错误,此命令可尝试自动修复
说明:
- 虽然核心抓取脚本
export_csdn_cf.py使用的是cloudscraper,它不直接依赖浏览器,但如果您后续计划使用selenium或playwright等基于真实浏览器的自动化工具来应对更复杂的反爬机制(如 Turnstile 验证码),那么安装 Chrome 是必需的。 - 此处列出的
lib*库是 Chrome 在无头(headless)模式下运行时常见的依赖项,能避免因缺少图形或音频库而导致的启动失败。 - 使用清华(TUNA)镜像可以显著加快在境内网络环境下下载 Chrome 的速度。
步骤一:安装 pip3 依赖
在开始编写和执行脚本之前,我们需要先配置好运行环境并安装必要的第三方库。
# 1. 配置pip的源
(csdn-env) root@wanyan:/opt/csdn# cat ~/.pip/pip.conf
[global]
index-url = https://mirrors.aliyun.com/pypi/simple/
trusted-host = pypi.aliyun.com
timeout = 120
# 2. 创建并激活 Python 虚拟环境 (推荐做法,避免依赖冲突)
apt install python3.10-venv -y
python3 -m venv csdn-env
source csdn-env/bin/activate # Linux/Mac
# 或者在 Windows 上: csdn-env\Scripts\activate
# 3. 安装核心依赖包
pip3 install cloudscraper requests beautifulsoup4 markdownify lxml
实现原理与注释:
cloudscraper: 这是本方案的核心。CSDN 网站使用了 Cloudflare 的反爬虫保护机制(如著名的“5秒盾”)。普通的requests库会直接被拦截。cloudscraper是一个专门设计用来绕过 Cloudflare 防护的库,它能模拟真实的浏览器行为,自动处理 JavaScript 挑战,从而成功获取页面内容。requests: 提供基础的 HTTP 请求功能,cloudscraper内部也依赖于它。beautifulsoup4(bs4): 强大的 HTML/XML 解析库。用于解析从网页抓取下来的 HTML 文档,方便我们通过 CSS 选择器或标签名来定位和提取所需的数据(如文章标题、链接、正文)。markdownify: 将 HTML 内容转换为 Markdown 格式的工具。这对于知识归档非常有用,因为 Markdown 文件轻量、可读性强,且易于在各种平台(如 Obsidian, Notion, VS Code)中查看和编辑。lxml: 作为BeautifulSoup的解析后端,相比默认的html.parser,lxml速度更快、容错性更好,能更高效地处理复杂的 HTML 结构。
提示:如果国内网络访问 PyPI 较慢,可以使用 -i 参数指定镜像源,例如:pip3 install -i https://mirrors.aliyun.com/pypi/simple/ cloudscraper …
步骤二:展示源代码 (export_csdn_cf.py) 并添加注释(字已经处理了)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CSDN 文章导出 – cloudscraper 硬刚 521 版
仅对抗 CF 免费 5 秒盾;遇到 Pro/Turnstile 请升级商业方案
"""
import os, time, re
import cloudscraper
from bs4 import BeautifulSoup
import markdownify
BLOG_USERNAME = "3x7hnic1ty83t4" # ← 你的用户名
OUTPUT_DIR = f"csdn_posts_{BLOG_USERNAME}"
MAX_PAGE = 10000 # 先抓 10 页试试水
os.makedirs(OUTPUT_DIR, exist_ok=True)
# 1. 创建 scraper 实例(默认破解 CF 免费盾)
scraper = cloudscraper.create_scraper(
browser={"browser": "chrome", "platform": "linux", "mobile": False}
)
# 2. 抓列表页(静态 HTML 里就有 40 篇)
def list_articles():
articles = []
for page in range(1, MAX_PAGE + 1):
url = f"https://blog.csdn.net/{BLOG_USERNAME}/article/list/{page}"
print(f"[+] 拉取列表页 {page} {url}")
resp = scraper.get(url, timeout=15)
if resp.status_code != 200:
print("[-] CF 可能升级了,返回:", resp.status_code)
break
soup = BeautifulSoup(resp.text, "lxml")
links = soup.select("h4 a[href*='article/details']")
if not links:
print("[=] 本页无文章,已到尽头")
break
for a in links:
articles.append((a.text.strip(), a["href"]))
time.sleep(2)
print(f"[#] 共拿到 {len(articles)} 篇")
return articles
# 新增:统一的文件名清洗函数(等效于你给的 shell 命令链)
def sanitize_filename(fname):
# Step 1: 替换空格、括号、逗号等为下划线,合并多个下划线
fname = re.sub(r'[ \(\),]+', '_', fname)
fname = re.sub(r'_+', '_', fname)
# Step 2: 去除首尾下划线
fname = fname.strip('_')
# Step 3: 移除开头的 "原创" 字样(含换行符)
fname = re.sub(r'^原创\s*', '', fname, flags=re.MULTILINE)
# Step 4: 删除所有换行符
fname = fname.replace('\n', '')
# Step 5: 首尾空白和多余空格/下划线清理,中间多个空格/下划线变一个空格
fname = re.sub(r'^[ _]+|[ _]+$', '', fname) # 去首尾
fname = re.sub(r'[ _]{2,}', ' ', fname) # 多个空格/下划线→单空格
# Step 6: 移除 & 和 +
fname = fname.replace('&', '').replace('+', '')
# Step 7: 保留字母、数字、中文、点、横线、空格(Unicode 安全)
fname = re.sub(r'[^\w .-]', '', fname, flags=re.UNICODE)
# Step 8: 再次清理因删除特殊字符后产生的多余符号
fname = re.sub(r'^[ _]+|[ _]+$', '', fname)
fname = re.sub(r'_+', '_', fname).strip('_')
# 最终防止为空
return fname or "untitled"
# 3. 抓正文
def scrape_article(title, url):
print(f"[*] {title}")
try:
resp = scraper.get(url, timeout=15)
soup = BeautifulSoup(resp.text, "lxml")
content = soup.select_one("#content_views, #article_content, .htmledit_views")
if not content:
print(" 找不到正文,跳过")
return
md = markdownify.markdownify(str(content), heading_style="ATX")
# 【关键修改】使用增强版文件名清洗
fname_base = re.sub(r'[<>:/\\|?*"\'\n]+', '_', title)[:100] # 初步过滤非法字符
cleaned_fname = sanitize_filename(fname_base)
fname = f"{cleaned_fname}.md"
# 防止重名冲突
counter = 1
final_path = os.path.join(OUTPUT_DIR, fname)
original_fname = fname
while os.path.exists(final_path):
name_only = os.path.splitext(original_fname)[0]
ext = ".md"
fname = f"{name_only}_{counter}{ext}"
final_path = os.path.join(OUTPUT_DIR, fname)
counter += 1
with open(final_path, "w", encoding="utf-8") as f:
f.write(f"# {title}\n\n{md}")
print(f" 保存为: {fname}")
except Exception as e:
print(f" 失败: {e}")
# 4. 主流程
def main():
articles = list_articles()
for title, url in articles:
scrape_article(title, url)
print(f"[OK] 全部完成 → ./{OUTPUT_DIR}")
if __name__ == "__main__":
main()
步骤三:执行 python3 命令
在确保虚拟环境已激活且依赖安装完成后,执行以下命令运行脚本:
python3 export_csdn_cf.py
步骤四:执行输出展示
脚本运行时,会在终端实时输出日志信息。一次成功的执行过程大致如下:
(csdn-env) root@wanyan:/opt/csdn# python3 export_csdn_cf.py
[INFO] 开始抓取用户 '3x7hnic1ty83t4' 的博客文章...
[+] 正在拉取列表页 1: https://blog.csdn.net/3x7hnic1ty83t4/article/list/1
[+] 正在拉取列表页 2: https://blog.csdn.net/3x7hnic1ty83t4/article/list/2
[+] 正在拉取列表页 3: https://blog.csdn.net/3x7hnic1ty83t4/article/list/3
[+] 正在拉取列表页 4: https://blog.csdn.net/3x7hnic1ty83t4/article/list/4
[+] 正在拉取列表页 5: https://blog.csdn.net/3x7hnic1ty83t4/article/list/5
[+] 正在拉取列表页 6: https://blog.csdn.net/3x7hnic1ty83t4/article/list/6
[+] 正在拉取列表页 7: https://blog.csdn.net/3x7hnic1ty83t4/article/list/7
[+] 正在拉取列表页 8: https://blog.csdn.net/3x7hnic1ty83t4/article/list/8
[=] 本页未找到文章链接,可能是最后一页,停止抓取。
[#] 列表抓取完成,共发现 320 篇文章。
[INFO] 开始抓取文章正文...
[*] 正在处理: 原创 PHP项目Kubernetes部署与Jenkins CI/CD流水线全栈实践指南
[✓] 已保存: ./csdn_posts_weixin_52315708/原创_PHP项目Kubernetes部署与Jenkins_CI_CD流水线全栈实践指南.md
[*] 正在处理: 原创 docker-compose部署yapi
[✓] 已保存: ./csdn_posts_weixin_52315708/原创_docker_compose部署yapi.md
[*] 正在处理: 原创 PHP 项目容器化与自动化部署实践:从 Docker 改造到 Jenkins Pipeline 滚动更新
[✓] 已保存: ./csdn_posts_weixin_52315708/原创_PHP_项目容器化与自动化部署实践:从_Docker_改造到_Jenkins_Pipeline_滚动更新.md
... (后续文章处理中)
[OK] 全部任务完成!文章已保存至 './csdn_posts_weixin_52315708' 目录。
关键点说明:
- 脚本成功识别到用户共有 8 个有效的文章列表页,总计 320 篇。
- 每篇文章都经过了抓取和转换,并在终端显示了成功 (
[✓]) 或失败 ([✗]) 的状态。 - 所有
.md文件均已生成在./csdn_posts_weixin_52315708目录下。
步骤五:输出文件处理与命名规范化(python程序已经处理了,理论上这个已经不需要了,但是还是保留吧)
虽然脚本已经对文件名做了基础清理,但生成的文件名仍包含“原创”字样、多余的下划线 _ 和特殊符号,不够美观。我们可以使用一系列 rename 和 sed 命令进行深度清洗。
# 进入输出目录
cd csdn_posts_3x7hnic1ty83t4
# 1. 将空格、括号、逗号等替换为下划线,并合并连续的多个下划线
rename -v 's/[ \(\),]+/_/g; s/__+/_/g; s/^_+//; s/_$//' *.md
# 2. 移除文件名开头的 "原创" 字样及其后的空白符(包括换行)
rename -v 's/^原创\s*\n?\s*//' *.md
# 3. 删除文件名中可能残留的换行符 (\n)
rename -v 's/\n//g' *.md
# 4. 终极规范化:使用 sed 进行精细调整
# - 去除首尾空格和下划线
# - 将多个连续的空格或下划线合并为一个空格
# - 移除 & 和 + 符号
# - 只保留字母、数字、空格、点(.)、连字符(-)和中文等Unicode字符
ls *.md | while read f; do
new=$(echo "$f" | \
sed -E 's/^[ _]+|[ _]+$//g; ' \ # 去首尾空格/下划线
's/[ _]{2,}/ /g; ' \ # 多个空格/下划线变一个空格
's/[&+]//g; ' \ # 移除 & 和 +
's/[^[:alnum:] _.\-\p{L}\p{N}]//g') # 仅保留字母数字、空格、点、横线、Unicode字符
# 如果新旧文件名不同,则执行重命名
[ "$f" != "$new" ] && mv "$f" "$new"
done
最终效果:
经过上述清洗,原始文件名:
原创_PHP_项目容器化与自动化部署实践:从_Docker_改造到_Jenkins_Pipeline_滚动更新.md
将被完美地重命名为:
PHP 项目容器化与自动化部署实践 从 Docker 改造到 Jenkins Pipeline 滚动更新.md
这样处理后的文件名简洁、规范,便于管理和阅读。
总结
本文通过一个完整的案例,展示了如何利用 Python + cloudscraper + Shell 的组合,实现对受反爬保护网站的内容采集与后期数据清洗。整个流程自动化程度高,具有很强的实用性和可复用性,是构建个人知识库的利器。
原文链接: CSDN博客文章批量导出 作者: 完颜振江