Scrapy入门(二)
Scrapy组件详解
Items
爬取的主要目标就是从非结构性的数据源提取结构性数据。Scrapy提供 Item 类来满足这样的需求。
Item 对象是种简单的容器,保存了爬取到得数据。 其提供了 类似于词典(dictionary-like) 的API以及用于声明可用字段的简单语法。
使用Items类仅仅需要继承scrapy的Items类即可
eg
import scrapy
class Product(scrapy.Item):
name = scrapy.Field()
price = scrapy.Field()
Field
Field 对象对接受的值没有任何限制。Field 仅仅是内置的 dict 类的一个别名,并没有提供额外的方法或者属性。换句话说, Field 对象完完全全就是Python字典(dict)。被用来基于类属性(class attribute)的方法来支持 item声明语法
Item Pipeline
当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。
每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。
以下是item pipeline的一些典型应用:
- 清理HTML数据
- 验证爬取的数据(检查item包含某些字段)
- 查重(并丢弃)
- 将爬取结果保存到数据库中
简单的说,Spider用来提取数据,而Pipeline用来处理数据。使用Pipeline将爬取的数据存入数据库的例子会在后面的博客中介绍。
Scrapy框架内部提供了两个Item Pipeline,专门用于下载文件和图片
- FilesPipeline
- ImagePipeline
其中ImagePipeline是FilesPipeline的子类。
可以在settings中设定FILES_STORE
用来指定文件下载目录
ImagePipeline在FilesPipeline上添加了一些特有功能,在settings里设置IMAGES_THUMBS
生成图片缩略图。
eg
IMAGES_THUMBS={
'small':(50,50),
'big':(270,270),
}
还可以过滤尺寸过小的图片,在settings中配置IMAGES_MIN_WIDTH
和IMAGES_MIN_HEIGHT
即可
Settings
Scrapy设定(settings)提供了定制Scrapy组件的方法。您可以控制包括核心(core),插件(extension),pipeline及spider组件。
设定为代码提供了提取以key-value映射的配置值的的全局命名空间(namespace)。 设定可以通过下面介绍的多种机制进行设置。
例如在上面写好了Pipeline,需要在Settings里进行配置,Pipeline才能生效。
ITEM_PIPELINES = {
'myproject.pipelines.PricePipeline': 300,
'myproject.pipelines.JsonWriterPipeline': 800,
}
分配给每个类的整型值,确定了他们运行的顺序,item按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内。
更多的设定方式可以在官方文档中查阅。这里列举一些常用的:
-
DEPTH_LIMIT
爬取网站最大允许的深度(depth)值。如果为0,则没有限制。 -
ITEM_PIPELINES
保存项目中启用的pipeline及其顺序的字典。该字典默认为空. -
RANDOMIZE_DOWNLOAD_DELAY
如果启用,当从相同的网站获取数据时,Scrapy将会等待一个随机的值 (0.5到1.5之间的一个随机值 * DOWNLOAD_DELAY)。该随机值降低了crawler被检测到(接着被block)的机会。某些网站会分析请求, 查找请求之间时间的相似性。 -
ROBOTSTXT_OBEY
如果启用,Scrapy将会尊重 robots.txt策略。 -
USER_AGENT
用户代理
爬取Sklearn文档中所有例子
所爬取文件的起始页https://scikit-learn.org/stable/auto_examples/
创建项目
scrapy startproject sklearnExample
生成模板
cd sklearnExample
scrapy genspider example scikit-learn.org
编写Items类
import scrapy
class SklearnexampleItem(scrapy.Item):
file_urls = scrapy.Field()
files = scrapy.Field()
pass
设置管道
文件以它们URL的 SHA1 hash 作为文件名。为了方便识别,重写文件命名规则
from scrapy.pipelines.files import FilesPipeline
from urllib.parse import urlparse
from os.path import basename, dirname, join
class MyFilesPipeline(FilesPipeline):
def file_path(self, request, response=None, info=None):
path = urlparse(request.url).path
return join(basename(dirname(path)), basename(path))
配置setting
#开启管道
ITEM_PIPELINES = {
'sklearnExample.pipelines.MyFilesPipeline': 1,
# 'sklearnExample.pipelines.SklearnexamplePipeline': 300,
}
#设置下载文件位置
FILES_STORE = 'examples_src'
编写爬虫Spider
自己解析html,使用相应的css()方法和xpath()方法获取链接
import scrapy
from scrapy.linkextractors import LinkExtractor
from ..items import SklearnexampleItem
class ExampleSpider(scrapy.Spider):
name = 'example'
allowed_domains = ['scikit-learn.org']
start_urls = ['https://scikit-learn.org/stable/auto_examples/']
def parse(self, response):
le = LinkExtractor(restrict_css='div.figure span.caption-text')
print(len(le.extract_links(response)))
for link in le.extract_links(response):
yield scrapy.Request(link.url, callback=self.parse_example)
pass
def parse_example(self, response):
href = response.css('a.reference.download::attr(href)').extract_first()
url = response.urljoin(href)
example = SklearnexampleItem()
example['file_urls'] = [url]
return example
运行爬虫,查看结果
scrapy crawl example -o example.json
所有文件都被爬下来了,并且爬取的日志也被记录在example.json中。
爬取360图片
http://image.so.com/z?ch=art每次下拉页面就会发送jquery请求新的图片,使用chrome分析
##### 创建项目
scrapy startproject soImage
生成模板
cd soImage
scrapy genspider image image.so.com
配置setting
#开启管道
ITEM_PIPELINES = {
# 'soImage.pipelines.SoimagePipeline': 300,
'scrapy.pipelines.images.ImagesPipeline' : 1,
}
#设置下载文件位置
IMAGES_STORE = 'downloadImages'
另外360的网站robots协议是禁止爬虫的,如果不修改scrapy里的设置就无法访问
所以更改setting.py内的Obey robots.txt rules
ROBOTSTXT_OBEY = False
编写爬虫Spider
import scrapy
from scrapy import Request
import json
class ImageSpider(scrapy.Spider):
name = 'image'
BASE_URL = 'http://image.so.com/zj?ch=art&sn=%s&listtype=new&temp=1'
start_index = 0
MAX_DOWNLOAD_NUM = 1000 #防止下载过多,磁盘使用过大
start_urls = [BASE_URL % 0]
def parse(self, response):
infos = json.loads(response.body.decode('utf-8'))
print(infos)
yield {'image_urls' : [info['qhimg_url'] for info in infos['list']]}
self.start_index += infos['count']
if infos['count'] > 0 and self.start_index < self.MAX_DOWNLOAD_NUM:
yield Request(self.BASE_URL % self.start_index)
pass
运行爬虫,查看结果
所有图片就下载下来了
上一篇:Scrapy入门(一)