如何在Scrapy中无需URL请求传递数据?Python3及最新版本适配
解决Scrapy无需URL请求传递CSV数据的问题
你碰到的这个TypeError其实很好理解——Scrapy的Request对象要求第一个参数必须是有效的字符串URL,你传了None,自然就触发报错了。要实现不发起实际网络请求就把CSV数据传递到回调函数,根本不需要硬塞None给Request,咱们可以用两种更合理的方式解决:
方法1:用虚拟URL构造Request(最简单的方案)
我们可以用一个不会产生实际网络请求的虚拟URL(比如about:blank),把CSV数据放在meta里传递,这样既符合Scrapy的Request规范,又不会真的发起请求:
修改你start_requests方法里的yield语句:
yield scrapy.Request( url='about:blank', # 虚拟URL,不会实际发起网络请求 meta=items, dont_filter=True, # 避免被Scrapy的去重过滤器拦截 callback=self.parse_it )
修改后,Scrapy会创建一个合法的Request对象,但不会对about:blank发起实际请求,你的parse_it回调函数依然可以通过response.meta拿到CSV里的所有数据,原来的逻辑完全不用改动。
方法2:直接生成Response对象(更优雅的方案)
如果你不想创建Request对象,也可以直接生成一个空的Response对象并yield它,这样回调函数会直接被触发,完全绕开请求调度流程:
首先需要导入Response类,然后修改start_requests里的yield部分:
from scrapy.http import Response # ... 其他原有代码 ... yield Response( url='about:blank', meta=items )
你的parse_it函数不需要做任何修改,依然可以正常读取response.meta里的所有数据,而且这个方式不会创建Request对象,完全没有网络请求的开销。
额外小优化
其实你还可以简化代码,不用把每个字段都单独提取一遍再放进字典,直接用zip函数匹配字段名和行数据:
# 假设CSV的列顺序是url,title,developer,price,desc,rating field_names = ['url', 'title', 'developer', 'price', 'desc', 'rating'] items = dict(zip(field_names, row))
这样代码更简洁,也不容易因为字段顺序变动而出错。
内容的提问来源于stack exchange,提问作者MD Palash Babu
相关产品推荐
相关产品推荐

