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

基于BeautifulSoup爬取多页面列表时的翻页与日期范围筛选问题求助

解决慕尼黑BA申请页面爬取的分页与筛选问题

嘿,作为爬取新手遇到这种情况太正常了——很多官方网站的分页和筛选都不会用直观的URL参数,而是靠表单请求或者后台参数来处理。我给你梳理几个关键的解决方向,一步步来:

1. 先搞清楚网站的分页逻辑(为什么下一页链接没用?)

你遇到的“下一页链接跳回第一页”,大概率是因为这个网站的分页不是靠URL参数传递,而是通过POST表单参数或者隐藏的请求参数来实现的。你需要用浏览器的开发者工具来抓真实的请求:

  • 打开目标页面,按F12打开开发者工具,切换到「Network」标签
  • 点击页面上的「下一页」按钮,观察Network里新出现的请求:
    • 看请求类型是GET还是POST
    • 查看「Form Data」(POST请求)或者「Query String Parameters」(GET请求)里的参数,比如有没有page、offset、size这类和分页相关的字段
    • 同时看日期筛选的参数:如果页面上有选择年份的选项,选择2024年后,同样抓请求里的参数,比如year=2024或者startDate=2024-01-01

2. 替换你的请求方式,模拟真实的分页/筛选请求

一旦拿到这些参数,你就可以用requests库直接构造包含分页和筛选参数的请求,而不是只请求初始URL。比如如果是POST请求,代码框架大概是这样:

import requests
import time
from bs4 import BeautifulSoup

# 基础请求地址(从开发者工具里抓的真实请求地址)
target_url = "https://risi.muenchen.de/risi/antrag/ba/baantraguebersicht?2"
# 模拟浏览器的请求头,避免被反爬拦截
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
}

# 初始化请求参数:分页+筛选今年数据
request_params = {
    'year': 2024,  # 假设抓出来的年份参数是year
    'page': 1,     # 当前页码
    'size': 10     # 每页条目数,对应你看到的10条/页
}

all_entries = []

while True:
    # 根据实际请求类型选get/post,这里假设是POST
    response = requests.post(target_url, headers=headers, data=request_params)
    # 检查请求是否成功
    if response.status_code != 200:
        print(f"请求第{request_params['page']}页失败,状态码:{response.status_code}")
        break
    
    soup = BeautifulSoup(response.content, 'html.parser')
    # 更精准地定位条目:不要用uls[17]这种不稳定的索引,找条目专属的class
    # 比如看页面里每个条目li的class,假设是"antrag-list-item"
    entries = soup.find_all('li', class_='antrag-list-item')
    
    if not entries:
        print("没有更多条目了,停止爬取")
        break
    
    for entry in entries:
        # 提取数据:用更可靠的方式定位,避免索引错误
        title = entry.find('a', class_='headline-link').get_text(strip=True)
        # 先找到"Beschlossen am"的标签,再找它的兄弟节点(对应的数值)
        beschlossen = entry.find('div', string='Beschlossen am').find_next_sibling('div').get_text(strip=True)
        typ = entry.find('div', string='Antragstyp').find_next_sibling('div').get_text(strip=True)
        status = entry.find('div', string='Status').find_next_sibling('div').get_text(strip=True)
        ba = entry.find_all('a', class_='icon_action')[0].get_text(strip=True)
        referat = entry.find_all('a', class_='icon_action')[1].get_text(strip=True)
        
        all_entries.append({
            '标题': title,
            '决议日期': beschlossen,
            '类型': typ,
            '状态': status,
            'BA': ba,
            '部门': referat
        })
    
    print(f"已获取第{request_params['page']}页,共{len(all_entries)}条数据")
    request_params['page'] += 1  # 页码加1,继续下一页
    time.sleep(1)  # 加个延迟,避免请求太频繁被封

# 后续就可以分析all_entries里的数据了

3. 几个关键的优化点(避免踩坑)

  • 不要用索引定位元素:你之前用uls[17]和find_all[index],一旦页面结构微调,代码就会报错。尽量用元素的class、文本内容来定位,比如find('div', string='Beschlossen am')。
  • 添加请求头和延迟:官方网站一般有反爬机制,加User-Agent模拟浏览器,再加time.sleep()控制请求频率,避免被IP封禁。
  • 检查请求是否成功:每次请求后判断status_code,如果返回403/500,就停止或者重试。

4. 如果遇到动态加载(比如AJAX渲染)

如果上面的方法还是不行,可能网站是用JavaScript动态加载内容的,这时候你需要用selenium或者playwright来模拟浏览器的点击操作,比如自动点击下一页、选择年份。不过先优先尝试抓请求参数的方法,因为这种方法更高效,也不需要额外安装浏览器驱动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:47:42