1. Scrapy通用爬虫

通过Scrapy,我们可以轻松地完成一个站点爬虫的编写。但如果抓取的站点量非常大,比如爬取各大媒体的新闻信息,多个Spider则可能包含很多重复代码。

如果我们将各个站点的Spider的公共部分保留下来,不同的部分提取出来作为单独的配置,如爬取规则、页面解析方式等抽离出来做成一个配置文件,那么我们在新增一个爬虫的时候,只需要实现这些网站的爬取规则和提取规则即可。

这一章我们就来了解下Scrapy通用爬虫的实现方法。

1.1 CrawlSpider

在实现通用爬虫之前,我们需要先了解一下CrawlSpider,官方文档:https://scrapy.readthedocs.io/en/latest/topics/spiders.html#crawlspider

CrawlSpider是Scrapy提供的一个通用Spider。在Spider里,我们可以指定一些爬取规则来实现页面的提取,这些爬取规则由一个专门的数据结构Rule表示。Rule里包含提取和跟进页面的配置,Spider会根据Rule来确定当前页面中的哪些链接需要继续爬取、哪些页面的爬取结果需要用哪个方法解析等。

CrawlSpider继承自Spider类。除了Spider类的所有方法和属性,它还提供了一个非常重要的属性和方法。

rules,它是爬取规则属性,是包含一个或多个Rule对象的列表。每个Rule对爬取网站的动作都做了定义,CrawlSpider会读取rules的每一个Rule并进行解析。

parse_start_url(),它是一个可重写的方法。当start_urls里对应的Request得到Response时,该方法被调用,它会分析Response并必须返回Item对象或者Request对象。

这里最重要的内容莫过于Rule的定义了:

Rule参数:

  • link_extractor:是Link Extractor对象。通过它,Spider可以知道从爬取的页面中提取哪些链接。提取出的链接会自动生成Request。它又是一个数据结构,一般常用LxmlLinkExtractor对象作为参数。

allow是一个正则表达式或正则表达式列表,它定义了从当前页面提取出的链接哪些是符合要求的,只有符合要求的链接才会被跟进。deny则相反。allow_domains定义了符合要求的域名,只有此域名的链接才会被跟进生成新的Request,它相当于域名向名单。deny_domains则相反,相当于域名黑名单。restrict_xpaths定义了从当前页面中XPath匹配的区域提取链接,其值是XPath表达式或XPath表达式列表。restrict_css定义了从当前页面中css选择器匹配的区域提取链接,其值是css选择器或css选择器列表还有一些其他参数代表了提取链接的标签、是否去重、链接的处理等内容,使用的频率不高。

参考文档:https://scrapy.readthedocs.io/en/latest/topics/link-extractors.html#module-scrapy.linkextractors.lxmlhtml

  • callback:即回调函数,和之前定义Request的callback有相同的意义。每次从link_extractor中获取到链接时,该函数将会调用。该回调函数接收一个response作为其第一个参数,并返回一个包含Item或Request对象的列表。注意,避免使用pars()作为回调函数。由于CrawlSpider使用parse()方法来实现其逻辑,如果parse()方法覆盖了,CrawlSpider将会运行失败。
  • cb_kwargs:字典,它包含传递给回调函数的参数。
  • follow:布尔值,即True或False,它指定根据该规则从response提取的链接是否需要跟进。如果 callback参数为None,follow默认设置为True,否则默认为False。
  • process_links:指定处理函数,从link_extractor中获取到链接列表时,该函数将会调用, 它主要用于过滤。
  • process_request:同样是指定处理函数,根据该Rule提取到每个Request时,该函数部会调用,对Request进行处理。该函数必须返回Request或者None。

以上内容便是CraefISpider中的核心Rule的基本用法。但这些内容可能还不足以完成一个CrawlSpider爬虫。下面我们利用CrawlSpider实现新闻网站的爬取实例,来更好地理解Rule的用法。

1.2 Item Loader

我们了解了利用CrawlSpider的Rule来定义页面的爬取逻辑,这是可配置化的一部分内容。但是,Rule并没有对Item的提取方式做规则定义。对于Item的提取,我们需要借助另一个模块Item Loader来实现。

