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

使用Beautiful Soup爬取带分页表格PDF遇静态URL分页问题求助

解决ASP.NET静态分页网站的PDF批量下载问题

问题描述

能够成功下载目标网站第一页的PDF文件,但无法获取全部4000+页面的PDF;观察URL发现无分页附加参数,不清楚如何遍历所有分页爬取PDF。

原代码存在的问题

  1. 未初始化BeautifulSoup解析对象,直接使用soup会报错
  2. table1变量未定义,无法定位表格中的PDF链接
  3. 完全缺失分页遍历逻辑,仅处理了第一页内容

解决方案思路

目标网站基于ASP.NET构建,这类网站的分页通常通过POST请求提交表单参数实现(而非URL参数),核心是每次请求分页时,需要携带页面中的__VIEWSTATE、__VIEWSTATEGENERATOR、__EVENTVALIDATION等ASP.NET特有参数,以及触发分页的事件参数。

具体步骤:

  • 首次请求获取第一页内容,解析出总页码、表单参数和第一页的PDF链接
  • 循环遍历每一页,每次请求前更新表单参数,提交POST请求获取对应页面的HTML
  • 解析每个页面的PDF链接并下载

修正后的完整代码

import requests
from bs4 import BeautifulSoup
import re
import os

# 创建保存PDF的目录
if not os.path.exists("loksabha_pdfs"):
    os.makedirs("loksabha_pdfs")

base_url = "https://loksabha.nic.in/Questions/Qtextsearch.aspx"
session = requests.Session()  # 使用Session保持会话,维持Cookie

# 首次请求获取第一页内容和必要的表单参数
response = session.get(base_url)
soup = BeautifulSoup(response.text, "html.parser")

# 获取总页码
span = soup.find("span", id="ContentPlaceHolder1_lblfrom")
total_pages = int(re.findall(r'\d+', span.text)[-1])  # 提取总页数
print(f"总共有 {total_pages} 页需要处理")

# 初始化下载计数器
download_count = 0

# 遍历所有分页
for page_num in range(1, total_pages + 1):
    print(f"正在处理第 {page_num} 页...")
    
    # 解析当前页面的PDF链接
    table1 = soup.find("table", id="ContentPlaceHolder1_gvQsearch")  # 定位目标表格
    if not table1:
        print(f"第 {page_num} 页未找到目标表格,跳过")
        continue
    
    for link in table1.find_all("a"):
        href = link.get("href", "")
        if ".pdf" in href and "CalenderUploading" not in href:
            # 处理相对链接,转为绝对URL
            pdf_url = base_url.rsplit("/", 1)[0] + "/" + href if not href.startswith("http") else href
            
            try:
                pdf_response = session.get(pdf_url, timeout=30)
                pdf_response.raise_for_status()  # 检查请求是否成功
                
                download_count += 1
                # 保存PDF文件,用更有辨识度的文件名
                pdf_filename = f"loksabha_pdfs/pdf_{download_count}.pdf"
                with open(pdf_filename, "wb") as f:
                    f.write(pdf_response.content)
                print(f"已下载: {pdf_filename}")
            except Exception as e:
                print(f"下载 {pdf_url} 失败: {str(e)}")
    
    # 如果不是最后一页,准备请求下一页的表单参数
    if page_num < total_pages:
        # 获取ASP.NET表单的必要参数
        viewstate = soup.find("input", id="__VIEWSTATE")["value"]
        viewstate_generator = soup.find("input", id="__VIEWSTATEGENERATOR")["value"]
        event_validation = soup.find("input", id="__EVENTVALIDATION")["value"]
        
        # 构造分页POST数据(模拟点击下一页的参数)
        payload = {
            "__VIEWSTATE": viewstate,
            "__VIEWSTATEGENERATOR": viewstate_generator,
            "__EVENTVALIDATION": event_validation,
            "__EVENTTARGET": "ContentPlaceHolder1$gvQsearch",
            "__EVENTARGUMENT": f"Page${page_num + 1}"
        }
        
        # 提交POST请求获取下一页内容
        try:
            response = session.post(base_url, data=payload, timeout=30)
            response.raise_for_status()
            soup = BeautifulSoup(response.text, "html.parser")
        except Exception as e:
            print(f"请求第 {page_num + 1} 页失败: {str(e)}")
            break

print(f"所有页面处理完成,共下载 {download_count} 个PDF文件")

代码说明

  • 使用requests.Session()维持会话,避免每次请求重新建立连接,同时保留网站的Cookie
  • 自动创建保存目录,避免文件保存失败
  • 处理相对链接转为绝对URL,确保PDF能正确下载
  • 添加异常捕获,处理请求超时、链接失效等问题
  • 模拟ASP.NET分页的表单提交,正确遍历所有分页

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:45:23