基础命令
-
scrapy3 startproject demo [project_dir]在project_dir目录下创建一个Scrapy项目。如果project_dir未指定,project_dir则与相同myproject。
-
cd demo 进入到项目内
-
scrapy genspider mydomain mydomain.com 创建一个蜘蛛爬虫
-
全局命令:
startproject
genspider
settings
runspider
shell
fetch
view
version
仅项目命令:
crawl
check
list
parse
-edit
-bench -
scrapy crawl spidername 开始使用蜘蛛爬行
-
scrapy check [-l] spidername 运行合同检查
-
scrapy list 列出当前项目中所有可用的蜘蛛。输出是每行一个蜘蛛
-
scrapy fetch [–option] url_name 使用Scrapy下载器下载给定的URL,并将内容写入标准输出。
–nolog 不输出打印日志
–headers:打印响应的HTTP头,而不是响应的正文
–no-redirect:不遵循HTTP 3xx重定向(默认为遵循它们) -
scrapy view [–option] url_name 在浏览器中打开给定的URL,就像您的Scrapy蜘蛛会“看到”它一样。有时,蜘蛛看到的页面与普通用户的页面不同
–no-redirect:不遵循HTTP 3xx重定向(默认为遵循它们) -
scrapy shell url_name 为给定的URL(如果给定)启动Scrapy shell,如果没有给定的URL,则为空。还支持UNIX样式的本地文件路径
–no-redirect:不遵循HTTP 3xx重定向(默认为遵循它们
response.text
response.headers
view(response) -
scrapy parse url_name [options] 使用随–callback选项传递的方法(parse如果未提供),获取给定的URL并与处理它的蜘蛛解析。
callback或-c:蜘蛛方法,用作解析响应的回调, 调用
-
scrapy settings [options] 获取Scrapy设置的值
scrapy3 settings --get=DOWNLOADER_MIDDERWARES_BASE
-
scrapy runspider spider_file.py 无需创建项目即可运行包含在Python文件中的蜘蛛程序。
-
scrapy version [-v] 打印Scrapy版本。如果与-v它一起使用,还可以打印Python,Twisted和Platform信息,这对于错误报告很有
-
scrapy crawl myspider -a category = electronics
通过调用父类的初始化方法来获取category传来的参数(在父类的属性中)
class Myspider(scrapy.Spider) name = 'myspider' def __init__ (self,category=None,*args,**kwargs) super(Myspider,self).__init__(*args,**kwargs) self.category = category def parse(self,response) self.logger.info(self.category)
选择器
-
response.selector.xpath(’//span/text()’).extract_first()
selector.xpath选择器(也可简写为.xpath) -
response.selector.css(‘title::text’).extract_first()
selector.css选择器(也可简写为.css)
response.css(‘a::text()’) 提取元素文本
response.css(‘a::attr(src)’) 提取元素的属性值
extract(default=’’): 这个方法返回的是一个数组list对象,,里面包含了多个string,如果只有一个string,则返回[‘ABC’] default为找不到的默认值
extract_first():这个方法返回的是一个string字符串,是list数组里面的第一个字符串。基本元素[属性]例:p[title]
基本元素[属性 = 值] //属性只有一个值 p[title = qiuqiu2]
基本元素[属性 = 值] 属性中做字符串拆分,只要能拆出来value这个词就行
基本元素[属性 ~= 值] //属性有多个值,空格隔开 p[title ~= qiuqiu1 abc]
基本元素[属性 ^= 值] //属性以特定值开始 p[title ^= qiuqiu]
基本元素[属性 $= 值] //属性以特定值结束 p[title $= bc]
获取属性值(html)里面的标签属性 response.css('a[href=image] img::attr(src)’)
css选择器支持re(正则表达式) response.css(‘a::text’).re(‘None:(.*)’)
spider
对spider来说,爬取的循环类似下文:
-
以初始的URL初始化Request,并设置回调函数。 当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。
-
spider中初始的request是通过调用 start_requests() 来获取的。 start_requests() 读取 start_urls 中的URL, 并以 parse 为回调函数生成 Request 。
-
在回调函数内分析返回的(网页)内容,返回 Item 对象或者 Request 或者一个包括二者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。
-
在回调函数内,您可以使用 选择器(Selectors) (您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器) 来分析网页内容,并根据分析的数据生成item。
-
最后,由spider返回的item将被存到数据库(由某些 Item Pipeline 处理)或使用 Feed exports 存入到文件中。
spider作为Spider子类的属性方法
属性
-
name, 定义spider名字的字符串(string)。spider的名字定义了Scrapy如何定位(并初始化)spider,所以其必须是唯一的。 不过您可以生成多个相同的spider实例(instance),这没有任何限制。 name是spider最重要的属性,而且是必须的
name = ‘spider_name’
-
allowed_domains, 可选。包含了spider允许爬取的域名(domain)列表(list)。 当 OffsiteMiddleware 启用时, 域名不在列表中的URL不会被跟进
allowed_domains = [‘leadingme.top’]
-
start_urls, URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。 因此,第一个被获取到的页面的URL将是该列表之一。 后续的URL将会从获取到的数据中提取
start_urls = [‘http://leadingme.top/’]
-
custom_settings, 运行此Spider时将从项目范围的配置中覆盖的设置字典。由于必须在实例化之前更新设置,因此必须将其定义为类属性。
custom_settings = { DEFAULT_REQUEST_HEADERS : { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en', } }
方法
-
from_crawler(crawler,* args,** kwargs) 此方法 在新实例中设置crawler和settings属性,因此以后可以在Spider代码中对其进行访问
@classmethod return cls( mongo_url=crawler.settings.get('MONGO_URL'), mongo_db = crawler.settings.get('MONGO_DB') )
-
start_requests() 当指定了URL时,make_requests_from_url()将被调用来创建Request对象。该方法仅会被Scrapy调用一次,因此您可以将其实现为生成器。该方法的替代实现是使用start_urls的url生成Request。
默认的是get请求,可以改写start_requests()方法为post请求def start_requests(self): yield scrapy.Requests(url='http://httpbin.org/post',method='POST',callback=self.parse)
-
make_requests_from_url(url) 该方法Request在start_requests()初始化请求时被调用,也被用于转化URL为请求。
修改了默认的回调函数,次方法默认被start_requests调用,如果重写start _requests,则makemake_requests_from_url失效
def start_requests(self): yield scrapy.Requests(url='www.baidu.com',callback=self.parse_index def make_requests_from_url(self): yield scrapy.Requests(url=url,callback=self.parse_index) def parse(self, response): print('Baidu', response.status) ```
-
parse(response) 当response没有指定指定函数时,该方法是Scrapy处理下载的response的替代方法。parse负责处理response并返回处理的数据以及(/或)跟进的URL。 Spider对其他的请求的副本函数也有相同的要求。如果生成一个item对象,则返回给itempipeline处理,如果生成Request对象,则会被接入到start_urls(url队列中),等待start-requests调用
yiely item yiely scrapy.Request(url=url,callback=self.parse)
-
log(message[,level,component])使用scrapy.log.msg()方法记录(log)消息。log中自动带上该蜘蛛的name属性,通过调用self.logger实例对象的方法实现
CRITICAL - 严重错误(critical)
ERROR - 一般错误(regular errors)
WARNING - 警告信息(warning messages)
INFO - 一般信息(informational messages)
DEBUG - 调试信息(debugging messages)
from scrapy import log
log.msg("This is a warning", level=log.WARNING)
def parse(response):
self.logger.info(response.status) 控制台输出INFO:200的调试信息
- closed(reason) 当spider关闭时,该函数被调用。
Item Pipeline组件类
-
简介
当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理。每个item pipeline组件(有时称之为“Item Pipeline”)是实现了简单方法的Python类。他们接收到Item并通过它执行一些行为,同时也决定此Item是否继续通过pipeline,或是被丢弃而不再进行处理。
一般用于以下情景:
- 清理HTML数据
- 验证爬取的数据(检查item包含某些字段)
- 查重(并丢弃)
- 将爬取结果保存到数据库中 -
process_item(self, item, spider) 每个item pipeline组件都需要调用该方法,这个方法必须返回一个 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的item将不会被之后的pipeline组件所处理。(返回的值给优先级后面的Pipeline处理)
-
open_spider(self, spider) 当spider被开启时,这个方法被调用。
-
close_spider(spider) 当spider被关闭时,这个方法被调用
-
from_cralwer(cls, crawler)类方法 此方法 在新实例中设置crawler.settings属性,因此以后可以在Spider代码中对其进行访问
补充
- 写入json文件
import json
class JsonWriterPipeline(object):
def __init__(self):
self.file = open('items.jl', 'wb')
def process_item(self, item, spider):
line = json.dumps(dict(item)) + "\n"
self.file.write(line)
# 存储到MongoDB
import pymongo
class MongoPipeline(object):
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
# 相当于用 类(a,b)创建并返回了一个实例对象
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
collection_name = item.__class__.__name__
self.db[collection_name].insert(dict(item))
return item
- 去重
from scrapy.exceptions import DropItem
class DuplicatesPipeline(object):
def __init__(self):
# set() 函数创建一个无序不重复元素集,可进行关系测试,删除重复数据,还可以计算交集、差集、并集等 如 set([1,2,3])|set([4,5,6]) = set([1,2,3,4,5,6])
self.ids_seen = set()
def process_item(self, item, spider):
if item['id'] in self.ids_seen:
# 删除该item,并抛出异常
raise DropItem("Duplicate item found: %s" % item)
else:
self.ids_seen.add(item['id'])
return item
- 启用一个Pipeline组件类
ITEM_PIPELINES = {
'myproject.pipelines.PricePipeline': 300,
'myproject.pipelines.JsonWriterPipeline': 800,
}
分配给每个类的整型值,确定了他们运行的顺序,item按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内。
Scrapy分布式架构
- Redis队列
- Redis,非关系型数据库,Key-Value形式存储,结构灵活
- 是内存中的数据结构存储系统,处理速度快,性能好
- 提供队列,集合多种存储结构,方便队列维护
- Request去重(使用Redis集合)
- Redis提供集合数据结构,在Redis集合中存储每个Requests的指纹(id)
- 在向Request队列中加入Request前首先验证这个Request的指纹是否已经加入到集合中,如果不存在,则将Request添加入队列并将指纹加入集合
- 防止中断
- 在每台从机Scrapy启动时都会首先判断当前Redis Requets队列是否为空
- 如果不为空,则从队列中取得下一个Request执行爬取
- 如果为空,则重新开始爬取,第一台从机执行爬取向队列中添加Request
- Scrapy-Redis
- Scrapy-Redis库实现了分布式架构,改写了Scrapy的调度器,队列等组件。利用它可以方便地实现Scrapy分布式架构