Scrapy的Promisestyle工作流

scrapy-promise的Python项目详细描述


卑鄙的诺言

Promise API用于发出垃圾请求。在

用法和示例

fromscrapy_promiseimportfetch

这里的Promise与JavaScript中的Promise类似。如果你是一个新的承诺,一个伟大的起点将是MDN的 Promise API reference 以及Using Promises指南。在

创建和提出请求

fetch()接受scrapy.http.Request接受的所有参数,除了callback和{}

^{pr2}$

fetch()返回一个Promise对象,它是迭代器/生成器。您可以直接在start_requests中返回它, 或者yield from它在现有回调中。在

添加处理程序

如果您只调用fetch()并从中屈服,那么它所做的就是在请求完成后存储响应:

request=fetch('https://httpbin.org/ip')yield fromrequest# When the request is done>>>request.is_fulfilledTrue>>>request.get()<200https://httpbin.org/ip>

fetch()返回Promise对象。调用它的.then()方法并提供一个可调用的,一旦有响应,Promise将调用它。在

.then()返回另一个Promise,您可以yield from

defon_fulfill(response:TextResponse):# You can yield items from your handler# just like you would in a Scrapy callbackyieldItem(response)>>>yield fromfetch(...).then(on_fulfill)

您还可以使用.catch()附加一个错误处理程序,它将收到Twisted ^{}或异常:

defon_reject(exc:Union[Failure,Exception]):ifisinstance(exc,Failure):exc=exc.value...>>>yield fromfetch(...).then(on_fulfill).catch(on_reject)# will catch both exceptions during the request# and exceptions raised in on_fulfill

分支和链接

因为.then().catch()返回另一个Promise,所以可以链接其他处理程序。在

后续处理程序 将接收上一个处理程序的return值。这与普通的垃圾回调不同, 如果返回值无效:

yield from(fetch('https://httpbin.org/ip').then(parse_json)# returns dict.then(create_item)# will be passed the dict from the previous handler.catch(lambdaexc:logging.getLogger().error(exc)))

Dynamic chaining:如果在处理程序中返回另一个fetch()请求,则该请求将被调度, 下一个处理程序将用这个新请求的Response调用。这样可以安排多个 按顺序请求。在

yield from(fetch('https://httpbin.org/ip')# A second Request is created from the response of the first one and is scheduled..then(lambdaresponse:fetch(json.loads(response.text)['origin'])).then(lambdaresponse:(yieldItem(response))).catch(lambdaexc:logging.getLogger().error(exc)))

请注意,只有您返回的请求才会连接到随后生成的处理程序Request 中间的处理程序将由Scrapy直接调度。在

您还可以将多个处理程序附加到一个请求,并且将按照它们之前的顺序对它们进行求值 声明:

resource=fetch(...)resource.then(save_token)resource.then(parse_html).catch(log_error)resource.then(next_page).catch(stop_spider)yield fromresource# Evaluating any Promise in a chain/branch causes# the entire Promise tree to be evaluated.

承诺聚合函数

Promise提供了几个聚合函数,可以更好地控制请求的调度方式。在

fromnotcallbackimportPromise# dependency

Promise.all()只有在所有请求都成功发出时才会实现,并将在其中一个请求被成功发出时拒绝 请求失败。如果所有请求都成功,处理程序将收到一个响应列表:

defparse_pages(responses:Tuple[TextResponse]):forrinresponses:...yield fromPromise.all(*[fetch(url)forurlinurls]).then(parse_pages)

一旦其中一个请求被满足/拒绝,Promise.race()将立即完成。在

defselect_fastest_cdn():yield from(Promise.race(*[fetch(url,method='HEAD')forurlincdn_list]).then(crawl_server))

Promise.all_settled()无论是否完成所有请求,都始终满足 他们是成功的。处理程序将收到一个Promise的列表,其值(响应)可以被访问 使用.get()方法:

defreport(promises:Tuple[Promise]):forpromiseinpromises:result=promise.get()ifisinstance(result,Response):log.info(f'Crawled {result.url}')else:log.warn(f'Encountered error {result}')yield fromPromise.all_settled(*[fetch(u)foruinurls]).then(report)

Promise.any()满足第一个请求,如果没有请求成功,则拒绝:

defdownload(response):...yield from(Promise.any(*[fetch(u)foruinurls]).then(download).catch(lambdaexc:log.warn('No valid URL!')))

有关Promise API的详细信息,请参阅notcallback

另请参见

在回调中安排请求的其他方法:

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
在java代码中实现两个侦听器时发生swing错误   Lambda是否完全取消了Java8中匿名内部类的使用?   swing OpenSuse 12.3+Java双显示   POM中的java错误。xml文件,即使在清理{users}/之后。m2/用于*上次更新文件的存储库   JavaEDT特定的方法和其他东西   java如何使用GridLayout设置组件大小?有更好的办法吗?   java在itext7中生成二维码时,如何调整点的大小?   java如何在多行上显示文本并右对齐?   java在WebSphereCluString环境中分离Log4j日志   JAVA从文件读取,返回BigInteger值   当使用rxjava2进行排列时,使用javamockito。重试()   在java fasterxml中创建Xml   使用64位整数进行模运算的64位整数的java快速乘法,无溢出   java静态变量保留以前发布的值   datastax enterprise SSTable loader流式处理无法提供java。木卫一。IOException:对等方重置连接   java匹配的通配符是严格的,但找不到元素“mvc:annotationdriven”的声明。标准包装。可抛出   java无法在浏览器上下载文件文档?