(scrapy_redis框架源码: https://github.com/rmax/scrapy-redis)
1 概念原理
scrapy-redis是一个基于redis的分布式爬虫框架,用于在爬取大量请求数据的情况下,单个主机的处理能力不足问题.(可以解决单个机子的带宽限制,运行速度限制,以及分布式的节点出现问题,解决后可以再次启动,继续爬取)
其大概原理是通过redis对爬取的请求进行存储和调度,对爬取产生的数据(items)存储(供后续处理使用,如保存到MySQL中),以实现数据对多爬取节点的共享.(scrapy框架的队列是保存在内存中的,无法被其他爬取节点使用)
scrapy-redis对scrapy其中一些组件做了重建,主要为队列,调度,url去重三个组件,还添加保存数据到redis的管道文件.scrapy-redis的行流程:
2 安装
环境配置:
python
scrapy框架
redis数据库
redis --python操作redis模块 安装方法:pip install redis
安装scrapy-redis:
pip install scrapy-redis
3 实例运行
本次实例是scrapy_redis源码包中example-project,首先确保redis数据库已正常运行
a.修改settings.py文件
#coding:utf8
# Scrapy settings for example project
#
# For simplicity, this file contains only the most important settings by
# default. All the other settings are documented here:
#
# http://doc.scrapy.org/topics/settings.html
#
SPIDER_MODULES = ['example.spiders']
NEWSPIDER_MODULE = 'example.spiders'
USER_AGENT = 'scrapy-redis (+
#使用scrapy_redis框架url去重组件
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#使用scrapy_redis框架调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#调度器是否可以暂停
SCHEDULER_PERSIST = True
#使用scrapy_redis框架的队列
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"
#使用scrapy_redis管道
ITEM_PIPELINES = {
'example.pipelines.ExamplePipeline': 300,
'scrapy_redis.pipelines.RedisPipeline': 400,#使item数据保存redis上的管道文件
}
LOG_LEVEL = 'DEBUG'
# Introduce an artifical delay to make use of parallelism. to speed up the
# crawl.
DOWNLOAD_DELAY = 1
# redis服务器的 ip地址和端口号
REDIS_HOST = '192.168.10.128'
REDIS_PORT = 6379
# 或者可以使用下面这种方式
# 定义redis连接信息,如果定义redis_url 则redis_host 不生效
# REDIS_URL = 'redis://:123@192.168.10.128/2' # 最后2 是指定数据库索引
CONCURRENT_ITEMS = 100
CONCURRENT_REQUEST = 16
#每个域名同时并发的数量
CONCURRENT_REQUEST_PER_DOMAIN = 64
b.修改items.py文件
items.py加入:
class HaoItem(Item):
title = Field()
url = Field()
crawled = Field() #这是实例中已定义的第一个管道中需要用到
spider = Field() #这是实例中已定义的第一个管道中需要用到
c.修改spider文件下的dmoz文件:
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from example.items import HaoItem
class DmozSpider(CrawlSpider):
"""Follow categories and extract links."""
name = 'hao123'
#allowed_domains = ['dmoz.org']
start_urls = ['http://www.hao123.org/']
rules = [
Rule(LinkExtractor(
restrict_css=()
), callback='parse_directory', follow=False),
]
def parse_directory(self, response):
hao = HaoItem()
title = response.xpath('//title/text()').extract()[0]
url = response.url
hao['title'] = title
hao['url'] = url
yield hao
d.建立main文件运行spider,然后查看数据库,数据库中的数据会不断发生变化
4 将scrapy单机修改成scrapy-redis分布式
一般的话是先使用scrapy进行爬取测试,然后改成scrapy-redis分布式
a. 修改setting.py文件
redis的连接信息,调度器,队列,去重,管道 五部分
b. 修改爬虫文件中的继承
from scrapy_redis.spiders import RedisSpider,--spider #相对应对应的类
from scrapy_redis.spiders import RedisCrawlSpider,--crawlspider #相对应对应的类
设置redis_key="键" 例如:redis_key = 'liepin:start_url' #相当于start_url,项目
启动时,需要向redis数据库中导入此键以及对应的值
c. 启动所有slave(爬虫终端)
d. 向redis中push数据
e. 持久化,把提取到数据从redis中提取出来,存储到mysql等数据库中
例如:
#coding:utf8
import json
import redis
import MySQLdb
def main():
# 指定redis数据库信息
try:
print '正在连接redis'
rediscli = redis.StrictRedis(host='192.168.2.218', port=6379, db=5)
print 'redis连接成功'
# 指定mysql数据库
print '正在连接mysql'
mysqlcli = MySQLdb.connect('192.168.2.180', 'root', '123456', 'spider', charset='utf8')
# mysqlcli = MySQLdb.connect('192.168.2.218', 'centos4', '123456', 'spider', charset='utf8')
print 'mysql连接成功'
except Exception,e:
print '数据库连接失败'
print str(e)
exit()
while True:
source, data = rediscli.blpop(["lie_pin:items"])
# print source # redis里的键
# print data # 返回的数据
item = json.loads(data)
try:
# 使用cursor()方法获取操作游标
cur = mysqlcli.cursor()
# 使用execute方法执行SQL INSERT语句
sql = '''insert into job values(null,"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s")on duplicate key update ''' \
'''area=values(area),salary=values(salary),exp=values(exp),edu=values(edu),num=values(num),time=values(time),otherq=values(otherq),welfare=values(welfare)''' \
''',info=values(info),local=values(local),co_url=values(co_url),co_type=values(co_type)''' % \
(item['name'], item['co_name'], item['area'], item['salary'],item['exp'],item['edu'], item['num'], item['time'],
item['otherq'],item['welfare'],item['info'], item['local'], item['co_url'], item['co_type'],'liepin')
cur.execute(sql)
# 提交sql事务
mysqlcli.commit()
#关闭本次操作
cur.close()
print "inserted %s" % item['name']
except Exception,e:
print '插入失败'
print str(e)
if __name__ == '__main__':
main()
转载于:https://blog.51cto.com/linqi/1974856