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

使用BeautifulSoup批量下载意大利市政Zip文件遇问题求助

问题解决:意大利市政Zip文件批量下载

问题说明

需要为7000多个意大利市政单位下载Zip文件,文件可通过对应市政页面的“SCARICA I DATI CSV”按钮获取。但原代码访问市政主页后,返回的HTML中找不到任何CSV相关链接,导致代码报错。

原单个市政下载代码:

city_name = "vandoies-vintl"
prov_name = "bz"

r = urllib.request.urlopen('http://storico.openbilanci.it/bilanci/' + city_name + "-comune-" + prov_name).read()
soup = BeautifulSoup(r, 'lxml')

# 此处报错:HTML中无csv相关内容
csv = soup.find_all('a', attrs={'class':'pull-right csv'})
csvlink = csv[0]['href']
urllib.request.urlretrieve("http://storico.openbilanci.it" + csvlink, city_name+".zip")

问题原因

你访问的是市政的主页(无参数URL),但下载按钮仅存在于带年份、类型参数的子页面中(比如示例页面的year=2014&type=consuntivo&cas_com_type=cassa参数)。主页没有下载链接,必须先进入对应子页面才能抓取。

解决方案

1. 单个市政下载修复代码

如果固定下载某年份(比如2014)的consuntivo类型数据,可以直接构造子页面URL:

city_name = "vandoies-vintl"
prov_name = "bz"

# 构造带参数的子页面URL
url = f'http://storico.openbilanci.it/bilanci/{city_name}-comune-{prov_name}?year=2014&type=consuntivo&cas_com_type=cassa'
r = urllib.request.urlopen(url).read()
soup = BeautifulSoup(r, 'lxml')

# 查找下载链接
csv_links = soup.find_all('a', attrs={'class':'pull-right csv'})
if csv_links:
    csvlink = csv_links[0]['href']
    urllib.request.urlretrieve(f"http://storico.openbilanci.it{csvlink}", f"{city_name}.zip")
    print("下载成功")
else:
    print("未找到下载链接")

2. 批量下载代码修改版

以下是修改后的批量代码,增加了子页面URL构造逻辑,完善了错误处理:

import pandas as pd
import numpy as np
import time

from bs4 import BeautifulSoup
import urllib.request
import re
import os
import zipfile

output_path = r"/Users/aartimalik/Dropbox/delphine-miscellaneous/italy/test"

# 市政列表
munis = [("monale", "at"), ("portacomaro", "at")]
munis = pd.DataFrame(munis, columns=['municipality_clean','prov_abb'])

# 清洗市政名称格式
def remove_paren(string):
    return re.sub(r'\(.*\)', '', str(string))
munis['municipality_clean'] = munis['municipality_clean'].apply(remove_paren).str.strip()
munis['municipality_clean'] = munis['municipality_clean'].str.replace(' ', '-').str.lower()

# 初始化结果存储
scrapesuccess = pd.DataFrame(columns=munis.columns)
scrapefail = pd.DataFrame(columns=munis.columns)

# 遍历市政
for idx, row in munis.iterrows():
    city_name = row['municipality_clean']
    prov_name = row['prov_abb']
    try:
        # 构造子页面URL(以2014年consuntivo类型为例)
        sub_url = f'http://storico.openbilanci.it/bilanci/{city_name}-comune-{prov_name}?year=2014&type=consuntivo&cas_com_type=cassa'
        r = urllib.request.urlopen(sub_url).read()
        soup = BeautifulSoup(r, 'lxml')
        
        # 查找下载链接
        csv_links = soup.find_all('a', attrs={'class':'pull-right csv'})
        if csv_links:
            csvlink = csv_links[0]['href']
            zip_file_path = os.path.join(output_path, f"{city_name}.zip")
            urllib.request.urlretrieve(f"http://storico.openbilanci.it{csvlink}", zip_file_path)
            
            # 创建文件夹并解压
            new_folder = os.path.join(output_path, city_name.capitalize())
            os.makedirs(new_folder, exist_ok=True)
            
            with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
                zip_ref.extractall(new_folder)
            
            print(f"{idx}. {city_name}: 成功")
            scrapesuccess = pd.concat([scrapesuccess, pd.DataFrame([row])], ignore_index=True)
        else:
            print(f"{idx}. {city_name}: 未找到下载链接")
            scrapefail = pd.concat([scrapefail, pd.DataFrame([row])], ignore_index=True)
    except Exception as e:
        print(f"{idx}. {city_name}: 失败 - {str(e)}")
        scrapefail = pd.concat([scrapefail, pd.DataFrame([row])], ignore_index=True)

# 保存成功/失败列表(可选)
scrapesuccess.to_csv(os.path.join(output_path, 'success_list.csv'), index=False)
scrapefail.to_csv(os.path.join(output_path, 'fail_list.csv'), index=False)

额外说明

  • 如果需要下载多个年份或类型的数据,可以先从市政主页提取所有可用的参数组合(比如年份下拉框、类型选项),再循环遍历这些组合构造URL
  • 建议增加请求间隔(比如time.sleep(1)),避免对服务器造成过大压力
  • 部分市政可能没有对应年份的数据,需做好错误处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 05:35:35