Skip to content

一次爬取网站的经历

955字约3分钟

title-tattle

2024-10-22

前言

一次使用 wget 爬取网站资源的经历。

背景

昨天晚上在看 技术摘抄 的时候,发现该网站因为收到 Google 相关通知,不久会被关闭,所以我就想着能不能将整个网站的内容保存下来,后面还可以看。

经过后面一通 f12 分析,我发现它不是常规的前后端通过 ajax 请求来进行数据交互的,而是类似于 hexo 这类博客,将 markword 文件渲染为 html 进行展示,所以我想出来的唯一方法就是将 html 包括相关的 css、js、图片等全部下载下来。

这里会使用到一个工具 wget,然后编写了一些脚本,在我自己的服务器上跑了大概 1 天,成功的下载了所有的内容。

之所以要跑一天,是因为这个网站应该是基于 cloudflare 做了请求的限制,所以我每次的请求都必须要等待一段时间。

下面就将我这个过程中用到的 sh 脚本分享出来,希望大家慎用。

wget 批量爬取资源

首先 wget 命令是:

wget -r -l inf --no-parent --accept=html,css,jpg,jpeg,png,gif,md -e robots=off -w 5 -x -np -pk "download_url"

解释一下:

  • -r:启用递归下载。
  • -l inf:设置递归的最大深度为无限。
  • --no-parent:确保 wget 不会爬取到指定目录之外的上级目录。
  • --accept=html,css,jpg,jpeg,png,gif,md:只接受特定类型的文件。
  • -e robots=off:忽略站点的 robots.txt 文件。
  • -w 5:在每次请求之间等待 5 秒钟,这就是避免因为请求过于频繁而被封禁 IP 地址。
  • -x:使用原来的目录结构保存文件,这样下载的内容会按照原网站的目录结构进行组织。
  • -np:不追溯到父级目录。
  • -pk:下载显示 HTML 页面所必需的所有文件。比如,如果一个 HTML 页面包含图片、样式表等,那么这些也会一并被下载下来。
  • "download_url":这就是要下载的起始 URL。

在下载过程中,我们肯定不能手动输入 download_url,所以我会提前将网站的所有文章链接写到一个 txt 文件,其次,在下载完成后记录日志,方便后面如果哪里有问题好排查。

最后,启动 sh 时请使用 nohup,否则关掉终端后 sh 命令就会停止了,如下:

nohup ./download.sh index.txt &

download.sh 参考:

#!/bin/sh
# 参数是包含 URL 的文本文件名称
URL_FILE="$1"

# 日志文件名
LOG_FILE="download_log.txt"

# 清空或创建日志文件
> "$LOG_FILE"

# 读取 URL 文件并下载每个 URL
while IFS= read -r URL; do
  if [ -n "$URL" ]; then  # 确保 URL 不为空
    echo "Downloading from: $URL" | tee -a "$LOG_FILE"
    
    # 使用 wget 下载 URL,并将输出重定向到日志文件
    wget -r -l inf --no-parent --accept=html,css,jpg,jpeg,png,gif,md -e robots=off -w 5 -x -np -pk "$URL" 2>&1 | tee -a "$LOG_FILE"
    
    # 检查 wget 的退出状态
    if [ $? -eq 0 ]; then
      echo "Success: $URL" | tee -a "$LOG_FILE"
    else
      echo "Failure: $URL" | tee -a "$LOG_FILE"
    fi
  fi
done < "$URL_FILE"

echo "All downloads completed." | tee -a "$LOG_FILE"

将 .md 修改为 .html

将资源下载下来后,文件的后缀是 .md,但是里面的内容实际是 html,所以我们将所有的 .md 后缀修改为 .html,如下:

#!/bin/sh
# 检查是否提供了一个参数
if [ -z "$1" ]; then
  echo "请提供一个目录作为参数"
  exit 1
fi

# 定义目录变量
dir="$1"

# 使用 find 查找 .md 文件,并对每个找到的文件执行 mv 命令更改扩展名
find "$dir" -type f -name "*.md" | while read file; do
  # 获取文件的基本名称(不含扩展名)
  base="${file%.md}"
  # 重命名文件
  mv "$file" "${base}.html"
done