GVKun编程网logo

Scrapy:如何手动从spider_idle事件回调插入请求?(scrapy schedule)

27

对于想了解Scrapy:如何手动从spider_idle事件回调插入请求?的读者,本文将是一篇不可错过的文章,我们将详细介绍scrapyschedule,并且为您提供关于2.Spider_scrapy

对于想了解Scrapy:如何手动从spider_idle事件回调插入请求?的读者,本文将是一篇不可错过的文章,我们将详细介绍scrapy schedule,并且为您提供关于2.Spider_scrapy_in_practise、JavaScript如何手动触发onchange事件?、python – Scrapy:如何调试scrapy丢失的请求、python 爬虫之 Scrapy 框架 (CrawlSpider)的有价值信息。

本文目录一览:

Scrapy:如何手动从spider_idle事件回调插入请求?(scrapy schedule)

Scrapy:如何手动从spider_idle事件回调插入请求?(scrapy schedule)

我创建了一个Spider,并将一个方法链接到spider_idle事件。

如何手动添加请求?我不能仅仅从解析返回项-
在这种情况下,解析不会运行,因为所有已知的URL都已解析。我有一个生成新请求的方法,我想从spider_idle回调中运行它来添加创建的请求。

class FooSpider(BaseSpider):    name = ''foo''    def __init__(self):        dispatcher.connect(self.dont_close_me, signals.spider_idle)    def dont_close_me(self, spider):        if spider != self:            return        # The engine instance will allow me to schedule requests, but        # how do I get the engine object?        engine = unknown_get_engine()        engine.schedule(self.create_request())        # afterward, ensure we stay alive by raising DontCloseSpider        raise DontCloseSpider("..I prefer live spiders.")

更新:
我已经确定我可能需要该ExecutionEngine对象,但是尽管它可以从Crawler实例中获得,但我不完全知道如何从蜘蛛中获取该对象。

更新2: ..谢谢。..crawler被附加为超类的属性,因此我可以轻松使用self.crawler。>。>

答案1

小编典典
class FooSpider(BaseSpider):    def __init__(self, *args, **kwargs):        super(FooSpider, self).__init__(*args, **kwargs)        dispatcher.connect(self.dont_close_me, signals.spider_idle)    def dont_close_me(self, spider):        if spider != self:            return        self.crawler.engine.crawl(self.create_request(), spider)        raise DontCloseSpider("..I prefer live spiders.")

2016年更新:

class FooSpider(BaseSpider):    yet = False    @classmethod    def from_crawler(cls, crawler, *args, **kwargs):        from_crawler = super(FooSpider, cls).from_crawler        spider = from_crawler(crawler, *args, **kwargs)        crawler.signals.connect(spider.idle, signal=scrapy.signals.spider_idle)        return spider    def idle(self):        if not self.yet:            self.crawler.engine.crawl(self.create_request(), self)            self.yet = True

2.Spider_scrapy_in_practise

2.Spider_scrapy_in_practise

see http://scrapy.readthedocs.io/en/latest/topics/spiders.html

2.功能:

Spider 为整个爬取过程的业务核心。通过这个类的继承与实现既定的方法,scrapy会获取要爬取的URL,处理已经爬取内容的处理方式即结果。

1) 调用spider 的start_requests方法 获取 相应需要爬去的的url,且定义回调函数来指定处理逻辑的地方

2) 通过回调函数 来处理 被scrapy成功爬取后且封装成Response的内容。这个回调函数调用的时机是在当前的URL已经被成功爬 取后且返回了engine.(这个回调函数默认的命名为parse)

3) 通过parse不同的返回参数来确定不同的业务处理

 

3.主要属性和方法

  • name

    定义spider名字的字符串。

    例如,如果spider爬取 mywebsite.com ,该spider通常会被命名为 mywebsite

  • allowed_domains

    包含了spider允许爬取的域名(domain)的列表,可选。

  • start_urls

    初始URL元祖/列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。

  • start_requests(self)

    该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取(默认实现是使用 start_urls 的url)的第一个Request。

    当spider启动爬取并且未指定start_urls时,该方法被调用。

  • parse(self, response)

    当请求url返回网页没有指定回调函数时,默认的Request对象回调函数。用来处理网页返回的response,以及生成Item或者Request对象。

  • log(self, message[, level, component])

    使用 scrapy.log.msg() 方法记录(log)message。 更多数据请参见 logging

 

4.parse函数

## 返回list ## 返回生成器## 返回字典## scrapy.Request

a)如果返回的是Item 或者 dict 就表示这个request已经处理完了,下一步就去去itempipeline处理