Item Loader提供一种便捷的机制来帮助我们方便地提取Item。它提供的一系列API可以分析原始数据对Item进行赋值。Item提供的是保存抓取数据的容器,而Item Loader提供的是填充容器的机制。有了它,数据的提取会变得更加规则化。

Item LoaderAPI参数:

item:它是Item对象,可以调用add_xpath()、add_css()或add_value()等方法来填充Item对象。

selector:它是Selector对象,用来提取填充数据的选择器。

response:它是Response对象,用于使用构造选择器的Response。

实例:

  1. from scrapy.loader import ItemLoader
  2. from scrapyDemo.items import Product
  1. def parse(self, response):
    loader = ItemLoader(item=Product(),response=response)
    loader.add_xpath('name','//div[@class="product_name"]')
    loader.add_xpath('name','//div[@class="product_title"]')
    loader.add_xpath('price','//p[@id="price"]')
    loader.add_css('stock','p#stock]')
    loader.add_value('last_updated','today')
    return loader.load_item()

这里首先声明一个Product Item,用该Item和Response对象实例化Item Loader,调用add_xpath()方法把来向两个不同位置的数据提取出来,分配给name属性,再用add_xpath()、add_css()、add_value()等方法对不同属性依次赋值,最后调用load_item()方法实现Item的解析。这种方式比较规则化,我们可以把一些参数和规则单独提取出来做成配置文件或存到数据库,即可实现可配置化。

另外,Item Loader每个字段中都包含了一个Input Processor(输入处理器)和一个Output Processor(输出处理器)。Input Processor收到数据时立刻提取数据,Input Processor的结果被收集起来并且保存在ltemLoader内,但是不分配给Item。收集到所有的数据后,load_item()方法被调用来填充再生成Item对象 。在调用时会先调用Output Processor来处理之前收集到的数据,然后再存入Item中,这样就生成了Item。

内置的Processor:

(1) Identity

Identity是最简单的Processor,不进行任何处理,直接返回原来的数据。

(2) TakeFirst

TakeFirst返回列表的第一个非空值,类似extract_first()的功能,常用作Output Processor。

  1. from scrapy.loader.processors import TakeFirst
  2. processor = TakeFirst()
  3. print(processor(['',1,2,3]))

运行结果为1。

(3) Join

Join方法相当于字符串的join()方法,可以把列表并结成字符串,字符串默认使用空格分隔。

  1. from scrapy.loader.processors import Join
  2. processor = Join()
  3. print(processor(['one','two','three']))

运行结果为one two three。

它也可以通过参数更改默认的分隔符,例如改成逗号:

  1. from scrapy.loader.processors import Join
  2. processor = Join(',')
  3. print(processor(['one','two','three']))

运行结果为one,two,three。

(4) Compose

Compose是用给定的多个函数的组合而构造的Processor,每个输入值被传递到第一个函数,其输出再传递到第二个函数,依次类推,直到最后一个函数返回整个处理器的输出。

  1. from scrapy.loader.processors import Compose
  2. processor = Compose(str.upper,lambda s:s.strip())
  3. print(processor('hello world'))

运行结果为HELLO WORLD。

在这里我们构造了一个Compose Processor,传入一个开头带有空格的字符串。Compose Processor的参数有两个:第一个是str.upper,它可以将字母全部转为大写;第二个是一个匿名函数,它调用strip()方法去除头尾空白字符。Compose会顺次调用两个参数,最后返回结果的字符串全部转化为大写并且去除了开头的空格。

(5) MapCompose

与Compose类似,MapCompose可以迭代处理一个列表输入值。

  1. from scrapy.loader.processors import MapCompose
  2. processor = MapCompose(str.upper,lambda s:s.strip())
  3. print(processor(['Hello','World','Python']))

运行结果为['HELLO','WORLD','PYTHON']。

被处理的内容是一个可迭代对象,MapCompose会将该对象遍历然后依次处理。

(6) SelectJmes

SelectJmes可以查询JSON,传入Key,返回查询所得的Value。不过需要先安装jmespath库才可以使用它。

