从零实现自动化抓取与本地备份
目录导读
为什么需要网页源码保存脚本?
在日常开发、数据采集、网页存档或SEO分析中,手动通过“查看网页源代码”再保存的方式效率极低,一个自动化脚本能帮你:

- 批量抓取数百个页面源码
- 定时备份网站结构变化
- 分析竞争对手页面技术特征
- 建立本地离线版网页档案
Q:脚本保存的源码和手动保存有什么区别?
A:脚本可完整捕获HTTP响应内容,包含HTML、CSS、JS及隐藏的注释或服务器端注入代码,而手动保存可能丢失动态渲染后的数据。
核心实现原理与主流工具对比
技术原理图解
用户请求 → Python脚本 → 服务器响应 → 保存为本地文件(.html / .txt / .json)
主流实现方案对比
| 工具/库 | 适用场景 | 难度 | 动态页面支持 | 反爬绕过能力 |
|---|---|---|---|---|
| urllib | 简单静态页面 | 低 | 否 | 无 |
| requests | 带Cookie/Header抓取 | 低 | 否 | 基础UA伪装 |
| Selenium | 动态渲染页面 | 中高 | 完整支持 | 可配置代理 |
| Scrapy | 大规模批量采集 | 高 | 需中间件 | 内置策略 |
Q:我最应该选哪个?
A:个人或小批量推荐requests+BeautifulSoup组合;需要模拟浏览器行为则用Selenium;企业级批量用Scrapy框架。
手把手教你构建Python保存脚本
1 基础版:单页静态源码保存(含注释)
import requests
from datetime import datetime
def save_page_source(url, file_path=None):
# 设置请求头模拟正常浏览器
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
try:
# 发送GET请求
response = requests.get(url, headers=headers, timeout=10)
response.encoding = 'utf-8' # 自动识别编码
# 生成保存路径
if not file_path:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
file_path = f"page_source_{timestamp}.html"
# 保存源码到本地文件
with open(file_path, 'w', encoding='utf-8') as f:
f.write(response.text)
print(f"✓ 成功保存至: {file_path}")
return response.text
except Exception as e:
print(f"✗ 失败原因: {str(e)}")
return None
# 使用示例
save_page_source("https://example.com")
2 进阶版:批量保存与自动化命名
import os
import requests
from urllib.parse import urlparse
def batch_save(url_list, output_dir="saved_pages"):
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
for url in url_list:
# 从URL提取文件名(如 example_com.html)
parsed = urlparse(url)
file_name = parsed.netloc.replace(".", "_") + ".html"
file_path = os.path.join(output_dir, file_name)
save_page_source(url, file_path) # 调用基础函数
# 批量保存示例
urls = ["https://www.example.com/page1", "https://www.example.com/page2"]
batch_save(urls)
Q:遇到403禁止访问怎么办?
A:更新User-Agent为最新浏览器版本,添加Referer头,或使用Requests的Session保持Cookie。
高级技巧:处理动态加载与反爬
1 使用Selenium保存完整渲染后源码
对于需要JavaScript执行才能显示内容的页面(如单页应用SPA),可用Selenium抓取:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
def save_dynamic_page(url, output_file="dynamic_page.html"):
# 配置无头浏览器
chrome_options = Options()
chrome_options.add_argument("--headless") # 无界面模式
chrome_options.add_argument("--disable-gpu")
chrome_options.add_experimental_option("excludeSwitches", ["enable-logging"])
driver = webdriver.Chrome(options=chrome_options)
try:
driver.get(url)
# 等待页面完全加载
driver.implicitly_wait(10)
# 获取渲染后的源码
html_source = driver.page_source
with open(output_file, 'w', encoding='utf-8') as f:
f.write(html_source)
print(f"动态页面已保存至: {output_file}")
finally:
driver.quit()
2 应对反爬的5个关键点
- 请求间隔:使用
time.sleep()随机等待(1-3秒) - IP轮换:搭配免费代理池(如ProxyBroker)
- Cookie管理:保存session cookie维持登录态
- Referer伪装:模拟从站内跳转进入
- User-Agent轮换:准备工具如
fake_useragent库
Q:Selenium脚本运行缓慢怎么办?
A:使用无头模式(Headless)、禁用CSS/图片加载、或换用Playwright(速度更快)。
常见问题FAQ
Q1:脚本保存的html文件为什么打不开?
A:可能保存了残缺响应(网络中断),需检查状态码是否为200;或未设置response.encoding导致乱码。
Q2:如何保存带CSS/JS的完整网页?
A:使用工具如wget -p -k命令;或Python库requests-html(能自动下载引用资源)。
Q3:想保存手机版源码该怎么做?
A:在请求头中添加User-Agent: Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36模拟移动设备。
Q4:脚本会导致IP被封吗?
A:合理控制频率(每秒1个请求以下)并设置随机延迟,大多数站点不会封禁。
Q5:有无命令行一键实现的方法?
A:Linux/macOS用户直接用curl -o page.html https://example.com;Windows用wget(需安装)。
总结与最佳实践建议
核心要点回顾
- 选择工具:静态页面用
requests,动态页面用Selenium/Playwright - 编码处理:始终指定
utf-8编码防止乱码 - 反爬应对:伪装UA、控制频率、使用代理
- 存储优化:按网站域名/日期建立目录结构
长期维护建议
- 为脚本增加日志记录(记录每次保存的网址、时间、状态码)
- 定期检查目标网站结构变化(如class名更新)
- 将脚本部署在服务器上用crontab定时执行
最后提示:尊重网站robots.txt协议,仅保存公开允许抓取的页面,用于个人学习或内部存档,切勿用作商业侵权。
掌握这些技巧后,你已经能够高效实现网页源码的自动化保存,实践中遇到问题,务必先检查网络请求的
status_code和cookies,这是调试的黄金法则。