使用Beautiful Soup爬取带分页表格PDF遇静态URL分页问题求助
解决ASP.NET静态分页网站的PDF批量下载问题
问题描述
能够成功下载目标网站第一页的PDF文件,但无法获取全部4000+页面的PDF;观察URL发现无分页附加参数,不清楚如何遍历所有分页爬取PDF。
原代码存在的问题
- 未初始化
BeautifulSoup解析对象,直接使用soup会报错 table1变量未定义,无法定位表格中的PDF链接- 完全缺失分页遍历逻辑,仅处理了第一页内容
解决方案思路
目标网站基于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
相关产品推荐
相关产品推荐