pip install jmespath

安装好jmespath之后,便可以使用这个Processor了。

  1. from scrapy.loader.processors import SelectJmes
  2. processor = SelectJmes('foo')
  3. print(processor({'foo':'bar'}))

运行结果为:bar。

以上内容便是一些常用的Processor,在本节的实例中我们会使用Processor来进行数据的处理。接下来,我们用一个实例来了解Item Loader的用法。

1.3 通用爬虫案例

起点作为主流的小说网站,在防止数据采集反面还是做了准备的,其对主要的数字采用了自定义的编码映射取值,想直接通过页面来实现数据的获取,是无法实现的。

单独获取数字还是可以实现的,通过requests发送请求,用正则去匹配字符元素,并再次匹配其映射关系的url,获取到的数据通过font包工具解析成字典格式,再做编码匹配,起点返回的编码匹配英文数字,英文数字匹配阿拉伯数字,最后拼接,得到实际的数字字符串,但这样多次发送请求,爬取效率会大大降低。本次集中爬取舍弃了爬取数字,选择了较容易获取的评分数字。评分值默认为0 ,是从后台推送的js数据里取值更新的。

但是这太复杂了,我没空搞,现在写博客都是挤出时间来写。

1.3.1 新建项目

先新建Scrapy项目,名为qd。

scrapy startproject qd

创建一个CrawlSpider,需要先制定一个模板。我们可以先看看有哪些可用模版。

scrapy genspider -l

运行结果:

之前创建Spider的时候,我们默认使用了第一个模板basic。这次要创建CrawlSpider,就需要使用第二个模板crawl。

scrapy genspider -t crawl read qidian.com

运行之后便会生成一个CrawlSpider。

这次生成的Spider内容多了一个rules属性的定义。Rule第一个参数是LinkExtractor,就是上文所说的LxmllinkExtractor,只是名称不同。同时,默认的回调函数也不再是parse,而是parse_item。

1.3.2 定义Rule

要实现小说信息的爬取,我们需要做的就是定义好Rule,然后实现解析函数。下面我们就来一步步实现这个过程。

首先将start_urls修改为起始链接。

  1. start_urls = ['https://www.qidian.com/all?orderId=&style=1&pageSize=20&siteid=1&pubflag=0&hiddenField=0&page=1']

之后,Spider爬取start_urls里面的每一个链接。所以这里第一个爬取的页面就是我们刚才所定义的链接。得到Response之后,Spider就会根据每一个Rule来提取这个页面内的超链接,去生成进一步的Request。接下来,我们就需要定义Rule来指定提取哪些链接。

这是起点小说网的列表页,下一步自然就是将列表中的每一条小说详情的链接提取出来。这里直接指定这些链接所在区域即可。

rules:

  1. rules = (
  2. #匹配全部主页面的url规则 深度爬取子页面
  3. Rule(LinkExtractor(allow=(r'https://www.qidian.com/all\?orderId=\&style=1\&pageSize=20\&siteid=1\&pubflag=0\&hiddenField=0\&page=(\d+)')),follow=True),
  4. #匹配详情页面 不作深度爬取
  5. Rule(LinkExtractor(allow=r'https://book.qidian.com/info/(\d+)'), callback='parse_item', follow=False),
  6. )

1.3.3 解析页面

接下来我们需要做的就是解析页面内容了,将书名、作者、状态、类型、简介、评分、故事、最新章节提取出来即可。首先定义一个Item。

  1. # -*- coding: utf-8 -*-
  2.  
  3. # Define here the models for your scraped items
  4. #
  5. # See documentation in:
  6. # https://doc.scrapy.org/en/latest/topics/items.html
  7.  
  8. from scrapy import Field,Item
  9.  
  10. class QdItem(Item):
  11. # define the fields for your item here like:
  12.  
  13. book_name = Field() #书名
  14. author=Field() #作者
  15. state=Field() #状态
  16. type=Field() #类型
  17. about=Field() #简介
  18. score=Field() #评分
  19. story=Field() #故事
  20. news=Field() #最新章节

