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

基于Scrapy构建树形结构:瑞士联邦法律网站爬取需求

Hey Matt, 作为web scraping新手要啃这个树形结构的瑞士联邦法律网站,确实得先摸清楚页面的层级逻辑才行!我帮你梳理了一套可行的方案,从分析结构到代码实现,一步步来,最后能把整个类目树到法律文本的结构输出成JSON文件~

第一步:先搞懂网站的层级结构

这个网站的树形逻辑很清晰:

  • 首页是一级类目(比如「国家-人民-当局」「国防」这些)
  • 点击每个一级类目会进入子类目页面,可能还有多级子类目
  • 最终的叶子节点是具体的法律文本页面,包含标题和内容

你可以用浏览器开发者工具(F12)查看页面HTML,确认子类目、法律条目对应的标签和class,这是写爬虫的关键~

第二步:选合适的工具

对于这种层级爬取,我推荐两种方案:

  • 新手友好:requests + BeautifulSoup,用递归或迭代的方式遍历类目
  • 更专业高效:Scrapy框架,天生适合处理这种多层级的爬取任务

下面我给你写一个requests+BeautifulSoup的实现示例,上手快,容易理解。

第三步:爬虫代码实现

首先要导入依赖库:

import requests
from bs4 import BeautifulSoup
import json
from urllib.parse import urljoin
import time

然后写核心的递归爬取函数,用来遍历整个类目树:

# 网站基础URL
BASE_URL = "https://www.admin.ch/opc/fr/classified-compilation/national.html"
# 请求头,模拟浏览器访问,避免被反爬拦截
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 crawl_category(url):
    """递归爬取单个类目,返回包含子类目或法律条目的字典"""
    # 发送请求前加短暂延迟,降低爬取频率
    time.sleep(1)
    response = requests.get(url, headers=HEADERS)
    response.encoding = "utf-8"
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # 初始化当前类目数据
    category_data = {
        "name": soup.find("h1").text.strip(),
        "url": url,
        "children": []
    }
    
    # 查找子类目(这里的选择器是基于当前网站结构,若网站更新需调整)
    subcategories = soup.select("ul.list-level li a")
    if subcategories:
        # 有子类目,继续递归爬取
        for subcat in subcategories:
            subcat_url = urljoin(BASE_URL, subcat['href'])
            subcat_data = crawl_category(subcat_url)
            category_data["children"].append(subcat_data)
    else:
        # 没有子类目,说明是叶子节点,提取法律条目
        law_items = soup.select("div.entry")
        for item in law_items:
            law_title = item.find("h2").text.strip()
            law_url = urljoin(BASE_URL, item.find("a")['href'])
            # 可选:如果需要爬取法律文本内容,调用下面的crawl_law_content函数
            # law_content = crawl_law_content(law_url)
            category_data["children"].append({
                "type": "law",
                "title": law_title,
                "url": law_url
                # "content": law_content  # 打开注释即可获取内容
            })
    
    return category_data

def crawl_law_content(url):
    """爬取单个法律文本的内容"""
    time.sleep(1)
    response = requests.get(url, headers=HEADERS)
    response.encoding = "utf-8"
    soup = BeautifulSoup(response.text, 'html.parser')
    content = soup.find("div", class_="content").get_text(strip=True, separator="\n")
    return content

if __name__ == "__main__":
    # 爬取首页的所有一级类目
    response = requests.get(BASE_URL, headers=HEADERS)
    response.encoding = "utf-8"
    soup = BeautifulSoup(response.text, 'html.parser')
    top_categories = soup.select("ul.list-main li a")
    
    # 构建完整的树形结构
    full_law_tree = []
    for top_cat in top_categories:
        top_cat_url = urljoin(BASE_URL, top_cat['href'])
        top_cat_data = crawl_category(top_cat_url)
        full_law_tree.append(top_cat_data)
    
    # 保存为JSON文件,确保特殊字符正常显示
    with open("swiss_federal_laws_tree.json", "w", encoding="utf-8") as f:
        json.dump(full_law_tree, f, ensure_ascii=False, indent=4)
    
    print("爬取完成!树形结构已保存到 swiss_federal_laws_tree.json 文件中")
关键注意事项
  • 选择器调整:我写的选择器是基于当前网站的结构,但网站可能会更新,你一定要用浏览器开发者工具确认子类目、法律条目的实际选择器,调整代码里的select参数。
  • 反爬处理:一定要加HEADERS模拟浏览器,不然很容易被网站封禁IP;代码里加了time.sleep(1)控制爬取频率,也可以根据情况调整时长。
  • 递归深度问题:如果类目层级特别深,递归可能会触发栈溢出,这时候可以把递归改成迭代(用栈或队列来存储待爬取的类目URL)。
  • 数据清洗:提取的文本可能有多余的空格、换行,记得用strip()或正则表达式清理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:10:05