目录
- 下载中间件(Download MiddleWare)是如何加载的
- Spider MiddleWare是如何加载的
- 配置文件是如何起作用的
- 整体的执行流程是怎样的
- 扩展件是如何工作的
- 数据是怎么处理的
分析
我们之前经常会写yield Request ,yield Item 这种东西,到底yield 是做什么用的?返回的item又是如何处理的,好了我们今天先看数据是数据处理的。
我们正常的思路就是从spider的parse方法来着手,因为我们写的最多的代码就是从这里开始的,这样我们直接从scraper.py来看
1 2 3 4 5 |
def call_spider(self, result, request, spider): result.request = request dfd = defer_result(result) dfd.addCallbacks(request.callback or spider.parse, request.errback) return dfd.addCallback(iterate_spider_output) |
这里我就们就可以看到spider如果指定了callback,那callback对应的方法优先级最高,如果没有callback,那就是默认的spider.parse方法,我们来看看谁在调用这个call_spider方法
到最后一步的时候其实已经跨到engine.py了,我们不是经常写yield Request或者yield item这种方法吗?这yield和return 有什么区别呢,不急,我们先看看是怎么处理我们的输出的,先看如下的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def _process_spidermw_output(self, output, request, response, spider): """Process each Request/Item (given in the output parameter) returned from the given spider """ if isinstance(output, Request): self.crawler.engine.crawl(request=output, spider=spider) elif isinstance(output, (BaseItem, dict)): self.slot.itemproc_size += 1 dfd = self.itemproc.process_item(output, spider) dfd.addBoth(self._itemproc_finished, output, response, spider) return dfd elif output is None: pass else: typename = type(output).__name__ logger.error('Spider must return Request, BaseItem, dict or None, ' 'got %(typename)r in %(request)s', {'request': request, 'typename': typename}, extra={'spider': spider}) |
拿到返回的内容之后,先判断是item 还是request,如果是item ,则调用process_item方法–就是我们在pipeline里面的定义的内容,这里被加载进来之后做数据的方法,如果是request类型呢,就放回到队列之中,然后进一步的处理。
我们小小看一步是如何处理的
看看这个_scrape_next方法
1 2 3 4 |
def _scrape_next(self, spider, slot): while slot.queue: response, request, deferred = slot.next_response_request_deferred() self._scrape(response, request, spider).chainDeferred(deferred) |
信号槽中一直存在队列的时候,那就一直处理直到结束,一直调用_scrape方法。这样整个的流程和逻辑就清晰了.
大鱼,期待你做一个结合splash中(mouse_click)处理下一页点击事件的的完整教程,好像现在网上还没有人做过。
如果需要的人多了,我会考虑写的。一般情况下看文档和自己总结就可以了
1.process multiple webpages in parallel(这应该是splash最优秀的point),但是初学者没有办法深刻的比较selenium这种(似乎没法实现并行)。2.splash处理点击下一页事件的整个流程应该和传统获取a标签href里面的地址在抓取下一页内容完全不同。以上是我这个月一直都研究的(想做一个通用的处理点击一页的代码),可是发现真的有点难,目前网上是有很多处理下一页的方法,但是使用splash处理太少了,好吧,基本没有(selenium来处理的话好像没法并行),希望鱼神能否指点。(诚心脸,真的是没有办法了!)
有时间我系统的分析一下,大家互相学习一下
鱼神,考虑过没啊。
好文。666。
感谢支持~
666,希望出个对接kafka的分享
https://github.com/istresearch/scrapy-cluster 参考
treat = require("treat") function main(splash) splash.response_body_enabled = true assert(splash:go('http://www.mps.gov.cn/n2254314/n2254457/n2254466/index.html')) local get_dimensions = splash:jsfunc([[ function(){ var arr=document.getElementsByTagName('a');
var rect = tmp.getClientRects()[0]; return {"x": rect.left, "y": rect.top}} ]]) splash:set_viewport_full() splash:wait(0.1) local dimensions = get_dimensions() local result = treat.as_array({}) for i=1,2 do result
= splash:html() splash:mouse_click(dimensions.x,dimensions.y) splash:wait(2) end return result end
上面是自己写的Lua脚本,思路主要实现通过找到下一页按钮,调用mouse_click函数循环点击下一页,并获取网页源代码存放在result数组中,通过返回result到指定的回调函数,再在回调函数中提取网页中的数据。可是mouse_click是个异步加载的函数,每次要人为设置等待的时间,否则网速过慢会重复的存放之前的网页内容,看了很久的文档也不知道如何通过程序自动判断网页是否加载完成。同时自己也不知道如何判断网页是否是最后一页,有些网页最后一页还是个a标签(无奈。。)学生狗卡在这里一个月了(恐慌中。。。)网上没有找到一个完整的案例。希望鱼神能给我科普下,如何通过splash完美的实现这个功能。(跪谢了。。)