b)如果继续返回Request说明让scrapy继续爬取对应的url,这样就能实现迭代爬取的功能。

5.例子

# -*- coding:UTF-8 -*-
# coding:utf-8
import scrapy
from scrapy_in_practise.items import ScrapyCSDNItem
import sys
reload(sys)
sys.setdefaultencoding(''utf-8'')
​
​
​
class Douban_book_spider(scrapy.Spider):
   header = {
      ''Host'': ''blog.csdn.net'',
      ''Connection'': ''keep-alive'',
      ''Cache-Control'': ''max-age=0'',
      ''Accept'': ''text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'',
      ''accept-language'': ''zh-CN,zh;q=0.8'',
      ''referer'': ''https://blog.csdn.net/'',
      ''user-agent'': "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52"
   }
​
   name = "douban_book"
   # 减慢爬取速度 为1s
   download_delay = 3
   allowed_domains = ["blog.csdn.net"]
   start_urls = [''http://blog.csdn.net/column/details/16138.html'']
​
   #scrapy 在爬去启动的时候首选会调用spider 的start_requests方法 获取 相应需要爬去的的url, 且这个URL会以Request类的形式进行封装
   #通过yield生成器逐个返回Request
   #通过回调函数 来处理 被scrapy成功爬取后且封装成Response的内容。这个回调函数调用的时机是在当前的URL已经被成功爬取后且返回了engine.
   #这个过程中,会经过--->下载中间件--->下载器--->下载中间件--->Engine--->spider 中间件--->spider
   def start_requests(self):
      for url in self.start_urls:
         yield scrapy.Request(url=url,headers=self.header, callback=self.parse)
​
​
   #通过scrapy的 css selector 或 xpath selector获取需要的页面内容。
   def parse(self, response):
      ##item=ScrapyTestItem()  $(''.hot_blog li a'')[1].text
      ## 返回list
      ## 返回生成器
      ## 返回字典
      ## scrapy.Request
      item=ScrapyCSDNItem()
      for i in response.css(''.detail_list a::text'').extract():
         item[''title''] = i
         yield item
#     print response.status_code

 

class ScrapyInPractisePipeline(object):
    def process_item(self, item, spider):
        print ''>>>>>>''+item[''title'']
      
class ScrapyCSDNItem(scrapy.Item):
    title = scrapy.Field()
    #image_urls = scrapy.Field()

6.parse()方法的工作机制:

1. 因为使用的yield,而不是return。parse函数将会被当做一个生成器使用。scrapy会逐一获取parse方法中生成的结果,并判断该结果是一个什么样的类型;
2. 如果是request则加入爬取队列,如果是item类型则使用pipeline处理,其他类型则返回错误信息。
3. scrapy取到第一部分的request不会立马就去发送这个request,只是把这个request放到队列里,然后接着从生成器里获取;
4. 取尽第一部分的request,然后再获取第二部分的item,取到item了,就会放到对应的pipeline里处理;
5. parse()方法作为回调函数(callback)赋值给了Request,指定parse()方法来处理这些请求 scrapy.Request(url, callback=self.parse)
6. Request对象经过调度,执行生成 scrapy.http.response()的响应对象,并送回给parse()方法,直到调度器中没有Request(递归的思路)
7. 取尽之后,parse()工作结束,引擎再根据队列和pipelines中的内容去执行相应的操作;
8. 程序在取得各个页面的items前,会先处理完之前所有的request队列里的请求,然后再提取items。
7. 这一切的一切,Scrapy引擎和调度器将负责到底。

7.延伸阅读

CrawlSpider

XMLFeedSpider

CSVFeedSpider

SitemapSpider

@see https://doc.scrapy.org/en/latest/topics/spiders.html

8.样子代码

git: https://git.oschina.net/kra

JavaScript如何手动触发onchange事件?

JavaScript如何手动触发onchange事件?

如何解决JavaScript如何手动触发onchange事件??

有两种方法可以做到这一点。如果onchange侦听器是通过该element.onchange属性设置的函数,并且您对事件对象或冒泡/传播不感到烦恼,则最简单的方法是仅调用该函数:

element.onchange();

如果需要它来完全模拟真实事件,或者通过html属性或addEventListener/设置事件attachEvent,则需要进行一些功能检测以正确触发事件:

if ("createEvent" in document) {
    var evt = document.createEvent("HTMLEvents");
    evt.initEvent("change", false, true);
    element.dispatchEvent(evt);
}
else
    element.fireEvent("onchange");

解决方法

我正在通过日历窗口小部件设置日期时间文本字段值。显然,日历小部件会执行以下操作:

document.getElementById(''datetimetext'').value = date_value;

我想要的是:在更改日期时间文本字段中的值时,我需要重置页面中的其他一些字段。我已经将一个onchange事件侦听器添加到了不会被触发的datetimetext字段中,因为我猜onchange只有在元素获得焦点并且其值更改为失去焦点时才会被触发。

因此,我正在寻找一种手动触发此onchange事件的方法(我认为应该注意检查文本字段中的值差异)。

有任何想法吗 ?

python – Scrapy:如何调试scrapy丢失的请求

python – Scrapy:如何调试scrapy丢失的请求

我有一个scrapy蜘蛛,但它有时不会返回请求.

我发现通过在产生请求之前和获得响应之后添加日志消息.

Spider遍历页面并解析每个页面上的项目报废链接.

这是代码的一部分

SampleSpider(BaseSpider):
    ....
    def parse_page(self,response):
        ...
        request = Request(target_link,callback=self.parse_item_general)
        request.Meta[''date_updated''] = date_updated
        self.log(''parse_item_general_send {url}''.format(url=request.url),level=log.INFO)
        yield request

    def parse_item_general(self,response):
        self.log(''parse_item_general_recv {url}''.format(url=response.url),level=log.INFO)
        sel = Selector(response)
        ...

我已经比较了每条日志消息的数量,“parse_item_general_send”大于“parse_item_general_recv”

最终统计数据中没有400或500个错误,所有响应状态代码仅为200.看起来请求只是消失了.

我还添加了这些参数以最大限度地减少可能的错误:

CONCURRENT_REQUESTS_PER_DOMAIN = 1
DOWNLOAD_DELAY = 0.8

由于扭曲的异步性质,我不知道如何调试这个bug.
我发现了一个类似的问题:Python Scrapy not always downloading data from website,但它没有任何回应

解决方法

在和Rho相同的音符上,您可以添加设置

DUPEFILTER_scrapy.dupefilter.BaseDupeFilter''

到你的“settings.py”将删除网址缓存.这是一个棘手的问题,因为scrapy日志中没有调试字符串告诉您何时使用缓存结果.

python 爬虫之 Scrapy 框架 (CrawlSpider)

python 爬虫之 Scrapy 框架 (CrawlSpider)

提问:如果想要通过爬虫程序去爬取” 糗百 “全站数据新闻数据的话,有几种实现方法?

方法一:基于 Scrapy 框架中的 Spider 的递归爬去进行实现的 (Request 模块回调)

方法二:基于 CrawlSpider 的自动爬去进行实现 (更加简洁和高效)

一、简单介绍 CrawlSpider

  CrawlSpider 其实是 Spider 的一个子类,除了继承到 Spider 的特性和功能外,还派生除了其自己独有的更加强大的特性和功能。其中最显著的功能就是”LinkExtractors 链接提取器 “。Spider 是所有爬虫的基类,其设计原则只是为了爬取 start_url 列表中网页,而从爬取到的网页中提取出的 url 进行继续的爬取工作使用 CrawlSpider 更合适。

二、使用

  1. 创建 scrapy 工程 (cmd 切换到要创建项目的文件夹下执行):scrapy startproject projectName       (如:scrapy startproject  crawlPro)

  2. 创建爬虫文件 (cmd 切换到创建的项目下执行):scrapy genspider -t crawl spiderName www.xxx.com     (如:scrapy genspider -t crawl crawlDemo www.qiushibaike.com)

    -- 此指令对比以前的指令多了 "-t crawl",表示创建的爬虫文件是基于 CrawlSpider 这个类的,而不再是 Spider 这个基类。

  3. 启动爬虫文件 (cmd 基于步骤二的路径执行):scrapy crawl crawlDemo     (启动的一定是 name 对应的值,如果爬虫文件与 name 的值不一致,任然以 name 的值进行启动)

观察生成的爬虫文件

crawlDemo.py

# -*- coding: utf-8 -*-
import scrapy
# 导入CrawlSpider相关模块
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule

# 表示该爬虫程序是基于CrawlSpider类的
class CrawldemoSpider(CrawlSpider):
    name = ''crawlDemo''    #爬虫文件名称
    #allowed_domains = [''www.qiushibaike.com'']
    start_urls = [''http://www.qiushibaike.com/'']
    
    #连接提取器:会去起始url响应回来的页面中提取指定的url
    link = LinkExtractor(allow=r''/8hr/page/\d+'')
    #rules元组中存放的是不同的规则解析器(封装好了某种解析规则)
    rules = (
        #规则解析器:可以将连接提取器提取到的所有连接表示的页面进行指定规则(回调函数)的解析
        Rule(link, callback=''parse_item'', follow=True),
    )
    # 解析方法
    def parse_item(self, response):
        #print(response.url)
        divs = response.xpath(''//div[@id="content-left"]/div'')
        for div in divs:
            author = div.xpath(''./div[@]/a[2]/h2/text()'').extract_first()
            print(author)

  CrawlSpider 类和 Spider 类的最大不同是 CrawlSpider 多了一个 rules 属性,其作用是定义” 提取动作 “。在 rules 中可以包含一个或多个 Rule 对象,在 Rule 对象中包含了 LinkExtractor 对象。 

三、生成的爬虫文件参数介绍

3.1 LinkExtractor:顾名思义,链接提取器。

    LinkExtractor(

         allow=r''Items/'',# 满足括号中 “正则表达式” 的值会被提取,如果为空,则全部匹配。

         deny=xxx,  # 满足正则表达式的则不会被提取

 

         restrict_xpaths=xxx, # 满足 xpath 表达式的值会被提取

         restrict_css=xxx, # 满足 css 表达式的值会被提取

         deny_domains=xxx, # 不会被提取的链接的 domains。 

    )

    - 作用:提取 response 中符合规则的链接。 

3.2 Rule : 规则解析器。根据链接提取器中提取到的链接,根据指定规则提取解析器链接网页中的内容。

     Rule(LinkExtractor(allow=r''Items/''), callback=''parse_item'', follow=True)

    - 参数介绍:

      参数 1:指定链接提取器

      参数 2:指定规则解析器解析数据的规则(回调函数)

      参数 3:是否将链接提取器继续作用到链接提取器提取出的链接网页中。 callback None, 参数 3 的默认值为 true

3.3 rules=( ): 指定不同规则解析器。一个 Rule 对象表示一种提取规则。

3.4 CrawlSpider 整体爬取流程:

    a) 爬虫文件首先根据起始 url,获取该 url 的网页内容

    b) 链接提取器会根据指定提取规则将步骤 a 中网页内容中的链接进行提取

    c) 规则解析器会根据指定解析规则将链接提取器中提取到的链接中的网页内容根据指定的规则进行解析

    d) 将解析数据封装到 item 中,然后提交给管道进行持久化存储

