Scrapy使用Input Processor转绝对URL遇loader_context问题求助
解决Scrapy中Input Processor转换相对URL为绝对URL的问题
首先咱们得明确:要把相对URL转成绝对URL,核心是需要当前页面的Base URL(也就是response的url或者response的base_url),而loader_context就是用来把这个Base URL传递给Input Processor的关键桥梁。我给你一步步拆解正确的用法:
1. 自定义Input Processor类
先在items.py里写一个自定义的Input Processor,它会从loader_context里获取base_url,再把相对URL转成绝对URL:
from scrapy.loader.processors import TakeFirst from urllib.parse import urljoin class AbsoluteUrlProcessor: def __init__(self, base_url=None): self.base_url = base_url def __call__(self, values): # 取抓取到的第一个相对URL值处理 relative_url = values[0] if values else '' if self.base_url and relative_url: return urljoin(self.base_url, relative_url) return relative_url
如果你习惯用MapCompose的写法,也可以这样定义处理函数:
from urllib.parse import urljoin def make_absolute_url(relative_url, loader_context): base_url = loader_context.get('base_url') if base_url and relative_url: return urljoin(base_url, relative_url) return relative_url
2. 在Item类中配置Input Processor
接下来在items.py的Item定义里,把处理器和目标字段绑定:
方式一:用自定义类绑定
import scrapy from scrapy.loader.processors import TakeFirst class MyItem(scrapy.Item): detail_url = scrapy.Field( input_processor=AbsoluteUrlProcessor(), output_processor=TakeFirst() )
方式二:用MapCompose绑定
import scrapy from scrapy.loader.processors import MapCompose, TakeFirst class MyItem(scrapy.Item): detail_url = scrapy.Field( input_processor=MapCompose(make_absolute_url), output_processor=TakeFirst() )
3. 在Spider中传递loader_context到ItemLoader
这是最容易踩坑的一步!创建ItemLoader时,一定要把当前response的URL传入上下文:
from scrapy.spiders import Spider from myproject.items import MyItem from scrapy.loader import ItemLoader class MySpider(Spider): name = 'my_spider' start_urls = ['https://example.com'] def parse(self, response): # 方式一:传入response,Scrapy会自动把response.url存入context的response_url字段 loader = ItemLoader(item=MyItem(), response=response) # 方式二:手动指定base_url到context # loader = ItemLoader(item=MyItem()) # loader.context['base_url'] = response.url # 抓取页面中的相对URL,比如<a href="/detail/123">这类链接 loader.add_xpath('detail_url', '//a/@href') yield loader.load_item()
如果用方式一,你可以把处理器里的base_url改成从loader_context.get('response_url')获取,不用手动传值。
常见误区提醒
- 别漏传上下文:如果Input Processor依赖
loader_context里的值,但你没传递,肯定转不了绝对URL,这是最多人犯的错。 - 处理空值:要考虑抓取到的相对URL为空的情况,避免程序报错。
- 用
urljoin而不是字符串拼接:urljoin能自动处理各种复杂的相对路径(比如../开头的),比自己拼接字符串靠谱得多。
这样一套流程走下来,你的Input Processor就能正确把相对URL转成绝对URL啦!
内容的提问来源于stack exchange,提问作者Frank
相关产品推荐
相关产品推荐

