scrapy架构组成
(1)引擎 ‐‐‐》自动运行,无需关注,会自动组织所有的请求对象,分发给下载器
(2)下载器 ‐‐‐》从引擎处获取到请求对象后,请求数据
(3)spiders ‐‐‐》Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例
如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及分析某个网页(或者是有些网页)的地方。
(4)调度器 ‐‐‐》有自己的调度规则,无需关注
(5)管道(Item pipeline) ‐‐‐》最终处理数据的管道,会预留接口供我们处理数据当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。
以下是item pipeline的一些典型应用:
- 清理HTML数据
- 验证爬取的数据(检查item包含某些字段)
- 查重(并丢弃)
- 将爬取结果保存到数据库中
scrapy工作原理
yield
- 带有 yield 的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
- yield 是一个类似 return 的关键字,迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码(下一行)开始执行。
案例:
dangdang网url:‘http://category.dangdang.com/cp01.01.02.00.00.00.html’
在cmd创建项目
scrapy startproject scrapydangdang
创建爬虫文件
scrapy genspider dang http://category.dangdang.com/cp01.01.02.00.00.00.html
在items.py中写入:(这一步是定义你要下载的数据都有什么)
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class ScrapydangdangItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
src = scrapy.Field()
name=scrapy.Field()
price=scrapy.Field()
给src、name、price做定位:
(在给图片做定位时发现网站做了懒加载,但是第一张图片没有做懒加载,所以用if语句给区分开)
import scrapy
from scrapydangdang.items import ScrapydangdangItem
class DangSpider(scrapy.Spider):
name = 'dang'
allowed_domains = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']
start_urls = ['http://category.dangdang.com/cp01.01.02.00.00.00.html']
def parse(self, response):
#//ul[@class="bigimg"]/li//img/@src
#//ul[@class="bigimg"]/li//img/@alt
#//ul[@class="bigimg"]/li//span[@class="search_now_price"]
li_list=response.xpath('//ul[@class="bigimg"]/li')
for i in li_list:
src=i.xpath('.//img/@data-original').extract_first()
if src:
src=src
else:
src=i.xpath('.//img/@src').extract_first()
name=i.xpath('.//img/@alt').extract_first()
price=i.xpath('.//span[@class="search_now_price"]').extract_first()
book=ScrapydangdangItem(src=src,name=name,price=price)
#获取一个book 就将一个book交给pipelines
yield book
来到pipelines.py中使用管道下载:
(要使用管道时,要在settings.py中把ITEM_PIPELINES注释解掉)
ITEM_PIPELINES = {
'scrapydangdang.pipelines.ScrapydangdangPipeline': 300,
}
这里是name、src、price三个数据下载到一个json文件中。
#settings开启管道
class ScrapydangdangPipeline:
def open_spider(self,spider):
self.fp=open('book.json','w',encoding='utf-8')
#items就是yield后面的book对象
def process_item(self, item, spider):
self.fp.write(str(item))
return item
def close_spider(self,spider):
self.fp.close()
这里不宜使用with open('book.json','a',encoding='utf-8')as fp:
的形式,因为这种方法每传递一个对象就会打开一次文件,再关上一次文件,对文件的操作过于频繁。
为了提高下载速度,我们采用多条管道下载。
在settings.py中的ITEM_PIPELINES中加上:
(管道可以有很多个,而且有优先级,优先级范围是1-1000,值越小优先级越高)
ITEM_PIPELINES = {
'scrapydangdang.pipelines.ScrapydangdangPipeline': 300,
'scrapydangdang.pipelines.dangdangdownloadpipeline': 301,
}
然后在pipelines.py中定义管道类:
(这一步是下载图片)
import urllib.request
#'scrapydangdang.pipelines.dangdangdownloadpipeline': 301
class dangdangdownloadpipeline:
def process_item(self, item, spider):
url='http:'+item.get('src')
filename='./books/'+item.get('name')+'.jpg'
urllib.request.urlretrieve(url=url,filename=filename)
return item
cmd中scrapy crawl dang就能启动了: