在之前的项目中已经可以正常运行出scrapy框架下的爬虫程序,但是如果换一个项目换一个爬取任务,要活学活用还需要进行针对scrapy是如何运行的进行深入的学习.
基本概念
具体从代码中解析
item
pipelines
spiders
可以从这里学习详细的结构说明:
http://www.tuicool.com/articles/fiyIbq
Scrapy框架主要由五大组件组成,调试器(Scheduler)、下载器(Downloader)、爬虫(Spider)和实体管道(Item Pipeline)、Scrapy引擎(Scrapy Engine)。
如下图.
参照项目 meizitu 源代码在:
https://github.com/luyishisi/WebCrawlers/tree/master/scrapy_code/meizitu
在定义这部分时,要考虑项目目标是为了爬取妹子图网的图片,因此需要的结构有:
item代码如下:
import scrapy
class MeizituItem(scrapy.Item):
url = scrapy.Field()
name = scrapy.Field()
tags = scrapy.Field()
image_urls = scrapy.Field()
images = scrapy.Field()
Field对象指明了每个字段的元数据(metadata)。
您可以为每个字段指明任何类型的元数据。Field 对象对接受的值没有任何限制。也正是因为这个原因,文档也无法提供所有可用的元数据的键(key)参考列表。Field 对象中保存的每个键可以由多个组件使用,并且只有这些组件知道这个键的存在
可从抓取进程中得到这些信息, 比如预先解析提取到的原生数据,items 提供了盛装抓取到的数据的*容器* , 而Item Loaders提供了构件*装载populating*该容器。
在用于下面例子的管道功能时.在spiders中使用了item的实例化:代码如下:
def parse_item(self, response):
#l=用ItemLoader载入MeizituItem()
l = ItemLoader(item=MeizituItem(), response=response)
#名字
l.add_xpath('name', '//h2/a/text()')
#标签
l.add_xpath('tags', "//div[@id='maincontent']/div[@class='postmeta clearfix']/div[@class='metaRight']/p")
#图片连接
l.add_xpath('image_urls', "//div[@id='picture']/p/img/@src", Identity())
#url
l.add_value('url', response.url)
return l.load_item()
最终, 当所有数据被收集起来之后, 调用 ItemLoader.load_item() 方法, 实际上填充并且返回了之前通过调用 add_xpath(), add_css(), and add_value() 所提取和收集到的数据的Item.
需要导入settings配置文件,根据你保存的内容需要不同的包,例如,保存文本数据往往需要json包,本项目保存的是图片,则导入os包用于设定保存路径等.最重要的是要导入requests包.用于发送请求给图片的url,将返回的应答包进行保存.
本部分至少需要重写图片下载类,返回的是item对象.
file_urls
组内。
l.add_xpath('image_urls', "//div[@id='picture']/p/img/@src", Identity()
Pipeline
,file_urls || image_urls
组内的URLs将被Scrapy的调度器和下载器(这意味着调度器和下载器的中间件可以复用)安排下载(将url请求发送到下载器)。项目会在这个特定的管道阶段保持“locker”的状态,直到完成文件的下载(或者由于某些原因未完成下载)。files
)将被更新到结构中。这个组将包含一个字典列表,其中包括下载文件的信息,比如下载路径、源抓取地址(从 file_urls
组获得)和图片的校验码(checksum)。 files
列表中的文件顺序将和源 file_urls
组保持一致。如果某个图片下载失败,将会记录下错误信息,图片也不会出现在 files
组中。为了启用 media pipeline,你首先需要在项目中添加它setting.
对于 Images Pipeline, 使用:
<span class="n">ITEM_PIPELINES</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'scrapy.pipeline.<span style="color: #ff0000;">images</span>.<span style="color: #ff0000;">Images</span>Pipeline'</span><span class="p">:</span> <span class="mi">1</span><span class="p">}</span>
对于 Files Pipeline, 使用:
<span class="n">ITEM_PIPELINES</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'scrapy.pipeline.<span style="color: #ff0000;">files</span>.<span style="color: #ff0000;">Files</span>Pipeline'</span><span class="p">:</span> <span class="mi">1</span><span class="p">}</span>
因此配置文件如下:
BOT_NAME = 'meizitu'
SPIDER_MODULES = ['meizitu.spiders']
NEWSPIDER_MODULE = 'meizitu.spiders'
#载入ImageDownLoadPipeline类
#为了启用一个Item Pipeline组件,你必须将它的类添加到 ITEM_PIPELINES 配置
#分配给每个类的整型值,确定了他们运行的顺序,item按数字从低到高的顺序,通过pipeline,
TEM_PIPELINES = {'meizitu.pipelines.ImageDownloadPipeline': 1}
#图片储存,第一个meizitu是项目名称,imagedown部分则是类的名字.
IMAGES_STORE = '.'
# -*- coding: utf-8 -*-
#图片下载部分(自动增量)
import requests
from meizitu import settings
import os
#导入重写图片下载类
class ImageDownloadPipeline(object):
def process_item(self, item, spider):
#每个item pipeline组件都需要调用该方法,这个方法必须返回一个 Item (或任何继承类)对象,
# 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理
if 'image_urls' in item:#如果‘图片地址’在项目中
images = []#定义图片空集
dir_path = '%s/%s' % (settings.IMAGES_STORE, spider.name)
#建立目录名字和项目名称一致
if not os.path.exists(dir_path):
os.makedirs(dir_path)
#根据item字典进行查询
for image_url in item['image_urls']:
us = image_url.split('/')[3:]
image_file_name = '_'.join(us)
file_path = '%s/%s' % (dir_path, image_file_name)
images.append(file_path)
#如果这个文件存在则跳过
if os.path.exists(file_path):
continue
#进行图片文件写入,wb模式打开文件,然后requests.get获取图片流,
with open(file_path, 'wb') as handle:
response = requests.get(image_url, stream=True)
for block in response.iter_content(1024):
#获取的流如果有不存在的,则使用break结束,如果没有一次结束则进行写入
if not block:
break
handle.write(block)
item['images'] = images
return item
Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是定义爬取的动作及分析某个网页(或者是有些网页)的地方。
对spider来说,爬取的循环类似下文:
start_requests()
来获取的。 start_requests()
读取 start_urls
中的URL, 并以 parse
为回调函数生成 Request
。Item
对象、dict、 Request
或者一个包括三者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。
虽然该循环对任何类型的spider都(多少)适用,但Scrapy仍然为了不同的需求提供了多种默认spider。
导入选择器,itemloader等.重写类,从start_urls开始爬取
# -*- coding: utf-8 -*-
import scrapy
from scrapy.selector import Selector
from scrapy.contrib.loader import ItemLoader, Identity
from meizitu.items import MeizituItem
class MeiziSpider(scrapy.Spider):
name = "meizi"
allowed_domains = ["meizitu.com"]
start_urls = (
'http://www.meizitu.com/',
)
def parse(self, response):
#sel是页面源代码,载入scrapy.selector
sel = Selector(response)
#每个连接,用@href属性
for link in sel.xpath('//h2/a/@href').extract():
#请求=Request(连接,parese_item)
request = scrapy.Request(link, callback=self.parse_item)
yield request#返回请求
#获取页码集合
pages = sel.xpath('//*[@id="wp_page_numbers"]/ul/li/a/@href').extract()
print('pages: %s' % pages)#打印页码
if len(pages) > 2:#如果页码集合>2
page_link = pages[-2]#图片连接=读取页码集合的倒数第二个页码
page_link = page_link.replace('/a/', '')#图片连接=page_link(a替换成空)
request = scrapy.Request('http://www.meizitu.com/a/%s' % page_link, callback=self.parse)
yield request#返回请求
def parse_item(self, response):
#l=用ItemLoader载入MeizituItem()
l = ItemLoader(item=MeizituItem(), response=response)
#名字
l.add_xpath('name', '//h2/a/text()')
#标签
l.add_xpath('tags', "//div[@id='maincontent']/div[@class='postmeta clearfix']/div[@class='metaRight']/p")
#图片连接
l.add_xpath('image_urls', "//div[@id='picture']/p/img/@src", Identity())
#url
l.add_value('url', response.url)
return l.load_item()
阿萨德 阿斯顿
原创文章,转载请注明: 转载自URl-team
本文链接地址: scrapy笔记六 scrapy运行架构的实例配合解析
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有