然后我创建了很多方法,在分别获取这些信息。

  1. def get_book_name(self,response):
  2.  
  3. book_name=response.xpath('//h1/em/text()').extract()[0]
  4. if len(book_name)>0:
  5. book_name=book_name.strip()
  6. else:
  7. book_name='NULL'
  8. return book_name
  9.  
  10. def get_author(self,response):
  11. author=response.xpath('//h1/span/a/text()').extract()[0]
  12. if len(author)>0:
  13. author=author.strip()
  14. else:
  15. author='NULL'
  16. return author
  17.  
  18. def get_state(self,response):
  19. state=response.xpath('//p[@class="tag"]/span/text()').extract()[0]
  20. if len(state)>0:
  21. state=state.strip()
  22. else:
  23. st='NULL'
  24. return state
  25.  
  26. def get_type(self,response):
  27. type=response.xpath('//p[@class="tag"]/a/text()').extract()
  28. if len(type)>0:
  29. t=""
  30. for i in type:
  31. t+=' '+i
  32. type=t
  33. else:
  34. type='NULL'
  35. return type
  36.  
  37. def get_about(self,response):
  38. about=response.xpath('//p[@class="intro"]/text()').extract()[0]
  39. if len(about)>0:
  40. about=about.strip()
  41. else:
  42. about='NULL'
  43. return about
  44.  
  45. def get_score(self,response):
  46.  
  47. def get_sc(id):
  48. urll = 'https://book.qidian.com/ajax/comment/index?_csrfToken=ziKrBzt4NggZbkfyUMDwZvGH0X0wtrO5RdEGbI9w&bookId=' + id + '&pageSize=15'
  49. rr = requests.get(urll)
  50. # print(rr)
  51. score = rr.text[16:19]
  52. return score
  53.  
  54. bid=response.xpath('//a[@id="bookImg"]/@data-bid').extract()[0] #获取书的id
  55. if len(bid)>0:
  56. score=get_sc(bid) #调用方法获取评分 若是整数 可能返回 9,"
  57. if score[1]==',':
  58. score=score.replace(',"',".0")
  59. else:
  60. score=score
  61.  
  62. else:
  63. score='NULL'
  64. return score
  65.  
  66. def get_story(self,response):
  67. story=response.xpath('//div[@class="book-intro"]/p/text()').extract()[0]
  68. if len(story)>0:
  69. story=story.strip()
  70. else:
  71. story='NULL'
  72. return story
  73.  
  74. def get_news(self,response):
  75. news=response.xpath('//div[@class="detail"]/p[@class="cf"]/a/text()').extract()[0]
  76. if len(news)>0:
  77. news=news.strip()
  78. else:
  79. news='NULL'
  80. return news

其他部分就没什么变化了,就settings加入了请求头:

  1. DEFAULT_REQUEST_HEADERS = {
  2. 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  3. 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv 11.0) like Gecko',
  4. }

1.3.4 运行程序

scrapy crawl read

运行结果:

1.3.5 完整代码

