继续入门示例Demo项目:
项目默认已经创建好了items和 pipelines
Items
爬取的主要目标就是从非结构性的数据源提取结构性数据,例如网页。 Scrapy spider可以以python的dict来返回提取的数据.虽然dict很方便,并且用起来也熟悉,但是其缺少结构性,容易打错字段的名字或者返回不一致的数据,尤其在具有多个spider的大项目中。。
为了定义常用的输出数据,Scrapy提供了 Item 类。 Item 对象是种简单的容器,保存了爬取到得数据。 其提供了 类似于词典(dictionary-like) 的API以及用于声明可用字段的简单语法。
许多Scrapy组件使用了Item提供的额外信息: exporter根据Item声明的字段来导出数据、 序列化可以通过Item字段的元数据(metadata)来定义、 trackref 追踪Item实例来帮助寻找内存泄露 (see 使用 trackref 调试内存泄露) 等等。
Item Pipeline
当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。
每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。
以下是item pipeline的一些典型应用:
清理HTML数据
验证爬取的数据(检查item包含某些字段)
查重(并丢弃)
将爬取结果保存到数据库中
items.py默认代码:
# -*- 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 DemoItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() pass
pipelines.py默认代码:
class DemoPipeline(object): def process_item(self, item, spider): return item
自定义items:
import scrapy class DemoItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() # 存储标题 url = scrapy.Field() # 存储地址
在pipelines中对数据就行清洗:
class DemoPipeline(object): def process_item(self, item, spider): title = item["title"] url = item["url"] """这里插入数据操作代码 比如写入数据库之类的操作""" return item
回到spiders (dev456.py)文件中, 使用刚刚定义的item:
# -*- coding: utf-8 -*- import scrapy from demo.items import DemoItem class Dev456Spider(scrapy.Spider): name = 'dev456' allowed_domains = ['456dev.com'] start_urls = ['http://www.456dev.com/list-1.html'] def parse(self, response): titles = response.xpath("//li/a[contains(@class, 'title')]/text()").extract() urls = response.xpath("//li/a[contains(@class, 'title')]/@href").extract() for title, url in zip(titles, urls): item = DemoItem() item["title"] = title item["url"] = response.urljoin(url) yield item
最后在settings.py中启用pipelines, 取消注释启用默认item pipeline:
执行结果:
一下子跑完了,因为这只是一页的数据,如何抓取整个栏目的数据呢:
通过分析,我们可以知道只要让spider继续请求分页地址解析数据就行了:
# -*- coding: utf-8 -*- import scrapy from demo.items import DemoItem class Dev456Spider(scrapy.Spider): name = 'dev456' allowed_domains = ['456dev.com'] start_urls = ['http://www.456dev.com/list-1.html'] def parse(self, response): titles = response.xpath("//li/a[contains(@class, 'title')]/text()").extract() urls = response.xpath("//li/a[contains(@class, 'title')]/@href").extract() for title, url in zip(titles, urls): item = DemoItem() item["title"] = title item["url"] = response.urljoin(url) yield item # 下一页数据 next_url_list = response.xpath("//li[contains(@class, 'next')]/a/@href").extract() if next_url_list: # 新请求 yield scrapy.Request(response.urljoin(next_url_list[0]))
新请求默认继续调用parse方法解析数据,循环下去,直到没有下页数据时停止.
附上完整的项目代码: