Day 45 爬虫_scrapy框架_CrawlSpider的全站数据
CrawlSpider的全站数据
CrawlSpider:类,Spider的一个子类
全站数据爬去的方式
1、基于Spider:手动请求
2、基于CrawlSpider
CrawlSpider的使用:
1、创建工程:scrapy startproject XXX
2、cd XXX
3、创建爬虫文件(CrawlSpider)
创建项目:scrapy genspider -t crawl xxx www.xxx.com
链接提取器:根据指定的规则(allow)进行指定连接的提取
规则解析器:将谅解提取到的链接进行指定规则(callback)的解析
需求:爬取 sun 网站中的编号,新闻标题,新闻内容,编号
分析:爬取的数据没有在同一张页面中
1、可以使用链接提取器提取所有的页码链接
2、让联机提取器提取所有的新闻详情页的链接
代码示例:
baiduPro.py
from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from baidu.items import BaiduItem,BaiduItem_detail class BaiduproSpider(CrawlSpider): name = 'baiduPro' # allowed_domains = ['https://www.baidu.com/s?wd=wangyi'] start_urls = ['http://wz.sun0769.com/political/index/politicsNewest'] # 连接提取器:根据指定的(allow=“正则”)进行指定连接的提取 Link = LinkExtractor(allow=r'id=\d+&page=\d+') Link_detail = LinkExtractor(allow=r'/political/politics/index\?id=\d+') rules = ( # 规则解析器:将连接提取器提取到的链接进行指定规则(callback)的解析操作 # follow=True:可以将链接提取器 继续作用到 连接提取器提取到的链接 所对应的页面中 Rule(Link, callback='parse_item', follow=False), Rule(Link_detail, callback='detail_item') ) # 以下两个解析方法无法实现请求传参,因为没有使用手动化请求 # 也就是说以下两部分内容无法存储到同一个 item 中,可以存储到两个 item 中 def parse_item(self, response): li_title = response.xpath('/html/body/div[2]/div[3]/ul[2]/li') for li in li_title: title_num = li.xpath('./span[@class="state1"]/text()').extract_first() title = li.xpath('.//a[@class="color-hover"]/text()').extract_first() item = BaiduItem() item['title_num'] = title_num item['title'] = title yield item def detail_item(self, response): print(response) detail_num = response.xpath('/html/body/div[3]/div[2]/div[2]/div[1]/span[4]/text()').extract_first() detail = response.xpath('/html/body/div[3]/div[2]/div[2]/div[2]/pre/text()').extract_first() detail_num = detail_num.split(':')[1] detail = ''.join(detail) item = BaiduItem_detail() item['detail_num'] = detail_num item['detail'] = detail yield item
items.py
import scrapy class BaiduItem(scrapy.Item): # define the fields for your item here like: title_num = scrapy.Field() title= scrapy.Field() class BaiduItem_detail(scrapy.Item): detail_num = scrapy.Field() detail = scrapy.Field()
pipelines.py
import pymysql class BaiduPipeline(object): def open_spider(self, spider): print('写入数据库。。。') self.conn = pymysql.Connect(host='192.168.214.23', port=3306, user='root', password='123456', db='srcapy', charset='utf8') def process_item(self, item, spider): # 如何判断 item 类型 # 将数据写入数据库时,如何保证数据的一致性 self.cursor = self.conn.cursor() if item.__class__.__name__ == 'BaiduItem': try: self.cursor.execute( 'insert into scr_sum(title_num,title) value ("%s","%s")' % (item['title_num'], item['title'])) self.conn.commit() except Exception as e: print(e) self.conn.rollback() pass elif item.__class__.__name__ == 'BaiduItem_detail': try: self.cursor.execute( 'update scr_sum set detail_num = "%s",detail = "%s" where title_num = "%s"' % ( item['detail_num'], item['detail'], item['detail_num'])) self.conn.commit() except Exception as e: print(e) self.conn.rollback() # print(type(item['detail']),item['detail']) return item def close_spider(self, spider): print('入库完成') self.cursor.close() self.conn.close()
settings.py
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36 OPR/67.0.3575.137 (Edition B2)' ROBOTSTXT_OBEY = False LOG_LEVEL = 'ERROR' ITEM_PIPELINES = { 'baidu.pipelines.BaiduPipeline': 300, }
分布式爬虫
概念:我们需要搭建一个分布式集群,让其对一组资源进行分布联合爬取
作用:提升爬取数据的效率
如何实现分布式
1、安装一个 scrapy-redis 的组件
2、原生的 scrapy 是不可以实现分布式爬虫,必须要让 scrapy 结合着scrapy-redis组件一起实现分布式爬虫
3、为什么原生的 scrapy 不可以实现分布式?
1、调度器不可以被分布式集群共享
2、管道你可以被分布式集群共享
scrapy-redis组件作用:可以给原生的 scrapy 框架提供可以被共享的管道和调度器
实现流程
1、创建一个工程:scrapy startproject fbs
2、创建一个基于 CrawlSpider 的爬虫文件:scrapy genspider -t crawl fbsPro www.xxx.com
3、修改当前爬虫文件
1、导包:from scrapy_redis.spiders import RedisCrawlSpider
2、将当前爬虫文件的父类修改为:RedisCrawlSpider
3、将 allowed_domains 与 start_urls 两行注释掉
4、添加一个新属性:redis_key = 'fbs' 可以被共享的调度器队列的名称
5、编写数据解析操作
4、修改配置文件 settins
# 指定使用可以被共享的管道 ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 } # 指定调度器 # 增加了一个去重容器类的配置, 作用使用Redis 的 set 集合来存储请求的指纹数据, 从而实现请求去重的持久化 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用 scrapy-redis 组件自己的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis 中请求队列和去重指纹的 set。如果是True, 就表示要持久化存储, 就不清空数据,否则清空数据 SCHEDULER_PERSIST = True
5、redis相关操作配置:
1、配置redis的配置文件:
linux或者mac:redis.conf
windows:redis.windows.conf
2、代开配置文件修改:
将bind 127.0.0.1进行删除
关闭保护模式:protected-mode yes改为no
3、结合着配置文件开启redis服务
redis-server 配置文件
4、启动客户端:redis-cli
6、执行工程:scrapy runspider xxx.py
7、向调度器的队列中放入一个起始的url:
调度器的队列在redis的客户端中:lpush xxx www.xxx.com
最后,爬取到的数据存储在了 redis 的 proName:items 这个数据结构中
增量式爬虫
概念:监测网站数据更新的情况,只会爬取网站最新更新出来的数据。
分析:
1、指定一个起始url
2、基于CrawlSpider获取其他页码链接
3、基于Rule将其他页码链接进行请求
4、从每一个页码对应的页面源码中解析出每一个电影详情页的URL
5、核心:检测电影详情页的url之前有没有请求过
将爬取过的电影详情页的url存储,存储到redis的set数据结构
6、对详情页的url发起请求,然后解析出电影的名称和简介
7、进行持久化存储