read.py:

  1. # -*- coding: utf-8 -*-
  2.  
  3. from scrapy.linkextractors import LinkExtractor
  4. from scrapy.spiders import CrawlSpider, Rule
  5. from qd.items import QdItem
  6. import requests
  7.  
  8. class ReadSpider(CrawlSpider):
  9. name = 'read'
  10. # allowed_domains = ['qidian.com']
  11. start_urls = ['https://www.qidian.com/all?orderId=&style=1&pageSize=20&siteid=1&pubflag=0&hiddenField=0&page=1']
  12.  
  13. rules = (
  14. #匹配全部主页面的url规则 深度爬取子页面
  15. Rule(LinkExtractor(allow=(r'https://www.qidian.com/all\?orderId=\&style=1\&pageSize=20\&siteid=1\&pubflag=0\&hiddenField=0\&page=(\d+)')),follow=True),
  16. #匹配详情页面 不作深度爬取
  17. Rule(LinkExtractor(allow=r'https://book.qidian.com/info/(\d+)'), callback='parse_item', follow=False),
  18. )
  19.  
  20. def parse_item(self, response):
  21. item=QdItem()
  22. item['book_name']=self.get_book_name(response)
  23. item['author']=self.get_author(response)
  24. item['state']=self.get_state(response)
  25. item['type']=self.get_type(response)
  26. item['about']=self.get_about(response)
  27. item['score']=self.get_score(response)
  28. item['story']=self.get_story(response)
  29. item['news']=self.get_news(response)
  30. yield item
  31.  
  32. def get_book_name(self,response):
  33.  
  34. book_name=response.xpath('//h1/em/text()').extract()[0]
  35. if len(book_name)>0:
  36. book_name=book_name.strip()
  37. else:
  38. book_name='NULL'
  39. return book_name
  40.  
  41. def get_author(self,response):
  42. author=response.xpath('//h1/span/a/text()').extract()[0]
  43. if len(author)>0:
  44. author=author.strip()
  45. else:
  46. author='NULL'
  47. return author
  48.  
  49. def get_state(self,response):
  50. state=response.xpath('//p[@class="tag"]/span/text()').extract()[0]
  51. if len(state)>0:
  52. state=state.strip()
  53. else:
  54. st='NULL'
  55. return state
  56.  
  57. def get_type(self,response):
  58. type=response.xpath('//p[@class="tag"]/a/text()').extract()
  59. if len(type)>0:
  60. t=""
  61. for i in type:
  62. t+=' '+i
  63. type=t
  64. else:
  65. type='NULL'
  66. return type
  67.  
  68. def get_about(self,response):
  69. about=response.xpath('//p[@class="intro"]/text()').extract()[0]
  70. if len(about)>0:
  71. about=about.strip()
  72. else:
  73. about='NULL'
  74. return about
  75.  
  76. def get_score(self,response):
  77.  
  78. def get_sc(id):
  79. urll = 'https://book.qidian.com/ajax/comment/index?_csrfToken=ziKrBzt4NggZbkfyUMDwZvGH0X0wtrO5RdEGbI9w&bookId=' + id + '&pageSize=15'
  80. rr = requests.get(urll)
  81. # print(rr)
  82. score = rr.text[16:19]
  83. return score
  84.  
  85. bid=response.xpath('//a[@id="bookImg"]/@data-bid').extract()[0] #获取书的id
  86. if len(bid)>0:
  87. score=get_sc(bid) #调用方法获取评分 若是整数 可能返回 9,"
  88. if score[1]==',':
  89. score=score.replace(',"',".0")
  90. else:
  91. score=score
  92.  
  93. else:
  94. score='NULL'
  95. return score
  96.  
  97. def get_story(self,response):
  98. story=response.xpath('//div[@class="book-intro"]/p/text()').extract()[0]
  99. if len(story)>0:
  100. story=story.strip()
  101. else:
  102. story='NULL'
  103. return story
  104.  
  105. def get_news(self,response):
  106. news=response.xpath('//div[@class="detail"]/p[@class="cf"]/a/text()').extract()[0]
  107. if len(news)>0:
  108. news=news.strip()
  109. else:
  110. news='NULL'
  111. return news

items.py:

  1. # -*- coding: utf-8 -*-
  2.  
  3. # Define here the models for your scraped items
  4. #
  5. # See documentation in:
  6. # https://doc.scrapy.org/en/latest/topics/items.html
  7.  
  8. from scrapy import Field,Item
  9.  
  10. class QdItem(Item):
  11. # define the fields for your item here like:
  12.  
  13. book_name = Field() #书名
  14. author=Field() #作者
  15. state=Field() #状态
  16. type=Field() #类型
  17. about=Field() #简介
  18. score=Field() #评分
  19. story=Field() #故事
  20. news=Field() #最新章节

