分布式爬虫与增量式爬虫
-
增加并发
默认scrapy开启时并发线程为32个,可以适当的增加
-
降低日志级别
在运行scrapy时,会有大量的日志信息输出,为了减少CPU的使用路,可以设置log的输出信息为error即可
LOG_LEVEL="ERROR"
-
禁止cookie
如果不是真的需要cookie,则在scrapy的使用时可以禁止cookie,从而减少CPU的使用率,提升爬取效率
COOKIES_ENABLED=False
-
禁止重试
对失败的HTTP重新请求,会减慢爬取速度,因此可以禁止重试
RETRY_ENABLED=False
-
减少下载超时
如果对一个非常慢的链接进行爬取,减少下载超时可以让卡住的链接快速被放弃,从而提升小效率
DOWNLOAD_ENABLED=10
二.Crawlspider
创建基于Crawlspider 的爬虫文件
scrapy genspider -t crawl chouti www.xxx.com
作用1:能够在页面中查找指定url,并去重,解析
实例一:糗百爬取
在爬虫文件中
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from choutipro.items import ChoutiproItem
item=ChoutiproItem()
#注:继承的父类不再试Spider类,是CrawlSpider
class ChoutiSpider(CrawlSpider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
#1.链接提取器,allow表示的是链接提取器提取链接的规则
link=LinkExtractor(allow=r'/text/page/\d+/')
link1=LinkExtractor(allow=r'/text/$')
rules = (
#2.规则解析器:将链接提取器所对应的页面数据进行指定形式的解析
Rule(link, callback='parse_item', follow=False),
Rule(link1, callback='parse_item', follow=False),
)
def parse_item(self, response):
item = {}
div_list=response.xpath('//*[@id="content-left"]/div')
for div in div_list:
content=div.xpath('./a/div/span/text()').extract_first()
item["content"]=content
yield item
return item
在items.py中
import scrapy
class ChoutiproItem(scrapy.Item):
# define the fields for your item here like:
content = scrapy.Field()
pass
在管道文件中
class ChoutiproPipeline(object):
f=None
def open_spider(self,spider):
print("开始爬虫!")
self.f= open('./qiubai.txt','w',encoding='utf-8')
def process_item(self, item, spider):
self.f.write(item['content']+"\n")
return item
def close_spider(self,spider):
print("结束爬虫!")
self.f.close()
案例二:所有链接
作用2:能够在页面中递归查找指定url,并去重,解析
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from choutipro.items import ChoutiproItem
item=ChoutiproItem()
#注:继承的父类不再试Spider类,是CrawlSpider
class ChoutiSpider(CrawlSpider):
name = 'qiubai'
# allowed_domains = ['www.xxx.com']
start_urls = ['https://www.qiushibaike.com/text/']
#1.链接提取器,allow表示的是链接提取器提取链接的规则
link=LinkExtractor(allow=r'/text/page/\d+/')
link1=LinkExtractor(allow=r'/text/$')
rules = (
#2.规则解析器:将链接提取器所对应的页面数据进行指定形式的解析
Rule(link, callback='parse_item', follow=True),
Rule(link1, callback='parse_item', follow=True),
)
#follow=True代表将链接提取器继续作用到链接提取器提取到的链接所对应的页面
def parse_item(self, response):
item = {}
div_list=response.xpath('//*[@id="content-left"]/div')
for div in div_list:
content=div.xpath('./a/div/span/text()').extract_first()
item["content"]=content
yield item
return item
三.分布式爬虫(多台机器)
1.为什么原生scrapy不能实现分布式
-
调度器不能被共享
-
管道无法共享
2.scrapy-redis组件的作用
提供了可以被共享的调度器和管道
3.分布式爬虫流程
1.环境安装:pip3 install scrapy-redis
2.创建工程:
scrapy startproject redischoutipro
cd redischoutipro
3.创建爬虫文件,基于RedisCrawlSpider
scrapy genspider -t crawl chouti www.xxx.com
4.对爬虫文件中的相关属性进行修改
(1)导包:
from scrapy_redis.spiders import RedisCrawlSpider
(2)将当前爬虫文件的父类改成RedisCrawlSpider
(3)注释掉allowed_domains和start_urls,因为不需要其实url,因为分布式爬虫的多台机器中的代码时一样的,在一台机器上扔出一个起始url,哪台机器抢到哪台机器就对起始页面发送请求
(4)将起始url替换成url_key,表示调度器队列的名称:
redis_key = 'chouti'
5.编写爬虫文件,items文件
6.在配置文件中进行配置
(1)使用组件中封装好的可以被共享的管道类:
ITEM_PIPELINES={
'scrapy_redis.piplines.RedisPiplines':400
}
(2)配置调度器,使用组建中封装好的可以被共享的调度器
DUPEFILTER_CLASS='scrapy_redis.dupefilter.RFPDupeFilter'
SCHEDULER='scrapy_redis.scheduler.Scheduler'
SCHEDULER_PERSIST= True
指定存储数据的redis
REDIS_HOST='127.0.0.1'
REDIS_PORT=6379
修改ua,robots协议
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36'
ROBOTSTXT_OBEY = False
7.启动redis,redis也需要配置
在配置文件中取消保护模式
protected-mode no
bing绑定取消
#bing 127.0.0.1
重新启动启动redis,让配置文件生效
redis-cli
6.执行分布式程序(一定要在该目录下)
scrapy runspider chouti.py
7.向调度器队列中扔入起始url
在redis-cli中执行:
lpush chouti https://dig.chouti.com/all/hot/recent/1
8.查看redis中是否爬到了数据
keys *
lrange chouti:items0 -1
爬虫文件
# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from redischoutipro.items import RedischoutiproItem
#1.导包
from scrapy_redis.spiders import RedisCrawlSpider
item=RedischoutiproItem()
class ChoutiSpider(RedisCrawlSpider):
name = 'chouti'
# allowed_domains = ['www.xxx.com']
# start_urls = ['http://www.xxx.com/']
redis_key = 'chouti' #表示调度器队列的名称
rules = (
Rule(LinkExtractor(allow=r'/all/hot/recent/\d+'), callback='parse_item', follow=True),
)
def parse_item(self, response):
div_list=response.xpath('//div[@class="item"]')
for div in div_list:
content=div.xpath('./div[4]/div[1]/a/text()').extract_first()
name=div.xpath('./div[4]/div[2]/a[4]/b/text()').extract_first()
print(name)
print(1111111111111)
print(content)
item["name"]=name
item["content"]=content
yield item #这样提交到的是原生scrapy的管道当中
#item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
#item['name'] = response.xpath('//div[@id="name"]').get()
#item['description'] = response.xpath('//div[@id="description"]').get()
return item
items.py
import scrapy
class RedischoutiproItem(scrapy.Item):
# define the fields for your item here like:
name = scrapy.Field()
content = scrapy.Field()
pass
配置文件
#管道类
ITEM_PIPELINES={
'scrapy_redis.pipelines.RedisPipeline':400
}
#调度器的配置
#去重容器的配置
DUPEFILTER_CLASS='scrapy_redis.dupefilter.RFPDupeFilter'
#组件自己的调度器
SCHEDULER='scrapy_redis.scheduler.Scheduler'
#调度器的配置是否持久化(爬虫结束是要不要清除redis请求队列和去重指纹的set)
SCHEDULER_PERSIST= True
#redis配置
REDIS_HOST='127.0.0.1'
REDIS_PORT=6379
四.增量式爬虫(只爬取最新的数据)
概念:通过爬虫程序检测网站数据的更新的情况,以便可以爬取到更新出的新数据
方式一:对url去重
对数据取哈希值,用哈希值判断是否重复(自己制定了一种形式的数据指纹)
注:redis2.10.6的版本以前才可以存字典
车牌多少,冒泡,快排,单例模式,http,进程线程协成,协成怎么实现,爬虫,运维
算法 整体回顾总结 博客整理
项目:
基于...实现的... :十分钟
基于...实现的...:十分钟
基于...实现的...:十分钟
基于...实现的...:十分钟
项目背:
看页面想
打断:反问
你考我这个
改变世界,改变自己!