如何修复Scrapy的Unsupported URL scheme错误?
解决Scrapy + Flask 集成中的URL Scheme错误及其他问题
你遇到的核心错误是URL缺少HTTP/HTTPS协议头,但代码里还有几个其他需要修正的问题,我来一步步帮你解决:
1. 直接触发错误的根源:URL Scheme缺失
Scrapy必须依赖明确的http://或https://协议头才能识别并处理请求,你传入的www.google.com没有协议前缀,Scrapy会判定它的URL Scheme为空,从而抛出Unsupported URL scheme ''错误。
修复方式:
在接收请求或初始化爬虫时,自动为URL补充协议头:
# 在Flask路由中处理URL url = request.json['url'] if not url.startswith(('http://', 'https://')): url = f'https://{url}'
也可以在爬虫的__init__方法中做相同检查,确保start_urls里的URL均带有合法协议。
2. 代码中的语法错误
你写的self.start_urlsappend(url)存在语法问题,正确写法是:
self.start_urls.append(url)
更简洁的方式是直接初始化列表:
self.start_urls = [url]
3. 爬虫运行逻辑的致命问题
你当前用subprocess调用Scrapy的方式有两个关键缺陷:
- 你传递了
self.start_urls(一个列表)给-a url=参数,这会让Scrapy收到类似['www.google.com']的字符串,显然不是合法URL。 - 更重要的是:subprocess启动的Scrapy进程与Flask进程完全独立,内存不共享,因此
self.news不会被Scrapy进程填充,最终返回的是空列表。
推荐修复方案:用Scrapy的CrawlerProcess直接在Flask进程内运行爬虫
这种方式可以直接获取爬虫结果,无需依赖外部文件或进程间通信,更符合Python应用的集成逻辑。
修改后的完整代码示例:
from flask import Flask, jsonify, request import scrapy from scrapy.crawler import CrawlerProcess from scrapy.utils.project import get_project_settings from scrapy import signals from scrapy.signalmanager import dispatcher app = Flask(__name__) class ClassSpider(scrapy.Spider): name = 'mySpider' def __init__(self, url, nbrPage): self.pages = nbrPage # 确保URL带合法协议头 if not url.startswith(('http://', 'https://')): url = f'https://{url}' self.start_urls = [url] def parse(self, response): # 替换为你的实际解析逻辑,示例提取页面标题 title = response.css('h1::text').get() if title: # 使用yield返回item,这是Scrapy的标准做法 yield {'title': title.strip()} # 分页逻辑示例(根据你的需求调整) if self.pages > 1: next_page = response.css('a.next-page::attr(href)').get() if next_page: self.pages -= 1 yield response.follow(next_page, self.parse) def run_spider(url, nbrPage): """辅助函数:运行爬虫并收集结果""" results = [] def collect_item(item, response, spider): results.append(item) # 连接Scrapy信号,实时收集爬取到的item dispatcher.connect(collect_item, signal=signals.item_scraped) # 初始化爬虫进程 process = CrawlerProcess(get_project_settings()) process.crawl(ClassSpider, url=url, nbrPage=nbrPage) process.start() # 阻塞直到爬虫运行完成 return results @app.route('/', methods=['POST']) def getNews(): try: url = request.json['url'] news_data = run_spider(url, 2) return jsonify({'data': news_data}) except Exception as e: return jsonify({'error': str(e)}), 400 if __name__ == "__main__": app.run(debug=True)
额外注意事项
- 确保你的Scrapy项目存在
settings.py文件(可通过scrapy startproject生成项目框架,再将爬虫放入对应目录),或手动配置CrawlerProcess的运行参数。 - Flask默认是多线程模式,使用信号收集结果是线程安全的,比用类属性存储结果更可靠。
- 如果你的爬虫需要处理大量请求,建议引入异步任务队列(如Celery)来运行爬虫,避免阻塞Flask主线程影响服务响应。
内容的提问来源于stack exchange,提问作者Med ADDOU
相关产品推荐
相关产品推荐