settings.py:

  1. # -*- coding: utf-8 -*-
  2.  
  3. # Scrapy settings for qd project
  4. #
  5. # For simplicity, this file contains only settings considered important or
  6. # commonly used. You can find more settings consulting the documentation:
  7. #
  8. # https://docs.scrapy.org/en/latest/topics/settings.html
  9. # https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
  10. # https://docs.scrapy.org/en/latest/topics/spider-middleware.html
  11.  
  12. BOT_NAME = 'qd'
  13.  
  14. SPIDER_MODULES = ['qd.spiders']
  15. NEWSPIDER_MODULE = 'qd.spiders'
  16.  
  17. DEFAULT_REQUEST_HEADERS = {
  18. 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  19. 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv 11.0) like Gecko',
  20. }
  21. # Crawl responsibly by identifying yourself (and your website) on the user-agent
  22. #USER_AGENT = 'qd (+http://www.yourdomain.com)'
  23.  
  24. # Obey robots.txt rules
  25. ROBOTSTXT_OBEY = True
  26.  
  27. # Configure maximum concurrent requests performed by Scrapy (default: 16)
  28. #CONCURRENT_REQUESTS = 32
  29.  
  30. # Configure a delay for requests for the same website (default: 0)
  31. # See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
  32. # See also autothrottle settings and docs
  33. #DOWNLOAD_DELAY = 3
  34. # The download delay setting will honor only one of:
  35. #CONCURRENT_REQUESTS_PER_DOMAIN = 16
  36. #CONCURRENT_REQUESTS_PER_IP = 16
  37.  
  38. # Disable cookies (enabled by default)
  39. #COOKIES_ENABLED = False
  40.  
  41. # Disable Telnet Console (enabled by default)
  42. #TELNETCONSOLE_ENABLED = False
  43.  
  44. # Override the default request headers:
  45. #DEFAULT_REQUEST_HEADERS = {
  46. # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  47. # 'Accept-Language': 'en',
  48. #}
  49.  
  50. # Enable or disable spider middlewares
  51. # See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
  52. #SPIDER_MIDDLEWARES = {
  53. # 'qd.middlewares.QdSpiderMiddleware': 543,
  54. #}
  55.  
  56. # Enable or disable downloader middlewares
  57. # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
  58. #DOWNLOADER_MIDDLEWARES = {
  59. # 'qd.middlewares.QdDownloaderMiddleware': 543,
  60. #}
  61.  
  62. # Enable or disable extensions
  63. # See https://docs.scrapy.org/en/latest/topics/extensions.html
  64. #EXTENSIONS = {
  65. # 'scrapy.extensions.telnet.TelnetConsole': None,
  66. #}
  67.  
  68. # Configure item pipelines
  69. # See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
  70. #ITEM_PIPELINES = {
  71. # 'qd.pipelines.QdPipeline': 300,
  72. #}
  73.  
  74. # Enable and configure the AutoThrottle extension (disabled by default)
  75. # See https://docs.scrapy.org/en/latest/topics/autothrottle.html
  76. #AUTOTHROTTLE_ENABLED = True
  77. # The initial download delay
  78. #AUTOTHROTTLE_START_DELAY = 5
  79. # The maximum download delay to be set in case of high latencies
  80. #AUTOTHROTTLE_MAX_DELAY = 60
  81. # The average number of requests Scrapy should be sending in parallel to
  82. # each remote server
  83. #AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
  84. # Enable showing throttling stats for every response received:
  85. #AUTOTHROTTLE_DEBUG = False
  86.  
  87. # Enable and configure HTTP caching (disabled by default)
  88. # See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html#httpcache-middleware-settings
  89. #HTTPCACHE_ENABLED = True
  90. #HTTPCACHE_EXPIRATION_SECS = 0
  91. #HTTPCACHE_DIR = 'httpcache'
  92. #HTTPCACHE_IGNORE_HTTP_CODES = []
  93. #HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

