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

Scrapy爬取下载文件报Missing scheme及IsADirectoryError问题

问题描述

使用Scrapy框架从目标网站下载数据文件时,先后触发两个报错:

  1. 第一个报错信息如下:

raise ValueError(f'Missing scheme in request url: {self._url}')
ValueError: Missing scheme in request url: h

已确认提取的链接可正常传递到回调函数,无法定位错误触发点,初始实现代码如下:

爬虫主文件代码

import scrapy
from nhs.items import DownfilesItem

class NhsScapeSpider(scrapy.Spider):
    name = 'nhs_scape'
    #allowed_domains = ['nh']
    start_urls = ['https://www.england.nhs.uk/statistics/statistical-work-areas/ae-waiting-times-and-activity/ae-attendances-and-emergency-admissions-2021-22/']

    custom_settings = {
        'USER_AGENT':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
    }

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(
                url = url,
                callback = self.parse
            )

    def parse(self, response):
        side_panel = response.xpath("//aside[@class='subnav group minimal_nav desktop-only']//ul[@class='children']//li")
        for years in side_panel:
            year_links = years.xpath('.//a/@href').get()
            yield response.follow(year_links, callback = self.download_files)


    def download_files(self, response):
        test_files = response.xpath("//article[@class='rich-text']//p")
        month_files = response.xpath("//article[@class='rich-text']//h3")
        
        for files, mn in zip(test_files, month_files):
            all_files = files.xpath('.//a//@href').getall()
            all_file_names = files.xpath('.//a//text()').getall()
            month_year = mn.xpath('.//text()').get()

            for ind_files,ind_text in zip(all_files, all_file_names):
                item = DownfilesItem()

                if '.xls' in ind_files and 'Monthly' in ind_text:
                    item['file_urls'] = ind_files
                    item['original_file_name'] = ind_text
                    yield item

                elif '.xls' in ind_files and 'Week' in ind_text:
                    item['file_urls'] = ind_files
                    item['original_file_name'] = ind_text
                    yield item

Items.py代码

import scrapy
class DownfilesItem(scrapy.Item):
    # define the fields for your item here like:
    file_urls = scrapy.Field()
    original_file_name = scrapy.Field()

Pipelines.py代码

from scrapy.pipelines.files import FilesPipeline
class DownfilesPipeline(FilesPipeline):
    def file_path(self, request, response=None, info=None):
        file_name: str = request.url.split("/")[1]
        return file_name

Settings.py配置

ITEM_PIPELINES = {'nhs.pipelines.DownfilesPipeline': 150}
FILES_STORE = "Files"
  1. 调整代码后触发第二个报错:
IsADirectoryError: [Errno 21] Is a directory: 'Files/'

初步判断报错与FILES_STORE = "Files"配置相关,但移除该配置后程序不再抛错,却无法下载任何文件。


错误原因

两个报错分别由两处代码逻辑错误导致,和FILES_STORE配置本身无关:

  1. Missing scheme报错原因:Scrapy内置的FilesPipeline要求Item中file_urls字段必须传入列表类型的URL集合,代码中直接将单个字符串URL赋值给file_urls,Scrapy会将字符串作为可迭代对象逐字符遍历,第一个遍历到的字符是h(来自https://开头),将其作为独立URL发起请求时,自然会触发缺少协议头的报错。
  2. IsADirectoryError报错原因:自定义的file_path方法逻辑错误,对URL按/分割后取索引为1的元素,对于标准HTTP URLhttps://example.com/path/file.xls,分割后结果为['https:', '', 'example.com', 'path', 'file.xls'],索引1位置是空字符串,相当于返回空路径作为保存文件名,Scrapy会直接尝试向Files/目录本身写入文件,触发目录不可写为文件的错误。

修复方案

按以下步骤修改代码即可解决问题:

  • 修正file_urls字段赋值:给file_urls传入列表格式的URL,同时建议用response.urljoin处理相对路径,确保URL完整带协议头。修改download_files方法中赋值部分:
# 原代码 item['file_urls'] = ind_files 替换为
item['file_urls'] = [response.urljoin(ind_files)]
  • 修正Pipelines中文件路径提取逻辑:不要通过固定索引取文件名,正确提取URL最后一段作为文件名,避免返回空路径:
from scrapy.pipelines.files import FilesPipeline
from urllib.parse import urlparse
import os

class DownfilesPipeline(FilesPipeline):
    def file_path(self, request, response=None, info=None):
        # 解析URL获取路径部分,提取最后一段作为文件名
        parsed_url = urlparse(request.url)
        file_name = os.path.basename(parsed_url.path)
        return file_name
  • 保留FILES_STORE配置:该配置是FilesPipeline必填项,指定文件保存的根目录,配置为相对路径时会在项目根目录下自动创建对应文件夹,确保运行爬虫的用户对项目目录有读写权限即可。
  • (可选)放开allowed_domains配置,填入正确域名www.england.nhs.uk,避免链接被OffsiteMiddleware过滤。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 23:30:09