四、基于 CrawlSpider 示例

创建爬虫项目和启动爬虫项目以及 settings 中配置自行完成,在这里不在追赘述

4.1 爬虫文件

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from qiubaiBycrawl.items import QiubaibycrawlItem
import re
class QiubaitestSpider(CrawlSpider):
    name = ''qiubaiTest''
    #起始url
    start_urls = [''http://www.qiushibaike.com/'']

    #定义链接提取器,且指定其提取规则
    page_link = LinkExtractor(allow=r''/8hr/page/\d+/'')
    
    rules = (
        #定义规则解析器,且指定解析规则通过callback回调函数
        Rule(page_link, callback=''parse_item'', follow=True),
    )

    #自定义规则解析器的解析规则函数
    def parse_item(self, response):
        div_list = response.xpath(''//div[@id="content-left"]/div'')
        
        for div in div_list:
            #定义item
            item = QiubaibycrawlItem()
            #根据xpath表达式提取糗百中段子的作者
            item[''author''] = div.xpath(''./div/a[2]/h2/text()'').extract_first().strip(''\n'')
            #根据xpath表达式提取糗百中段子的内容
            item[''content''] = div.xpath(''.//div[@]/span/text()'').extract_first().strip(''\n'')

            yield item #将item提交至管道

4.2items 文件

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

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy


class QiubaibycrawlItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    author = scrapy.Field() #作者
    content = scrapy.Field() #内容

4.3 管道文件

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

# Define your item pipelines here
#
# Don''t forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

class QiubaibycrawlPipeline(object):
    
    def __init__(self):
        self.fp = None
        
    def open_spider(self,spider):
        print(''开始爬虫'')
        self.fp = open(''./data.txt'',''w'')
        
    def process_item(self, item, spider):
        #将爬虫文件提交的item写入文件进行持久化存储
        self.fp.write(item[''author'']+'':''+item[''content'']+''\n'')
        return item
    
    def close_spider(self,spider):
        print(''结束爬虫'')
        self.fp.close()

 

关于Scrapy:如何手动从spider_idle事件回调插入请求?scrapy schedule的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于2.Spider_scrapy_in_practise、JavaScript如何手动触发onchange事件?、python – Scrapy:如何调试scrapy丢失的请求、python 爬虫之 Scrapy 框架 (CrawlSpider)的相关知识,请在本站寻找。

本文标签: