假设我有一个看似这样的抓取项目
{
name: "Foo",
country: "US",
url: "http://..."
}
在一个管道中,我想对URL发出GET请求,并检查一些标题,如content_type和status。当标题不符合某些条件时,我想删除该项目。像
class MyPipeline(object):
def process_item(self, item, spider):
request(item['url'], function(response) {
if (...) {
raise DropItem()
}
return item
}, function(error){
raise DropItem()
})
使用管道无法闻到这样的气味。你怎么看?任何想法如何实现这一目标?
蜘蛛:
import scrapy
import json
class StationSpider(scrapy.Spider):
name = 'station'
start_urls = ['http://...']
def parse(self, response):
jsonResponse = json.loads(response.body_as_unicode())
for station in jsonResponse:
yield station
答案 0 :(得分:6)
简单方法
import requests
def process_item(self, item, spider):
response = requests.get(item['url'])
if r.status_code ...:
raise DropItem()
elif response.text ...:
raise DropItem()
else:
return item
Scrapy方式
现在我认为你不应该在管道内做这件事,你应该在蜘蛛内部处理它而不是产生一个项目而是一个请求,然后产生该项目。
现在,如果您仍想在管道中包含scrapy请求,可以执行以下操作:
class MyPipeline(object):
def __init__(self, crawler):
self.crawler = crawler
@classmethod
def from_crawler(cls, crawler):
return cls(crawler)
def process_item(self, item, spider):
...
self.crawler.engine.crawl(
Request(
url='someurl',
callback=self.custom_callback,
),
spider,
)
# you have to drop the item, and send it again after your check
raise DropItem()
# YES, you can define a method callback inside the same pipeline
def custom_callback(self, response):
...
yield item
检查我们是否在管道内模拟蜘蛛回调的相同行为。当你想要做一个额外的请求时,你需要找出一种总是丢弃项目的方法,并且只是通过额外的回调传递那些项目。
一种方法是发送不同类型的项目,并在管道的process_item
内进行检查:
def process_item(self, item, spider):
if isinstance(item, TempItem):
...
elif isinstance(item, FinalItem):
yield item