前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >二、Item Pipeline和Spider-----基于scrapy取校花网的信息 编写item pipeline

二、Item Pipeline和Spider-----基于scrapy取校花网的信息 编写item pipeline

作者头像
酱紫安
发布2018-04-16 15:22:07
1.2K0
发布2018-04-16 15:22:07
举报
文章被收录于专栏:python学习路python学习路

Item Pipeline

当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item。

每个Item Pipeline都是实现了简单方法的Python类,比如决定此Item是丢弃而存储。以下是item pipeline的一些典型应用:

  • 验证爬取的数据(检查item包含某些字段,比如说name字段)
  • 查重(并丢弃)
  • 将爬取结果保存到文件或者数据库中

编写item pipeline

编写item pipeline很简单,item pipiline组件是一个独立的Python类,其中process_item()方法必须实现

代码语言:javascript
复制
 1  2 
 3 class SomethingPipeline(object):
 4     def __init__(self):    
 5         # 可选实现,做参数初始化等
 6         # doing something
 7 
 8     def process_item(self, item, spider):
 9         # item (Item 对象) – 被爬取的item
10         # spider (Spider 对象) – 爬取该item的spider
11         # 这个方法必须实现,每个item pipeline组件都需要调用该方法,
12         # 这个方法必须返回一个 Item 对象,被丢弃的item将不会被之后的pipeline组件所处理。
13         return item
14 
15     def open_spider(self, spider):
16         # spider (Spider 对象) – 被开启的spider
17         # 可选实现,当spider被开启时,这个方法被调用。
18 
19     def close_spider(self, spider):
20         # spider (Spider 对象) – 被关闭的spider
21         # 可选实现,当spider被关闭时,这个方法被调用

 启用一个Item Pipeline组件

为了启用Item Pipeline组件,必须将它的类添加到 settings.py文件ITEM_PIPELINES 配置,就像下面这个例子:

代码语言:javascript
复制
1 # See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
2 ITEM_PIPELINES = {
3     #'mySpider.pipelines.SomePipeline': 300,
4     "mySpider.pipelines.ItcastJsonPipeline":300
5 }

 分配给每个类的整型值,确定了他们运行的顺序,item按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内(0-1000随意设置,数值越低,组件的优先级越高)。

Spider

Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及分析某个网页(或者是有些网页)的地方。

class scrapy.Spider是最基本的类,所有编写的爬虫必须继承这个类。

__init__() : 初始化爬虫名字和start_urls列表

start_requests() 调用make_requests_from url():生成Requests对象交给Scrapy下载并返回response

parse() : 解析response,并返回Item或Requests(需指定回调函数)。Item传给Item pipline持久化 , 而Requests交由Scrapy下载,并由指定的回调函数处理(默认parse()),一直进行循环,直到处理完所有的数据为止。

代码语言:javascript
复制
 1 # -*- coding: utf-8 -*-
 2 import scrapy
 3 
 4 
 5 class BaiduSpider(scrapy.Spider):
 6     name = 'baidu'
 7     allowed_domains = ['baidu.com']
 8     start_urls = ['http://baidu.com/']
 9 
10     def parse(self, response):
11         pass
代码语言:javascript
复制
 源码:

  1 class Spider(object_ref):
  2     """Base class for scrapy spiders. All spiders must inherit from this
  3     class.
  4     """
  5     # 定义spider名字的字符串(string)。spider的名字定义了Scrapy如何定位(并初始化)spider,所以其必须是唯一的。
  6     # name是spider最重要的属性,而且是必须的。
  7     # 一般做法是以该网站(domain)(加或不加 后缀 )来命名spider。
  8 
  9     name = None
 10     custom_settings = None
 11 
 12     # 初始化,提取爬虫名字,start_ruls
 13     def __init__(self, name=None, **kwargs):
 14         if name is not None:
 15             self.name = name
 16         # 如果爬虫没有名字,中断后续操作则报错
 17         elif not getattr(self, 'name', None):
 18             raise ValueError("%s must have a name" % type(self).__name__)
 19 
 20         # python 对象或类型通过内置成员__dict__来存储成员信息
 21         self.__dict__.update(kwargs)
 22 
 23         # URL列表。当没有指定的URL时,spider将从该列表中开始进行爬取。 因此,第一个被获取到的页面的URL将是该列表之一。 后续的URL将会从获取到的数据中提取。
 24         if not hasattr(self, 'start_urls'):
 25             self.start_urls = []
 26 
 27     @property
 28     def logger(self):
 29         logger = logging.getLogger(self.name)
 30         return logging.LoggerAdapter(logger, {'spider': self})
 31 
 32     #打印Scrapy执行后的log信息
 33     def log(self, message, level=logging.DEBUG, **kw):
 34         """Log the given message at the given log level
 35 
 36         This helper wraps a log call to the logger within the spider, but you
 37         can use it directly (e.g. Spider.logger.info('msg')) or use any other
 38         Python logger too.
 39         """
 40         self.logger.log(level, message, **kw)
 41 
 42     @classmethod
 43     def from_crawler(cls, crawler, *args, **kwargs):
 44         spider = cls(*args, **kwargs)
 45         spider._set_crawler(crawler)
 46         return spider
 47 
 48     # 判断对象object的属性是否存在,不存在做断言处理
 49     def set_crawler(self, crawler):
 50         warnings.warn("set_crawler is deprecated, instantiate and bound the "
 51                       "spider to this crawler with from_crawler method "
 52                       "instead.",
 53                       category=ScrapyDeprecationWarning, stacklevel=2)
 54         assert not hasattr(self, 'crawler'), "Spider already bounded to a " \
 55                                              "crawler"
 56         self._set_crawler(crawler)
 57 
 58     def _set_crawler(self, crawler):
 59         self.crawler = crawler
 60         self.settings = crawler.settings
 61         crawler.signals.connect(self.close, signals.spider_closed)
 62 
 63     # 该方法将读取start_urls内的地址,并为每一个地址生成一个Request对象,交给Scrapy下载并返回Response
 64     def start_requests(self):
 65         cls = self.__class__
 66         if method_is_overridden(cls, Spider, 'make_requests_from_url'):
 67             warnings.warn(
 68                 "Spider.make_requests_from_url method is deprecated; it "
 69                 "won't be called in future Scrapy releases. Please "
 70                 "override Spider.start_requests method instead (see %s.%s)." % (
 71                     cls.__module__, cls.__name__
 72                 ),
 73             )
 74             for url in self.start_urls:
 75                 yield self.make_requests_from_url(url)
 76         else:
 77             for url in self.start_urls:
 78                 yield Request(url, dont_filter=True)
 79 
 80     # start_requests()中调用,实际生成Request的函数。
 81     # Request对象默认的回调函数为parse(),提交的方式为get
 82     def make_requests_from_url(self, url):
 83         """ This method is deprecated. """
 84         return Request(url, dont_filter=True)
 85 
 86     # 默认的Request对象回调函数,处理返回的response。
 87     # 生成Item或者Request对象。用户必须实现这个类
 88     def parse(self, response):
 89         raise NotImplementedError('{}.parse callback is not defined'.format(self.__class__.__name__))
 90 
 91 
 92     @classmethod
 93     def update_settings(cls, settings):
 94         settings.setdict(cls.custom_settings or {}, priority='spider')
 95 
 96     @classmethod
 97     def handles_request(cls, request):
 98         return url_is_from_spider(request.url, cls)
 99 
