You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Python遍历多页URL批量下载符合过滤规则的PDF文件

Python实现ASN站点PDF批量下载工具

前置依赖安装

先执行命令安装所需第三方库:
pip install requests beautifulsoup4 tqdm

实现规则说明

  • 分页遍历逻辑:基于给定的分页URL模板逐页请求,当返回页无有效搜索结果时自动终止遍历,无需手动配置总页数
  • 链接检测逻辑:一级搜索结果页中直接指向PDF的链接直接进入下载校验流程;非PDF跳转链接自动发起二级请求,提取目标页内所有PDF资源链接
  • 过滤规则:所有待下载PDF自动提取文件名,文件名以"INS"开头的文件直接跳过,不执行下载
  • 容错逻辑:内置请求超时、重复文件跳过机制,避免因网络波动导致爬取中断

完整代码

import os
import requests
from urllib.parse import urljoin, unquote
from bs4 import BeautifulSoup
from tqdm import tqdm

# -------------------------- 配置项 可根据需求修改 --------------------------
START_YEAR = 2020  # 检索起始年份
END_YEAR = 2024    # 检索结束年份
SEARCH_KEYWORD = ""  # 搜索关键词,无关键词留空即可
SAVE_DIR = "./asn_pdfs"  # PDF本地保存路径
REQUEST_TIMEOUT = 15  # 单次请求超时时间 单位秒
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
    "Accept-Language": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7"
}
# ------------------------------------------------------------------------

# 初始化保存目录
os.makedirs(SAVE_DIR, exist_ok=True)
# 已下载文件集合 用于去重
downloaded_files = set(os.listdir(SAVE_DIR))
# 全局已爬取链接集合 避免重复请求二级页
crawled_pages = set()

def extract_pdf_from_page(page_url):
    """从指定页面提取所有符合规则的PDF下载链接"""
    pdf_links = []
    if page_url in crawled_pages:
        return pdf_links
    crawled_pages.add(page_url)
    
    try:
        resp = requests.get(page_url, headers=HEADERS, timeout=REQUEST_TIMEOUT)
        resp.raise_for_status()
        soup = BeautifulSoup(resp.text, "html.parser")
        
        for a_tag in soup.find_all("a", href=True):
            href = a_tag["href"].strip()
            absolute_url = urljoin(page_url, href)
            # 识别PDF链接
            if absolute_url.lower().endswith(".pdf"):
                # 提取文件名 过滤INS开头的文件
                file_name = unquote(absolute_url.split("/")[-1])
                if file_name.startswith("INS"):
                    print(f"跳过规则过滤文件: {file_name}")
                    continue
                pdf_links.append((absolute_url, file_name))
    except Exception as e:
        print(f"页面解析失败 {page_url}: {str(e)}")
    
    return pdf_links

def download_pdf(pdf_url, file_name):
    """执行PDF下载"""
    if file_name in downloaded_files:
        return
    save_path = os.path.join(SAVE_DIR, file_name)
    
    try:
        resp = requests.get(pdf_url, headers=HEADERS, stream=True, timeout=REQUEST_TIMEOUT)
        resp.raise_for_status()
        total_size = int(resp.headers.get("content-length", 0))
        
        with open(save_path, "wb") as f, tqdm(
            desc=file_name,
            total=total_size,
            unit="iB",
            unit_scale=True,
            unit_divisor=1024,
            leave=False
        ) as pbar:
            for chunk in resp.iter_content(chunk_size=1024):
                if chunk:
                    size = f.write(chunk)
                    pbar.update(size)
        downloaded_files.add(file_name)
        print(f"下载完成: {file_name}")
    except Exception as e:
        print(f"下载失败 {pdf_url}: {str(e)}")
        if os.path.exists(save_path):
            os.remove(save_path)

if __name__ == "__main__":
    page_num = 1
    url_template = "https://www.asn.fr/recherche?filter_year[from]={}&filter_year[to]={}&limit=50&search_content_type=&search_text={}&sort_type=date&page={}"
    
    while True:
        current_page_url = url_template.format(START_YEAR, END_YEAR, SEARCH_KEYWORD, page_num)
        print(f"\n正在爬取第 {page_num} 页: {current_page_url}")
        
        try:
            resp = requests.get(current_page_url, headers=HEADERS, timeout=REQUEST_TIMEOUT)
            resp.raise_for_status()
            soup = BeautifulSoup(resp.text, "html.parser")
            result_links = soup.find_all("a", href=True)
            
            # 无有效结果时终止遍历
            if not result_links:
                print("已到达最后一页,爬取终止")
                break
            
            page_pdf_tasks = []
            for a_tag in result_links:
                href = a_tag["href"].strip()
                absolute_url = urljoin(current_page_url, href)
                # 跳过非http链接、锚点链接
                if not absolute_url.startswith("http") or "#" in absolute_url:
                    continue
                # 直接是PDF链接的直接加入任务
                if absolute_url.lower().endswith(".pdf"):
                    file_name = unquote(absolute_url.split("/")[-1])
                    if not file_name.startswith("INS"):
                        page_pdf_tasks.append((absolute_url, file_name))
                # 非PDF链接进入二级页提取PDF,仅爬取本站点链接避免跳转外部站
                elif "asn.fr" in absolute_url:
                    page_pdf_tasks.extend(extract_pdf_from_page(absolute_url))
            
            # 执行当前页所有下载任务
            for pdf_url, file_name in page_pdf_tasks:
                download_pdf(pdf_url, file_name)
            
            page_num += 1
        except Exception as e:
            print(f"第 {page_num} 页请求失败: {str(e)},终止爬取")
            break

使用注意事项

  • 首次运行前可根据自身需求修改代码开头配置块内的参数,默认检索2020-2024年全站无关键词的所有公开内容
  • 脚本仅会爬取asn.fr域名下的页面,不会跳转至外部站点,避免无效请求
  • 爬取过程中会自动跳过已下载文件,中途中断后重新运行会从断点位置继续,不会重复下载
  • 若爬取速度较慢,可自行调整代码内的REQUEST_TIMEOUT参数,或添加代理配置

内容的提问来源于stack exchange,提问作者Ing DESIGN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 00:57:21