Skip to content

批量下载与合并课件

举例: http://zhiqihuang.top/gr/lectures.php , 网站上有很多 url. 点开后, 是 http://zhiqihuang.top/gr/lectures/*.pdf。

批量爬取 http://zhiqihuang.top/gr/lectures/*.pdf

# 导入所需的库:requests 用于发起网络请求,BeautifulSoup 用于解析 HTML,os 用于操作文件系统
import requests
from bs4 import BeautifulSoup
import os

# 设置要抓取 PDF 文件链接的网页 URL
url = 'http://zhiqihuang.top/gr/lectures.php'
# 使用 requests 库发起 HTTP GET 请求,获取网页内容
response = requests.get(url)
# 使用 BeautifulSoup 解析获取到的网页内容,'html.parser' 是用来解析 HTML 的解析器
soup = BeautifulSoup(response.text, 'html.parser')

# 使用 BeautifulSoup 查找所有的 <a> 标签(即超链接标签),并过滤出那些 href 属性以 '.pdf' 结尾的链接
# 这一步是为了找到所有指向 PDF 文件的链接
pdf_links = [link.get('href') for link in soup.find_all('a') if link.get('href') and link.get('href').endswith('.pdf')]

# 设置一个目录用于存放下载的 PDF 文件
download_dir = 'downloaded_pdfs'
# 使用 os.makedirs 创建这个目录,exist_ok=True 参数表示如果目录已经存在则忽略该命令,不会引发错误
os.makedirs(download_dir, exist_ok=True)

# 遍历所有找到的 PDF 文件链接
for pdf_url in pdf_links:
    # 构建完整的 PDF 文件 URL,因为从网页上获取的可能是相对路径
    full_pdf_url = f'http://zhiqihuang.top/gr/{pdf_url}'
    # 使用 requests 发起 GET 请求下载 PDF 文件,stream=True 参数表示以流模式获取数据,适用于下载大文件
    pdf_response = requests.get(full_pdf_url, stream=True)

    # 检查 HTTP 响应状态码,200 表示请求成功
    if pdf_response.status_code == 200:
        # 从 PDF 链接中提取文件名
        pdf_name = os.path.basename(pdf_url)
        # 构建保存 PDF 文件的完整路径
        pdf_path = os.path.join(download_dir, pdf_name)

        # 以二进制写模式打开文件,准备写入下载的 PDF 数据
        with open(pdf_path, 'wb') as pdf_file:
            # iter_content 方法用于流式下载文件,chunk_size=8192 表示每次写入 8192 字节的数据
            for chunk in pdf_response.iter_content(chunk_size=8192):
                pdf_file.write(chunk)

        # 打印下载成功的消息
        print(f"Downloaded {pdf_name}")
    else:
        # 如果状态码不是 200,打印下载失败的消息
        print(f"Failed to download {pdf_url}, status code {pdf_response.status_code}")

# 最后,打印所有文件尝试下载完成的消息
print("All PDF files have been downloaded or attempted.")

将下载好的 pdf 合并:

# 导入操作系统相关的库,用于处理文件和目录路径
import os
# 导入 fitz 库,也就是 PyMuPDF,一个用于处理 PDF 文件的库
import fitz

# 定义一个函数来合并 PDF 文件
# pdfs_dir 参数是包含 PDF 文件的目录的路径
# output_pdf_name 参数是合并后的 PDF 文件的名称
def merge_pdfs(pdfs_dir, output_pdf_name):
    # 创建一个新的空 PDF 文档对象
    merged_pdf = fitz.open()
    # 获取指定目录下的所有文件名,然后按字母顺序排序
    pdf_files = sorted(os.listdir(pdfs_dir))

    # 遍历排序后的文件名列表
    for pdf_file in pdf_files:
        # 检查文件名是否以 .pdf 结尾
        if pdf_file.endswith('.pdf'):
            # 构建完整的文件路径
            pdf_file_path = os.path.join(pdfs_dir, pdf_file)
            # 打印出正在尝试打开的 PDF 文件路径
            print(f"Trying to open: {pdf_file_path}")
            try:
                # 使用 fitz 打开当前的 PDF 文件
                current_pdf = fitz.open(pdf_file_path)
                # 将当前打开的 PDF 文档插入到合并的 PDF 文档中
                merged_pdf.insert_pdf(current_pdf)
                # 关闭当前打开的 PDF 文件
                current_pdf.close()
            except Exception as e:
                # 如果在处理当前 PDF 文件时遇到异常,则打印错误信息
                print(f"Error processing {pdf_file_path}: {e}")

    # 检查合并后的 PDF 文档中是否至少有一页
    if len(merged_pdf) > 0:
        # 如果有,则保存合并后的 PDF 文档到指定的文件名
        merged_pdf.save(output_pdf_name)
        # 关闭合并后的 PDF 文档
        merged_pdf.close()
        # 打印成功合并的消息
        print(f"All PDF files have been merged into {output_pdf_name}")
    else:
        # 如果合并后的 PDF 文档中没有页面,则打印错误消息
        print("No PDF files were merged. Please check the file paths.")

# 指定包含 PDF 文件的目录的路径
pdfs_dir = '/mnt/e/garnet/mathworld/huangzhiqiang_gr/downloaded_pdfs'
# 指定合并后的 PDF 文件的名称
output_pdf_name = 'Merged_PDFs.pdf'
# 调用函数,执行合并 PDF 文件的操作
merge_pdfs(pdfs_dir, output_pdf_name)