V2EX 首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
V2EX  ›  Python

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

  •  
  •   scb20100708 · 31 天前 · 522 次点击
    这是一个创建于 31 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我需要先用回调函数 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)
    
    14 回复  |  直到 2017-11-18 16:59:18 +08:00
        1
    scb20100708   31 天前
    发现补充中的代码错了,def change_list(self):应是 def change_list(self,response):
    改后也输出不了想输出的"[0,1,2,3,4]"
        2
    leavic   31 天前
    把 print 写进 callback 函数的最后。。。。。
        3
    scb20100708   31 天前
    @leavic
    还有别的方法吗?实际代码还有函数“ change_list2 ”也要改变类变量,想在所有改变执行完后再处理类变量。
        4
    860670496   31 天前
    请参考:
    https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014317799226173f45ce40636141b6abc8424e12b5fb27000

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

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

    所以直接用啃 scrapy 的方法来学 python 不是个好选择,这个坑我也掉过,就是看教程的时候完全是表面上的理解生成器的概念,一用起来就傻了,必须得动手写几个才能彻底明白
        5
    knightdf   31 天前
    把 yield Request(url,callback)其后的语句放在 callback 的后面执行
        6
    leavic   31 天前   ♥ 1
    @scb20100708 没有什么好方法了,你的需求就应该是把函数放进 callback 里面。
        7
    iyaozhen   31 天前 via Android
    只能 callback 吧。回调地狱就是那么来的
        8
    scb20100708   30 天前
    @860670496
    你给的参考资料看过了,我想不是 yield 的问题,因为 callback 函数会执行,只不过在 callback 函数执行前就执行 yield Request(url,callback)后的语句了。
    @leavic @knightdf @iyaozhen
    好的,谢谢各位
        9
    hcnhcn012   30 天前 via iPhone
    机制就是这样,为了效率,要是你 callback 里面花了一个很长时间的的 IO 操作,整个框架都在等你的 callback 然后 yield 带出从而发生阻塞那效率会很低,具体怎么实现的话就要结合 twisted 看源码了
        10
    RadishWind   30 天前
    还没有实验 加个修饰器行不行?在修饰器中等待?
        11
    zhijiansha   30 天前
    scrapy 是异步的,reuqest 请求也是放进队列的
        12
    larsenlouis   30 天前   ♥ 1
    “回调函数 callback 改变类变量,然后使用类变量”
    是发出单个请求->callback 链->print,还是发出所有的请求->完成每个请求的 callback 链->print ?
    后者可以用 def spider_closed(self, spider) 参考 https://doc.scrapy.org/en/latest/topics/signals.html
        13
    scb20100708   30 天前
    @hcnhcn012
    谢谢,twisted 还没用过,这个问题先搁这儿吧
    @RadishWind
    感觉和把 print 语句放在 callback 中一样,谢谢哈
    @zhijiansha
    谢谢
        14
    scb20100708   29 天前
    @larsenlouis
    谢谢,我想要实现的正是你说的“发出所有的请求->完成每个请求的 callback 链->print ? “。
    方法可行,谢谢啦。
    还找到了一个办法,直接在类中加个函数:
    def closed(self, reason):
    print(list_for_test)
    参考:
    https://stackoverflow.com/a/33312325/7011350
    DigitalOcean
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   鸣谢   ·   2650 人在线   最高记录 3541   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.0 · 63ms · UTC 08:50 · PVG 16:50 · LAX 00:50 · JFK 03:50
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1