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

使用BeautifulSoup爬取Xcel Energy网站xls文件时遭遇urllib 404错误

解决爬取Xcel Energy官网xls表格时的404错误

嘿,我之前爬这类企业官网的时候也碰到过一模一样的404问题,大概率是这几个常见原因,咱们一步步来排查解决:

1. 先确认你构造的URL是不是完整路径

很多时候页面里的下载链接是相对路径(比如/documents/xxx.xls),如果你直接把这个相对路径当成完整URL去请求,服务器肯定找不到资源返回404。

解决方法是用urllib.parse.urljoin把主域名和相对路径拼接成完整URL:

from urllib.parse import urljoin
from bs4 import BeautifulSoup
import urllib.request

base_url = "https://www.xcelenergy.com"
page_url = f"{base_url}/working_with_us/municipalities/community_energy_reports"

# 获取页面内容(先加个简单的UA头避免被拦截)
req = urllib.request.Request(page_url, headers={"User-Agent": "Mozilla/5.0"})
page_content = urllib.request.urlopen(req).read()
soup = BeautifulSoup(page_content, "html.parser")

# 提取xls链接并拼接完整URL
xls_links = []
for a_tag in soup.find_all("a", href=lambda x: x and x.endswith(".xls")):
    relative_url = a_tag["href"]
    full_url = urljoin(base_url, relative_url)
    xls_links.append(full_url)
    print("完整下载URL:", full_url)

拼接完之后,一定要手动把这个URL复制到浏览器里打开——如果浏览器也打不开,那可能是链接本身失效了;如果浏览器能打开,那就是请求头或者反爬的问题。

2. 给请求添加浏览器伪装的请求头

urllib默认的请求头是Python-urllib/3.x这种标识,很多网站会直接拦截这类非浏览器的请求,返回404(其实是服务器拒绝访问,伪装成404)。

你需要给请求添加User-Agent等头信息,伪装成浏览器访问:

import urllib.request

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",
    "Referer": base_url  # 有些网站会检查Referer,确保请求来自官网页面
}

for full_url in xls_links:
    try:
        req = urllib.request.Request(full_url, headers=headers)
        response = urllib.request.urlopen(req)
        # 保存文件
        filename = full_url.split("/")[-1]
        with open(filename, "wb") as f:
            f.write(response.read())
        print(f"成功下载: {filename}")
    except urllib.error.HTTPError as e:
        print(f"下载失败 {full_url}: {e}")

如果觉得urllib写起来麻烦,推荐用requests库,代码更简洁直观:

import requests

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"}

for full_url in xls_links:
    try:
        response = requests.get(full_url, headers=headers)
        response.raise_for_status()  # 主动抛出HTTP错误
        filename = full_url.split("/")[-1]
        with open(filename, "wb") as f:
            f.write(response.content)
        print(f"成功下载: {filename}")
    except requests.exceptions.RequestException as e:
        print(f"下载失败 {full_url}: {e}")

3. 检查页面是否是动态加载内容

如果上面两步都试过还是404,那可能页面的下载链接是通过JavaScript动态渲染出来的——BeautifulSoup只能解析静态HTML,抓不到JS生成的链接。

这种情况可以用Selenium模拟浏览器加载页面,然后提取真实链接:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
import requests

# 配置无头浏览器(不打开可视化窗口)
chrome_options = Options()
chrome_options.add_argument("--headless=new")
chrome_options.add_argument("--disable-gpu")
chrome_options.add_argument("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")

driver = webdriver.Chrome(options=chrome_options)
driver.get("https://www.xcelenergy.com/working_with_us/municipalities/community_energy_reports")
driver.implicitly_wait(5)  # 等待页面元素加载

# 提取所有xls链接
xls_links = []
for a_tag in driver.find_elements(By.XPATH, "//a[contains(@href, '.xls')]"):
    full_url = a_tag.get_attribute("href")
    if full_url not in xls_links:
        xls_links.append(full_url)

# 下载文件
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"}
for full_url in xls_links:
    try:
        response = requests.get(full_url, headers=headers)
        response.raise_for_status()
        filename = full_url.split("/")[-1]
        with open(filename, "wb") as f:
            f.write(response.content)
        print(f"成功下载: {filename}")
    except requests.exceptions.RequestException as e:
        print(f"下载失败 {full_url}: {e}")

driver.quit()

最后排查小技巧

  • 用浏览器的开发者工具(F12)查看网络请求:找到下载xls的请求,复制它的完整URL和请求头,和你脚本里的对比,就能快速定位问题。
  • 有些网站会对频繁请求的IP进行封禁,如果多次请求失败,可以尝试添加延迟(比如time.sleep(2))或者使用代理IP。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 06:57:13