100     @staticmethod
101     def close(spider, reason):
102         closed = getattr(spider, 'closed', None)
103         if callable(closed):
104             return closed(reason)
105 
106     def __str__(self):
107         return "<%s %r at 0x%0x>" % (type(self).__name__, self.name, id(self))
108 
109     __repr__ = __str__

每天 一个小实例:(我取得是图片和图片名)

代码语言:javascript
复制
 1 items.py
 2 
 3 
 4 # -*- coding: utf-8 -*-
 5 
 6 # Define here the models for your scraped items
 7 #
 8 # See documentation in:
 9 # https://doc.scrapy.org/en/latest/topics/items.html
10 
11 import scrapy
12 
13 '''Item 定义结构化数据字段,用来保存爬取到的数据,有点像Python中的dict,但是提供了一些额外的保护减少错误。
14 
15 可以通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field的类属性来定义一个Item(可以理解成类似于ORM的映射关系)。'''
16 class MyspiderItem(scrapy.Item):
17     # define the fields for your item here like:
18     img_name = scrapy.Field()
19     img_url = scrapy.Field()
代码语言:javascript
复制
 1 xiaohua.py
 2 
 3 
 4 # -*- coding: utf-8 -*-
 5 import scrapy
 6 from myspider.items import MyspiderItem
 7 
 8 class BaisiSpider(scrapy.Spider):
 9     name = 'xiaohua'
10     allowed_domains = ['www.521609.com']
11     start_urls = ['http://www.521609.com/daxuexiaohua/list31.html']
12     #   page = 31
13     def parse(self, response):
14 
15         # 将我们得到的数据封装到一个 `MyspiderItem` 对象
16         item = MyspiderItem()
17 
18         #提取数据
19         img_list = response.xpath('//div[@class="index_img list_center"]/ul/li')
20         for img in img_list:
21             img_name = img.xpath('./a/img/@alt')[0].extract()
22             img_url = img.xpath('./a/img/@src')[0].extract()
23             item['img_name'] = img_name
24             item['img_url'] = img_url
25 
26             # 将获取的数据交给pipelines
27             yield item
28 
29         # if self.page < 35:
30         #     self.page += 1
31         #     curpage_url = 'http://www.521609.com/daxuexiaohua/list' + str(self.page) + '.html'
32         #
33         #  # 发送新的url请求加入待爬队列,并调用回调函数 self.parse
34         #     yield scrapy.Request(curpage_url, callback=self.parse)
代码语言:javascript
复制
 1 pipelines.py
 2 
 3 
 4 # -*- coding: utf-8 -*-
 5 
 6 # Define your item pipelines here
 7 #
 8 # Don't forget to add your pipeline to the ITEM_PIPELINES setting
 9 # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
10 import urllib.request
11 import os
12 class BaiSispiderPipeline():
13 
14     def process_item(self, item, spider):
15         base_url = 'http://www.521609.com'
16         file_name = item['img_name'] + '.png'
17         file_path = os.path.join("F:\\myspider\\myspider\\imgs", file_name)
18         if item['img_url']:
19              urllib.request.urlretrieve(base_url + item['img_url'],file_path)
20         # with open(file_path, 'wb') as file:
21         #     # 2. 获取图片里的内容
22         #     images = requests.get(base_url + item['img_url'])
23         #
24         #     # 3. 调用文件对象write() 方法,将page_html的内容写入到文件里
25         #     file.write(images.content)
26         return item

 结果:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-02-27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Item Pipeline
    • 编写item pipeline
    • Spider
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档