middlewares.py:

  1. # -*- coding: utf-8 -*-
  2.  
  3. # Define here the models for your spider middleware
  4. #
  5. # See documentation in:
  6. # https://docs.scrapy.org/en/latest/topics/spider-middleware.html
  7.  
  8. from scrapy import signals
  9.  
  10. class qdSpiderMiddleware(object):
  11. # Not all methods need to be defined. If a method is not defined,
  12. # scrapy acts as if the spider middleware does not modify the
  13. # passed objects.
  14.  
  15. @classmethod
  16. def from_crawler(cls, crawler):
  17. # This method is used by Scrapy to create your spiders.
  18. s = cls()
  19. crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
  20. return s
  21.  
  22. def process_spider_input(self, response, spider):
  23. # Called for each response that goes through the spider
  24. # middleware and into the spider.
  25.  
  26. # Should return None or raise an exception.
  27. return None
  28.  
  29. def process_spider_output(self, response, result, spider):
  30. # Called with the results returned from the Spider, after
  31. # it has processed the response.
  32.  
  33. # Must return an iterable of Request, dict or Item objects.
  34. for i in result:
  35. yield i
  36.  
  37. def process_spider_exception(self, response, exception, spider):
  38. # Called when a spider or process_spider_input() method
  39. # (from other spider middleware) raises an exception.
  40.  
  41. # Should return either None or an iterable of Request, dict
  42. # or Item objects.
  43. pass
  44.  
  45. def process_start_requests(self, start_requests, spider):
  46. # Called with the start requests of the spider, and works
  47. # similarly to the process_spider_output() method, except
  48. # that it doesn’t have a response associated.
  49.  
  50. # Must return only requests (not items).
  51. for r in start_requests:
  52. yield r
  53.  
  54. def spider_opened(self, spider):
  55. spider.logger.info('Spider opened: %s' % spider.name)
  56.  
  57. class qdDownloaderMiddleware(object):
  58. # Not all methods need to be defined. If a method is not defined,
  59. # scrapy acts as if the downloader middleware does not modify the
  60. # passed objects.
  61.  
  62. @classmethod
  63. def from_crawler(cls, crawler):
  64. # This method is used by Scrapy to create your spiders.
  65. s = cls()
  66. crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
  67. return s
  68.  
  69. def process_request(self, request, spider):
  70. # Called for each request that goes through the downloader
  71. # middleware.
  72.  
  73. # Must either:
  74. # - return None: continue processing this request
  75. # - or return a Response object
  76. # - or return a Request object
  77. # - or raise IgnoreRequest: process_exception() methods of
  78. # installed downloader middleware will be called
  79. return None
  80.  
  81. def process_response(self, request, response, spider):
  82. # Called with the response returned from the downloader.
  83.  
  84. # Must either;
  85. # - return a Response object
  86. # - return a Request object
  87. # - or raise IgnoreRequest
  88. return response
  89.  
  90. def process_exception(self, request, exception, spider):
  91. # Called when a download handler or a process_request()
  92. # (from other downloader middleware) raises an exception.
  93.  
  94. # Must either:
  95. # - return None: continue processing this exception
  96. # - return a Response object: stops process_exception() chain
  97. # - return a Request object: stops process_exception() chain
  98. pass
  99.  
  100. def spider_opened(self, spider):
  101. spider.logger.info('Spider opened: %s' % spider.name)

pipelines.py:

  1. # -*- coding: utf-8 -*-
  2.  
  3. # Define your item pipelines here
  4. #
  5. # Don't forget to add your pipeline to the ITEM_PIPELINES setting
  6. # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
  7.  
  8. class QdPipeline(object):
  9. def process_item(self, item, spider):
  10. return item

