![](/img/trans.png)
[英]How to compare each Scrapy spider item with another Scrapy spider items?
[英]scrapy how spider returns value to another spider
我正在抓取的网站包含许多玩家,当我点击任何玩家时,我可以进入他的页面。
网站结构如下:
<main page>
<link to player 1>
<link to player 2>
<link to player 3>
..
..
..
<link to payer n>
</main page>
当我点击任何链接时,我会转到播放器的页面,如下所示:
<player name>
<player team>
<player age>
<player salary>
<player date>
我想废弃年龄在20到25岁之间的所有球员。
使用第一个蜘蛛刮取主页面。
使用第一个蜘蛛获取链接。
使用第二个蜘蛛抓取每个链接。
使用第二个蜘蛛获取玩家信息。
使用管道将此信息保存在json文件中 。
如何将second spider
的date
值返回到第first spider
我构建了自己的middelware,并重写了process_spider_output
。 它允许我打印请求,但我不知道我还应该做什么,以便将该date
值返回给我的第一个蜘蛛
任何帮助表示赞赏
以下是一些代码:
def parse(self, response):
sel = Selector(response)
Container = sel.css('div[MyDiv]')
for player in Container:
extract LINK and TITLE
yield Request(LINK, meta={'Title': Title}, callback = self.parsePlayer)
def parsePlayer(self,response):
player = new PlayerItem();
extract DATE
return player
您需要做的就是检查parsePlayer
的date
,并仅返回相关的date
。
def parsePlayer(self,response):
player = new PlayerItem();
extract DATE
if DATE == some_criteria:
yield player
例如,如果您遇到性能问题(您正在废弃太多链接,并且您在某些限制之后不需要那些链接)。
鉴于Scrapy在非对称请求中工作,没有真正好的方法可以做到这一点。 您唯一的方法是尝试强制线性行为而不是默认的并行请求。
让我解释。 当你有两个这样的回调时,在默认行为上,scrapy将首先解析第一页(主页)并在其队列中放入对玩家页面的所有请求。 在没有等待第一页完成报废的情况下 ,它将开始处理这些玩家页面请求(不一定按照它们找到的顺序)。
因此,当您获得播放器页面p
过期的信息时,它已经发送了内部请求p+1
, p+2
... p+m
( m
基本上是一个随机数)并且可能已经开始处理其中一些要求。 可能在 p
之前甚至是p+1
(没有固定的顺序,请记住)。
因此,如果您保留此模式,则无法完全停在正确的页面,并且无法与parsePlayer
parse
进行交互。
您可以做的是强制它按顺序跟踪链接,以便您完全控制。 缺点是它会对性能造成很大影响 :如果scrapy一个接一个地跟随每个链接,则意味着它不能像往常那样同时处理它们并且它会减慢速度。
代码可能是这样的:
def parse(self, response):
sel = Selector(response)
self.container = sel.css('div[MyDiv]')
return self.increment(0)
# Function that will yield the request for player n°index
def increment(index):
player = self.container[index] # select current player
extract LINK and TITLE
yield Request(LINK, meta={'Title': Title, 'index': index}, callback=self.parsePlayer)
def parsePlayer(self,response):
player = new PlayerItem();
extract DATE
yield player
if DATE == some_criteria:
index = response.meta['index'] + 1
self.increment(index)
这样scrapy将获得主页面,然后是第一个玩家,然后是主页面,然后是第二个玩家,然后是主要等等......直到找到不符合标准的日期。 然后没有回调主函数,蜘蛛停止。
如果你还需要增加主页面的索引(例如,如果有n个主页面),这会变得有点复杂,但这个想法保持不变。
像(根据罗宾的答案):
class PlayerSpider(Spider):
def __init__(self):
self.player_urls = []
self.done = False # flag to know when a player with bday out of range found
def extract_player_urls(self, response):
sel = Selector(response)
self.player_urls.extend(extracted player links)
def parse(self, response):
self.extract_player_urls(response)
for i in xrange(10):
yield Request(self.player_urls.pop(), parse=self.parse_player)
def parse_player(self, response):
if self.done:
return
... extract player birth date
if bd_date not in range:
self.done = True
... somehow clear downloader queue
return
... create and fill item
yield item
yield Request(self.player_urls.pop(), parse=self.parse_player)
首先,我要感谢@ warwaruk ,@ Robin在这个问题上帮助我。
最好的感谢我的老师@ pault
我找到了解决方案,这里是算法:
在每个玩家的回调中:
4.1提取玩家的信息。
4.2检查愤怒中的日期,如果不是:什么也不做,如果是:检查这是否是主播放器列表中的最后一次播放。 如果是,则回调到第二个主页面。
def parse(self, response):
currentPlayer = 0
for each player in Players:
currentPlayer +=1
yield Request(player.link, meta={'currentPlayer':currentPlayer, 'numberOfPlayers':len(Players),callback = self.parsePlayer)
def parsePlayer(self,response):
currentPlayer = meta['currentPlayer]
numberOfPlayers = meta['numberOfPlayers']
extract player's information
if player[date] in range:
if currentPlayer == numberOfPlayers:
yield(linkToNextMainPage, callback = self.parse)
yield playerInformatoin #in order to be written in JSON file
else:
yield playerInformaton
它完美地工作:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.