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

如何使用Python和BeautifulSoup4循环爬取多页面数据(含4000页场景)

Hey there! 我来帮你梳理用Python和BeautifulSoup4实现多页面爬取的循环逻辑,还有你提到的分国家获取数据的问题~

一、多页面爬取的核心循环逻辑(支持4000页+自动终止)

针对你要遍历4000个页面、遇到last标识就终止的需求,咱可以做一个带双重终止条件的循环:既限制最大页数(防止无限循环),又检测页面的终止标识。

完整代码示例

import requests
from bs4 import BeautifulSoup
import time
import pandas as pd

# 基础配置
base_url = "https://your-target-site.com/data?page={}"
max_total_pages = 4000
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
}

def extract_page_data(soup):
    """封装单页数据提取逻辑,按需修改"""
    data_list = []
    # 示例:提取页面中所有带item-card类的元素信息
    items = soup.find_all("div", class_="item-card")
    for item in items:
        title = item.find("h2").get_text(strip=True) if item.find("h2") else "无标题"
        detail = item.find("p").get_text(strip=True) if item.find("p") else "无详情"
        data_list.append({"title": title, "detail": detail})
    return data_list

# 初始化循环参数
current_page = 1
has_next_page = True
all_data = []

while current_page <= max_total_pages and has_next_page:
    try:
        # 发送请求(处理编码和超时)
        response = requests.get(
            base_url.format(current_page),
            headers=headers,
            timeout=10
        )
        response.encoding = response.apparent_encoding  # 自动识别编码
        response.raise_for_status()  # 捕获HTTP错误
        
        # 解析页面
        soup = BeautifulSoup(response.text, "html.parser")
        
        # 1. 处理当前页面数据
        page_data = extract_page_data(soup)
        all_data.extend(page_data)
        print(f"已完成第{current_page}页爬取,累计获取{len(all_data)}条数据")
        
        # 2. 判断是否到达最后一页(两种常见判断方式,选适合你的)
        # 方式一:检测是否存在"last"标识(比如页面上的"最后一页"文本或特定class)
        last_indicator = soup.find("span", class_="last-page-tag") or soup.find(text="Last Page")
        # 方式二:检测下一页按钮是否存在/可用
        next_button = soup.find("a", class_="next-page-btn")
        
        if last_indicator or (not next_button or "disabled" in next_button.get("class", [])):
            has_next_page = False
            print(f"检测到最后一页标识,爬取将在第{current_page}页后终止")
        
        # 3. 页数自增+防反爬延迟
        current_page += 1
        time.sleep(1.5)  # 可根据网站反爬强度调整,建议1-3秒
        
    except requests.exceptions.RequestException as e:
        print(f"第{current_page}页请求失败:{str(e)}")
        # 可选:失败后重试1次
        time.sleep(3)
        continue

# 保存最终数据
pd.DataFrame(all_data).to_csv("total_scraped_data.csv", index=False, encoding="utf-8-sig")
print("全部爬取完成!数据已保存到total_scraped_data.csv")

关键细节说明

  • 双重终止条件:既限制最大页数(4000),又检测页面的last标识,避免因网站结构变化导致无限循环
  • 数据提取封装:把单页数据提取逻辑放到单独函数里,后续修改或维护更方便
  • 防反爬处理:加User-Agent模拟浏览器请求,加固定延迟,捕获请求异常避免程序崩溃
  • 编码处理:用response.apparent_encoding自动识别页面编码,避免乱码
二、分国家获取数据的解决方案(针对OSM覆盖不足的情况)

你提到有些国家(比如白俄罗斯)公开数据不在OSM里,需要单独爬取对应国家的官方数据源,这里给你一套模块化的处理思路:

核心思路

  1. 先整理国家数据源映射表:区分哪些国家可以用OSM接口,哪些需要爬取官方网站
  2. 为每个特殊国家编写专属爬取函数(因为不同国家的网站结构差异极大)
  3. 用一个主调度函数统一管理所有国家的爬取任务

法国数据爬取示例(针对你提到的法国政府网站)

def scrape_france_official_data():
    """爬取法国政府网站数据的专属函数"""
    france_regions = ["ile-de-france", "auvergne-rhone-alpes", "provence-alpes-cote-dazur"]  # 可扩展全法国区域
    france_base_url = "https://france-official-data.gov/region/{}?page={}"
    france_all_data = []
    
    for region in france_regions:
        page_num = 1
        has_next = True
        print(f"开始爬取法国{region}区域数据...")
        
        while has_next:
            try:
                response = requests.get(
                    france_base_url.format(region, page_num),
                    headers=headers,
                    timeout=10
                )
                response.encoding = "utf-8"
                soup = BeautifulSoup(response.text, "html.parser")
                
                # 提取法国区域数据(根据实际网站结构修改选择器)
                region_items = soup.find_all("div", class_="fr-data-item")
                for item in region_items:
                    name = item.find("h3").get_text(strip=True)
                    value = item.find("span", class_="data-value").get_text(strip=True)
                    france_all_data.append({
                        "country": "France",
                        "region": region,
                        "name": name,
                        "value": value
                    })
                
                # 判断下一页
                next_btn = soup.find("a", id="btn-next-region")
                has_next = bool(next_btn) and not "disabled" in next_btn.get("class", [])
                page_num += 1
                time.sleep(1)
                
            except Exception as e:
                print(f"法国{region}区域第{page_num}页爬取失败:{str(e)}")
                break
    
    # 保存法国数据
    pd.DataFrame(france_all_data).to_csv("france_official_data.csv", index=False, encoding="utf-8-sig")
    print("法国官方数据爬取完成!")

# 调用函数
scrape_france_official_data()

调度函数示例(统一管理多国家爬取)

def run_multi_country_scraper():
    # 先爬取OSM覆盖的国家数据(这里假设你有对应的OSM爬取函数)
    # scrape_osm_countries()
    
    # 再爬取特殊国家的数据
    scrape_france_official_data()
    # 可添加其他国家的爬取函数:scrape_belarus_data()、scrape_germany_data()等

run_multi_country_scraper()
三、必看的爬取注意事项
  • 合法性:爬取前务必查看目标网站的robots.txt文件,确保允许爬取,遵守网站的服务条款
  • 反爬升级:如果遇到更严格的反爬,可以考虑使用代理IP池、随机User-Agent库(比如fake-useragent)
  • 数据存储:数据量较大时(比如4000页的量级),建议用数据库(SQLite/PostgreSQL)替代CSV,提升存储和查询效率
  • 异常兜底:可以给关键步骤加更细致的异常捕获,比如页面元素找不到时的容错处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:15:56