爬虫(十八):Scrapy框架(五) Scrapy通用爬虫的更多相关文章

  1. 基于Scrapy框架的Python新闻爬虫

    概述 该项目是基于Scrapy框架的Python新闻爬虫,能够爬取网易,搜狐,凤凰和澎湃网站上的新闻,将标题,内容,评论,时间等内容整理并保存到本地 详细 代码下载:http://www.demoda ...

  2. 使用scrapy框架做赶集网爬虫

    使用scrapy框架做赶集网爬虫 一.安装 首先scrapy的安装之前需要安装这个模块:wheel.lxml.Twisted.pywin32,最后在安装scrapy pip install wheel ...

  3. python爬虫随笔-scrapy框架(1)——scrapy框架的安装和结构介绍

    scrapy框架简介 Scrapy,Python开发的一个快速.高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据.Scrapy用途广泛,可以用于数据挖掘.监测和自动化测试 ...

  4. Scrapy框架实战-妹子图爬虫

    Scrapy这个成熟的爬虫框架,用起来之后发现并没有想象中的那么难.即便是在一些小型的项目上,用scrapy甚至比用requests.urllib.urllib2更方便,简单,效率也更高.废话不多说, ...

  5. 爬虫(9) - Scrapy框架(1) | Scrapy 异步网络爬虫框架

    什么是Scrapy 基于Twisted的异步处理框架 纯python实现的爬虫框架 基本结构:5+2框架,5个组件,2个中间件 5个组件: Scrapy Engine:引擎,负责其他部件通信 进行信号 ...

  6. scrapy框架解读--深入理解爬虫原理

    scrapy框架结构图: 组成部分介绍: Scrapy Engine: 负责组件之间数据的流转,当某个动作发生时触发事件 Scheduler: 接收requests,并把他们入队,以便后续的调度 Do ...

  7. 基于Scrapy框架的增量式爬虫

    概述 概念:监测 核心技术:去重 基于 redis 的一个去重 适合使用增量式的网站: 基于深度爬取的 对爬取过的页面url进行一个记录(记录表) 基于非深度爬取的 记录表:爬取过的数据对应的数据指纹 ...

  8. [Python][Scrapy 框架] Python3 Scrapy的安装

    1.方法(只介绍 pip 方式安装) PS.不清楚 pip(easy_install) 可以百度或留言. cmd命令: (直接可以 pip,而不用跳转到 pip.exe目录下,是因为把所在目录加入 P ...

  9. 转: 【Java并发编程】之十八:第五篇中volatile意外问题的正确分析解答(含代码)

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17382679 在<Java并发编程学习笔记之五:volatile变量修饰符-意料之外 ...

随机推荐

  1. Spring事务服务

    Spring事务服务 (2013-07-22 11:13:36) 转载▼ 标签: 事务管理 ssh 分类: Sping Spring为事务管理提供了一流的支持.同时支持编程式事务和声明式事务.无论是编 ...

  2. jsp中获取attribute

    value="<%=request.getSession().getAttribute("username")%>"

  3. mysql 三表索引优化

    建表语句 CREATE TABLE IF NOT EXISTS `phone`( `phoneid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `card` ...

  4. centos 6.5安装NodeJS

    centos 6.5安装NodeJS 下载 可以在本地下载node.js最新版,然后通过ftp工具上传到服务器,或者直接在服务器终端使用wget命令下载(我当时下载的是node-v7.5.0-linu ...

  5. SimpleAuthenticationInfo

    public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSa ...

  6. f_lseek

    我在STM32中移植了fatfs文件系统,实现在SD卡对文件的读写.在普通读写中都没有问题,但是一旦我关闭文件系统,再次打开读写,之前写的数据就被覆盖.比如举个例子:       u8 tx_buff ...

  7. JVM:垃圾回收

    概述 上一篇文章我们已经了解了 Java 的这几块内存区域.对于垃圾回收来说,针对或者关注的是 Java 堆这块区域.因为对于程序计数器.栈.本地方法栈来说,他们随线程而生,随线程而灭,所以这个区域的 ...

  8. Jdk8中Stream流的使用,让你脱离for循环

    学习要求: 知道一点儿函数式接口和Lambda表达式的基础知识,有利于更好的学习. 1.先体验一下Stream的好处 需求:给你一个ArrayList用来保存学生的成绩,让你打印出其中大于60的成绩. ...

  9. IDEA中利用MAVEN制作和打包普通可执行应用(非SprintBoot的WEB应用)

    我使用IDEA也就半年,开发中常常会遇到一些问题,例如用IDEA编写普通的可执行程序: 之前使用Eclipse编写一个可执行的JAVA程序,然后导出打包,非常方便: 但是我呢,想在 IDEA 中用Ma ...

  10. Educational Codeforces Round 65 选做

    好久没更博客了,随便水一篇 E. Range Deleting 题意 给你一个长度为 \(n\) 的序列 \(a_1,a_2,\dots a_n\) ,定义 \(f(l,r)\) 为删除 \(l\le ...