在 scrapy 中,怎么让 yield Request(url,callback)中的 callback 函数执行完成后才执行 yield Request(url,callback)其后的语句?

2017-11-17 14:33:17 +08:00
 scb20100708

我需要先用回调函数 callback 改变类变量,然后使用类变量,但发现程序的实际执行是不等待 yield Request(url,callback)中的 callbak 函数执行完成,便执行其后的语句了。怎么办呢?

写了个程序来表达我的意图:

# -*- coding: utf-8 -*-

from scrapy import Spider, Request

class ZhihuSpider(Spider):
    name = "debug_zhihu"
    allowed_domains = ["www.zhihu.com"]
    list_for_test = []

    def start_requests(self):
        yield Request('https://www.zhihu.com/people/excited-vczh/following', self.change_list)
        print('after sent Request statement,list_for_test:', self.list_for_test)
		# 想打印出“[0,1,2,3,4]”,结果打印出"[]"

    def change_list(self):
        for each_item in range(0, 5):
            self.list_for_test.append(each_item)
6425 次点击
所在节点    Python
14 条回复
scb20100708
2017-11-17 14:49:10 +08:00
发现补充中的代码错了,def change_list(self):应是 def change_list(self,response):
改后也输出不了想输出的"[0,1,2,3,4]"
leavic
2017-11-17 14:50:25 +08:00
把 print 写进 callback 函数的最后。。。。。
scb20100708
2017-11-17 15:00:18 +08:00
@leavic
还有别的方法吗?实际代码还有函数“ change_list2 ”也要改变类变量,想在所有改变执行完后再处理类变量。
860670496
2017-11-17 15:21:30 +08:00
请参考:
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317799226173f45ce40636141b6abc8424e12b5fb27000

如果一个函数定义中包含 yield 关键字,那么这个函数就不再是一个普通函数,而是一个 generator:

这里,最难理解的就是 generator 和函数的执行流程不一样。函数是顺序执行,遇到 return 语句或者最后一行函数语句就返回。而变成 generator 的函数,在每次调用 next()的时候执行,遇到 yield 语句返回,再次执行时从上次返回的 yield 语句处继续执行。

所以直接用啃 scrapy 的方法来学 python 不是个好选择,这个坑我也掉过,就是看教程的时候完全是表面上的理解生成器的概念,一用起来就傻了,必须得动手写几个才能彻底明白
knightdf
2017-11-17 15:36:36 +08:00
把 yield Request(url,callback)其后的语句放在 callback 的后面执行
leavic
2017-11-17 15:50:23 +08:00
@scb20100708 没有什么好方法了,你的需求就应该是把函数放进 callback 里面。
iyaozhen
2017-11-17 16:05:06 +08:00
只能 callback 吧。回调地狱就是那么来的
scb20100708
2017-11-17 19:11:06 +08:00
@860670496
你给的参考资料看过了,我想不是 yield 的问题,因为 callback 函数会执行,只不过在 callback 函数执行前就执行 yield Request(url,callback)后的语句了。
@leavic @knightdf @iyaozhen
好的,谢谢各位
hcnhcn012
2017-11-17 19:29:44 +08:00
机制就是这样,为了效率,要是你 callback 里面花了一个很长时间的的 IO 操作,整个框架都在等你的 callback 然后 yield 带出从而发生阻塞那效率会很低,具体怎么实现的话就要结合 twisted 看源码了
RadishWind
2017-11-17 19:32:43 +08:00
还没有实验 加个修饰器行不行?在修饰器中等待?
zhijiansha
2017-11-17 19:46:01 +08:00
scrapy 是异步的,reuqest 请求也是放进队列的
larsenlouis
2017-11-17 20:24:37 +08:00
“回调函数 callback 改变类变量,然后使用类变量”
是发出单个请求->callback 链->print,还是发出所有的请求->完成每个请求的 callback 链->print ?
后者可以用 def spider_closed(self, spider) 参考 https://doc.scrapy.org/en/latest/topics/signals.html
scb20100708
2017-11-17 20:54:35 +08:00
@hcnhcn012
谢谢,twisted 还没用过,这个问题先搁这儿吧
@RadishWind
感觉和把 print 语句放在 callback 中一样,谢谢哈
@zhijiansha
谢谢
scb20100708
2017-11-18 16:59:18 +08:00
@larsenlouis
谢谢,我想要实现的正是你说的“发出所有的请求->完成每个请求的 callback 链->print ? “。
方法可行,谢谢啦。
还找到了一个办法,直接在类中加个函数:
def closed(self, reason):
print(list_for_test)
参考:
https://stackoverflow.com/a/33312325/7011350

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/407231

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX