Cod*_*eyB 72 python web-crawler scrapy
我有一个包含多个蜘蛛的scrapy项目.有什么方法可以定义哪些管道用于哪个蜘蛛?并非我所定义的所有管道都适用于每个蜘蛛.
谢谢
Ran*_*ngh 99
只需从主设置中删除所有管道,然后在蜘蛛内部使用它.
这将为每个蜘蛛定义用户的管道
class testSpider(InitSpider):
name = 'test'
custom_settings = {
'ITEM_PIPELINES': {
'app.MyPipeline': 400
}
}
Run Code Online (Sandbox Code Playgroud)
mst*_*ger 35
基于Pablo Hoffman的解决方案,您可以在process_itemPipeline对象的方法上使用以下装饰器,以便它检查pipeline蜘蛛的属性是否应该执行.例如:
def check_spider_pipeline(process_item_method):
@functools.wraps(process_item_method)
def wrapper(self, item, spider):
# message template for debugging
msg = '%%s %s pipeline step' % (self.__class__.__name__,)
# if class is in the spider's pipeline, then use the
# process_item method normally.
if self.__class__ in spider.pipeline:
spider.log(msg % 'executing', level=log.DEBUG)
return process_item_method(self, item, spider)
# otherwise, just return the untouched item (skip this step in
# the pipeline)
else:
spider.log(msg % 'skipping', level=log.DEBUG)
return item
return wrapper
Run Code Online (Sandbox Code Playgroud)
为使此装饰器正常工作,spider必须具有一个管道属性,其中包含要用于处理项目的Pipeline对象的容器,例如:
class MySpider(BaseSpider):
pipeline = set([
pipelines.Save,
pipelines.Validate,
])
def parse(self, response):
# insert scrapy goodness here
return item
Run Code Online (Sandbox Code Playgroud)
然后在一个pipelines.py文件中:
class Save(object):
@check_spider_pipeline
def process_item(self, item, spider):
# do saving here
return item
class Validate(object):
@check_spider_pipeline
def process_item(self, item, spider):
# do validating here
return item
Run Code Online (Sandbox Code Playgroud)
所有Pipeline对象仍然应该在ITEM_PIPELINES中的设置中定义(按照正确的顺序 - 更改将很好,以便也可以在Spider上指定顺序).
eLR*_*uLL 12
这里给出的其他解决方案都很好,但我认为它们可能很慢,因为我们实际上并没有使用每个蜘蛛的管道,而是每次返回一个项目时检查是否存在管道(在某些情况下,这可能会达到百万).
完全禁用(或启用)每个蜘蛛的功能的好方法是使用custom_setting和from_crawler所有扩展,如下所示:
pipelines.py
from scrapy.exceptions import NotConfigured
class SomePipeline(object):
def __init__(self):
pass
@classmethod
def from_crawler(cls, crawler):
if not crawler.settings.getbool('SOMEPIPELINE_ENABLED'):
# if this isn't specified in settings, the pipeline will be completely disabled
raise NotConfigured
return cls()
def process_item(self, item, spider):
# change my item
return item
Run Code Online (Sandbox Code Playgroud)
settings.py
ITEM_PIPELINES = {
'myproject.pipelines.SomePipeline': 300,
}
SOMEPIPELINE_ENABLED = True # you could have the pipeline enabled by default
Run Code Online (Sandbox Code Playgroud)
spider1.py
class Spider1(Spider):
name = 'spider1'
start_urls = ["http://example.com"]
custom_settings = {
'SOMEPIPELINE_ENABLED': False
}
Run Code Online (Sandbox Code Playgroud)
当您检查时,我们已指定custom_settings将覆盖指定的内容settings.py,并且我们正在禁用SOMEPIPELINE_ENABLED此蜘蛛.
现在当你运行这个蜘蛛时,请检查以下内容:
[scrapy] INFO: Enabled item pipelines: []
Run Code Online (Sandbox Code Playgroud)
现在scrapy已经完全禁用了管道,并没有为整个运行而烦恼.检查这也适用于scrapy extensions和middlewares.
Fra*_*ila 10
我至少可以想到四种方法:
scrapy settings在每次调用spider之间更改管道设置default_settings['ITEM_PIPELINES']命令类定义到您希望该命令的管道列表.见本例的第6行.process_item()检查它正在运行的蜘蛛是什么,如果该蜘蛛应该被忽略则不执行任何操作.请参阅使用每个蜘蛛资源的示例来帮助您入门.(这似乎是一个丑陋的解决方案,因为它紧密地耦合了蜘蛛和物品管道.你可能不应该使用这个.)您可以name在管道中使用spider 的属性
class CustomPipeline(object)
def process_item(self, item, spider)
if spider.name == 'spider1':
# do something
return item
return item
Run Code Online (Sandbox Code Playgroud)
以这种方式定义所有管道可以实现您想要的.
最简单有效的解决方案是在每个蜘蛛本身中设置自定义设置。
custom_settings = {'ITEM_PIPELINES': {'project_name.pipelines.SecondPipeline': 300}}
Run Code Online (Sandbox Code Playgroud)
之后,您需要在 settings.py 文件中设置它们
ITEM_PIPELINES = {
'project_name.pipelines.FistPipeline': 300,
'project_name.pipelines.SecondPipeline': 400
}
Run Code Online (Sandbox Code Playgroud)
这样每个蜘蛛都会使用各自的管道。
小智 6
您可以像这样在蜘蛛内部设置项目管道设置:
class CustomSpider(Spider):
name = 'custom_spider'
custom_settings = {
'ITEM_PIPELINES': {
'__main__.PagePipeline': 400,
'__main__.ProductPipeline': 300,
},
'CONCURRENT_REQUESTS_PER_DOMAIN': 2
}
Run Code Online (Sandbox Code Playgroud)
然后,我可以通过向加载器/返回的项目添加一个值来拆分管道(甚至使用多个管道),该值标识蜘蛛的哪个部分发送了项目。这样我就不会得到任何 KeyError 异常,我知道哪些项目应该可用。
...
def scrape_stuff(self, response):
pageloader = PageLoader(
PageItem(), response=response)
pageloader.add_xpath('entire_page', '/html//text()')
pageloader.add_value('item_type', 'page')
yield pageloader.load_item()
productloader = ProductLoader(
ProductItem(), response=response)
productloader.add_xpath('product_name', '//span[contains(text(), "Example")]')
productloader.add_value('item_type', 'product')
yield productloader.load_item()
class PagePipeline:
def process_item(self, item, spider):
if item['item_type'] == 'product':
# do product stuff
if item['item_type'] == 'page':
# do page stuff
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20718 次 |
| 最近记录: |