100、后端如何防爬虫、持久化 、全站爬取cnblogs、爬虫中间件和下载中间件、scrapy加代理 、scrapy、分布式爬虫

2023年 8月 17日 85.0k 0

今日内容概要

  • 后端如何防爬虫
  • 持久化
  • 全站爬取cnblogs
  • 爬虫中间件和下载中间件
  • scrapy加代理、cookie、header
  • scrapy集成selenium
  • 源码去重规则
  • 分布式爬虫
  • linux介绍

今日内容详细

后端如何防爬虫

1.频率限制(ip,用户)
2.尽量登录后才能访问
3.爬虫可以拿到cookie,token模拟发送请求
	3.1 请求头携带发送请求时间(时间戳)--->后端中间件中取出请求头中得时间戳,跟当前时间做比较,如果时间过长,就返回错误
	3.2 请求头中带sign签名--->签名自己的规则生成
			项目名+时间戳+项目名--->md5摘要
			后端:项目名+时间戳+项目名跟传入的sign比较,如果一样
	3.3 整个对请求体进行加密
			有的只加密了一部分;有的直接全部把请求体加密
			app端把请求体全加密---->拦截器取出请求体---->同样秘钥解密

持久化

爬回来,解析完了,想存储,有两种方案。一是使用命令保存到json文件或csv文件中;二是使用pipline存储,可以存储多个位置

1.方案一:(一般不用)parse必须有return值,必须是列表套字典形式--->使用命令,可以保存到json格式中,csv中
    scrapy crawl cnblogs -o cnbogs.json  #以json形式保存
    scrapy crawl cnblogs -o cnbogs.csv  #以csv形式保存
    
    
2.方案二: 我们用的,使用pipline存储--->可以存到多个位置
	1.第一步:在item.py中写一个类
    class CnblogsItem(scrapy.Item):
       title = scrapy.Field()
       url = scrapy.Field()
       desc = scrapy.Field()
       img = scrapy.Field()
       author = scrapy.Field()
       create_time = scrapy.Field()
       content = scrapy.Field()  # 文章详情,展示没有
            
	2.第二步:在pipline.py中写代码,写一个类:open_spide,close_spider,process_item
 		1.open_spide:开启爬虫会触发
 		2.close_spider:爬完会触发
		3.process_item:每次要保存一个对象会触发
        class FirstscrapyFilePipeline:
            def open_spider(self, spider):
                print('我开了')
                self.f=open('a.txt','w',encoding='utf-8')
            def close_spider(self, spider):
                print('我关了')
                self.f.close()
            # 这个很重要
            def process_item(self, item, spider):
                self.f.write(item['title']+'\n')
                return item
	3.第三步:配置文件配置
    	ITEM_PIPELINES = {
           "myfirstscrapy.pipelines.MyCnblogsPipeline": 300, # 数字越小,优先级越高
        }
        
	4.第四步:在解析方法parse中yield item对象

方案一

import scrapy

class CnblogsSpider(scrapy.Spider):
    name = "cnblogs"
    allowed_domains = ["www.cnblogs.com"]
    start_urls = ["https://www.cnblogs.com"]

    def parse(self, response):
        # print(response.text)  # http响应包装成了response
        # 需求:解析出所有文章(xpath选择器)
        # article.post-item
        arctile_list = response.xpath('//article[contains(@class,"post-item")]')  # 列表中放对象

        print(len(arctile_list))
        l=[]
        for article in arctile_list:
            # a.post - item - title::text
            title = article.xpath('.//a/text()').extract_first()
            print(title)
            # a.post-item-title::attr(href)
            url = article.xpath('.//a[contains(@class,"post-item-title")]/@href').extract_first()
            print(url)
            # p.post-item-summary::text
            desc = article.xpath('.//p[contains(@class,"post-item-summary")]/text()').extract()
            # print(desc)
            real_desc = desc[0].replace('\n','').replace(' ','')
            if real_desc:
                desc = real_desc
            else:
                desc = desc[1].replace('\n', '').replace(' ', '')
            print(desc)
            # img.avatar::attr(src)
            img = article.xpath('.//p//img/@src').extract_first()
            print(img)
            # a.post-item-author>span::text
            author = article.xpath('.//section/footer/a[1]/span/text()').extract_first()
            print(author)
            # span.post-meta-item>span::text
            create_time = article.xpath('.//section/footer/span[1]/span/text()').extract_first()
            print(create_time)
            l.append({
               'title':title,
                'url':url,
                'desc':desc,
                'img':img,
                'author':author,
                'create_time':create_time
            })
            print(f"""
            文章标题:{title}
            文章链接:{url}
            文章简介:{desc}
            作者头像:{img}
            作者昵称:{author}
            文章创建时间:{create_time}
            """)
        return l
      
"""
ps:在终端注解输入:scrapy crawl cnblogs -o cnbogs.json  或 scrapy crawl cnblogs -o cnbogs.csv  
"""

方案二

练习1

item.py

import scrapy
class CnblogsItem(scrapy.Item):
   title = scrapy.Field()
   url = scrapy.Field()
   desc = scrapy.Field()
   img = scrapy.Field()
   author = scrapy.Field()
   create_time = scrapy.Field()
   content = scrapy.Field()  # 文章详情,展示没有

pipline.py

class MyCnblogsPipeline:
    def open_spider(self,spider):  # 开启爬虫会触发
        print('-------我开了')
        # print(spider)  # 
        self.f = open('cnblogs.txt','wt',encoding='utf-8')
        
    def process_item(self,item,spider):  #每次要保存一个对象会触发
        print('-------我来了')
        # item 当前被处理到的在cnblogs.py的parser中yield item
        # 存文件
        self.f.write('标题:%s,地址:%s\n'%(item['title'],item['url']))
        return item  #如果不返回,后续的pipline就拿不到了

    def close_spider(self,spider):  # 爬完会触发
        print('我关了')
        self.f.close()

Settings.py

# 管道  数字表示优先级,数字越小,优先级越高
ITEM_PIPELINES = {
   "myfirstscrapy.pipelines.MyCnblogsPipeline": 300,
}

cnblogs.py

import scrapy
from myfirstscrapy.items import CnblogsItem


class CnblogsSpider(scrapy.Spider):
    name = "cnblogs"
    allowed_domains = ["www.cnblogs.com"]
    start_urls = ["https://www.cnblogs.com"]

    def parse(self, response):
        item = CnblogsItem()

        arctile_list = response.xpath('//article[contains(@class,"post-item")]')  # 列表中放对象

        print(len(arctile_list))
        for article in arctile_list:
            # a.post - item - title::text
            title = article.xpath('.//a/text()').extract_first()
            # print(title)
            # a.post-item-title::attr(href)
            url = article.xpath('.//a[contains(@class,"post-item-title")]/@href').extract_first()
            # print(url)
            # p.post-item-summary::text
            desc = article.xpath('.//p[contains(@class,"post-item-summary")]/text()').extract()
            # print(desc)
            real_desc = desc[0].replace('\n','').replace(' ','')
            if real_desc:
                desc = real_desc
            else:
                desc = desc[1].replace('\n', '').replace(' ', '')
            # print(desc)
            # img.avatar::attr(src)
            img = article.xpath('.//p//img/@src').extract_first()
            # print(img)
            # a.post-item-author>span::text
            author = article.xpath('.//section/footer/a[1]/span/text()').extract_first()
            # print(author)
            # span.post-meta-item>span::text
            create_time = article.xpath('.//section/footer/span[1]/span/text()').extract_first()
            # print(create_time)

            item['title'] = title
            item['url'] = url
            item['desc'] = desc
            item['img'] = img
            item['author'] = author
            item['create_time'] = create_time
            yield item

全站爬取cnblogs

1.需求:继续爬取下一页并且爬取文章详情

1.步骤:
	1.Request创建:在parse中的for循环中,创建Request对象时,传入meta
  	yield Request(url=url, callback=self.detail_parse,meta={'item':item})
		ps:item对象一定要在for循环中创建,否则,当前页面都用同一个item导致同一页数据都一样
	
	2.在parser_detail中取出来
		item=response.meta.get('item')
		Response对象:detail_parse中,通过response取出meta取出item,把文章详情写入
    
    
    def parser_detail(self,response):
          # content = response.css('#cnblogs_post_body').extract_first()
          item=response.meta.get('item')
          content=str(response.xpath('//div[@id="cnblogs_post_body"]').extract_first())
          item['content']=content
          yield item

cnblogs.py

import scrapy
from myfirstscrapy.items import CnblogsItem
from scrapy.http.request import Request


class CnblogsSpider(scrapy.Spider):
    name = "cnblogs"
    allowed_domains = ["www.cnblogs.com"]
    start_urls = ["https://www.cnblogs.com"]

    def parse(self, response):
        # item = CnblogsItem()   # #会有问题,是个引用类型

        arctile_list = response.xpath('//article[contains(@class,"post-item")]')  # 列表中放对象

        print(len(arctile_list))
        for article in arctile_list:
            item = CnblogsItem()
            title = article.xpath('.//a/text()').extract_first()
            url = article.xpath('.//a[contains(@class,"post-item-title")]/@href').extract_first()
            desc = article.xpath('.//p[contains(@class,"post-item-summary")]/text()').extract()
            real_desc = desc[0].replace('\n','').replace(' ','')
            if real_desc:
                desc = real_desc
            else:
                desc = desc[1].replace('\n', '').replace(' ', '')
            img = article.xpath('.//p//img/@src').extract_first()
            author = article.xpath('.//section/footer/a[1]/span/text()').extract_first()
            create_time = article.xpath('.//section/footer/span[1]/span/text()').extract_first()
            item['title'] = title
            item['url'] = url
            item['desc'] = desc
            item['img'] = img
            item['author'] = author
            item['create_time'] = create_time
            # yield item
            yield Request(url = url,callback=self.parse_detail,meta={'item':item})  # # 详情地址,继续爬取,详情页面解析用parser_detail

        # 解析出下一页地址,然后yield一个对象;请求对象:解析出要爬去的地址
        next = "https://www.cnblogs.com" +response.css('#paging_block > div > a:last-child::attr(href)').extract_first()
        print(next)  # 拿到地址,继续爬取,组装成一个Request对象
        yield Request(url=next, callback=self.parse)  # 下一页地址,继续爬取,解析还是用parse


    def parse_detail(self,response):
        content = str(response.css('#cnblogs_post_body').extract_first())
        # content=response.xpath('//*[@id="cnblogs_post_body"]').extract_first()
        item = response.meta.get('item')
        item['content']=content
        yield item

items.py

import scrapy


class CnblogsItem(scrapy.Item):

   title = scrapy.Field()
   url = scrapy.Field()
   desc = scrapy.Field()
   img = scrapy.Field()
   author = scrapy.Field()
   create_time = scrapy.Field()
   content = scrapy.Field()  # 文章详情,展示没有

pipelines.py

class MyCnblogsMysqlPipline:
    def open_spider(self,spider):  # 开启爬虫会触发
        self.count = 0
        print('-------我开了')
        self.conn=pymysql.connect(
        user="root",
        password="ln1998151125",
        host='127.0.0.1',
        database="cnblogs",
        port=3306,
        )
        self.cursor=self.conn.cursor()

    def process_item(self,item,spider):  #每次要保存一个对象会触发
        print('-------我来了========')
        self.count +=1
        print(self.count)
        # item 当前被处理到的在cnblogs.py的parser中yield item
        # 存文件
        sql = 'insert into test (title,url,`desc`,img,author,create_time,content) values (%s,%s,%s,%s,%s,%s,%s)'
        self.cursor.execute(sql,args=[item['title'],item['url'],item['desc'],item['img'],item['author'],item['create_time'],item['content']])
        self.conn.commit()
        return item
    def close_spider(self,spider):  # 爬完会触发
        print('我关了')
        self.cursor.close()
        self.conn.close()

Settings.py

# 管道  数字表示优先级,数字越小,优先级越高
ITEM_PIPELINES = {
   "myfirstscrapy.pipelines.MyCnblogsPipeline": 300,
   "myfirstscrapy.pipelines.MyCnblogsMysqlPipline": 301,
}

爬虫中间件和下载中间件

 

1.爬虫中间件:爬虫和引擎之间
	用的很少,了解即可

2.下载中间件:引擎和下载器之间
	用的多,能干啥?
	进来request对象
    加代理
    加cookie
    加请求头
    出去response对象:修改响应对象,最后进入到爬虫的parser中就是修改后的response
        
        
        
3.爬虫中间件 (了解) middlewares.py
class MysfirstscrapySpiderMiddleware:

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_spider_input(self, response, spider):
        return None

    def process_spider_output(self, response, result, spider):
        for i in result:
            yield i

    def process_spider_exception(self, response, exception, spider):

        pass

    def process_start_requests(self, start_requests, spider):

        for r in start_requests:
            yield r

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)


# 下载中间件
class MysfirstscrapyDownloaderMiddleware:

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    # 请求来了执行
    def process_request(self, request, spider):
     	 print(request.url)
				"""
				返回值可以是如下:
        return None:继续处理本次请求,执行执行下一个中间件的process_request
        return Response:执行当前中间件的process_response回去,进入到引擎,被调度,进入第6步,返回到爬虫的解析方法中
        return a Request:直接返回,给引擎,被调度,进入第2步,进入调度器等待下次被调度爬取
        raise IgnoreRequest:执行 process_exception
				
				"""
        return None

    # 请求走了
    def process_response(self, request, response, spider):
				"""
				返回如下:
        return Response :继续往后走,进入到引擎,被调度到爬虫中解析
        return Request :进入到引擎,被调度进调度器
         - or raise IgnoreRequest:会执行process_exception
				"""
        return response

    def process_exception(self, request, exception, spider):
 
        pass

    def spider_opened(self, spider):
        spider.logger.info('Spider opened: %s' % spider.name)

        
4.在配置文件中配置
# 下载中间件
DOWNLOADER_MIDDLEWARES = {
   "myfirstscrapy.middlewares.MyfirstscrapyDownloaderMiddleware": 543,
}

scrapy加代理,cookie,header

加代理

1.在下载中间件的def process_request(self, request, spider)中写代码
	1.第一步:
		-在下载中间件写process_request方法
   	 def get_proxy(self):
        import requests
        res = requests.get('http://127.0.0.1:5010/get/').json()
        if res.get('https'):
            return 'https://' + res.get('proxy')
        else:
            return 'http://' + res.get('proxy')
     def process_request(self, request, spider):
            request.meta['proxy'] = self.get_proxy()
            return None
        
	2.第二步:代理可能不能用,会触发process_exception,在里面写
    def process_exception(self, request, exception, spider):
        print('-----',request.url)  # 这个地址没有爬
        return request

加cookie

def process_request(self, request, spider):
    print(request.cookies)
    request.cookies['name']='lqz'
    return None

修改请求头

加cookie

def process_request(self, request, spider):
        print(request.cookies)
        request.cookies['name']='na'
        return None

修改请求头

# 动态生成User-agent使用
    def process_request(self, request, spider):
        # fake_useragent模块
        from fake_useragent import UserAgent
        ua = UserAgent()
        request.headers['User-Agent']=str(ua.random)
        print(request.headers)
        return None

scrapy集成selenium

1.使用scrapy默认下载器--->类似于requests模块发送请求,不能执行js,有的页面拿回来数据不完整

2.想在scrapy中集成selenium,获取数据更完整,获取完后,自己组装成 Response对象,就会进爬虫解析,现在解析的是使用selenium拿回来的页面,数据更完整

3.集成selenium 因为有的页面,是执行完js后才渲染完,必须使用selenium去爬取数据才完整

4.注意:
	保证整个爬虫中,只有一个浏览器器
	只要爬取 下一页这种地址-->使用selenium;爬取详情--->继续使用原来的

步骤

1.第一步:在爬虫类中写
  from selenium import webdriver
  class CnblogsSpider(scrapy.Spider):
      bro = webdriver.Chrome(executable_path='./chromedriver.exe')
      bro.implicitly_wait(10)
      def close(spider, reason):
          spider.bro.close() #浏览器关掉
        
2.第二步:在中间件中
    def process_request(self, request, spider):
        # 爬取下一页这种地址--->用selenium,但是文章详情,就用原来的
        if 'sitehome/p' in request.url:
            spider.bro.get(request.url)
            from scrapy.http.response.html import HtmlResponse
            response = HtmlResponse(url=request.url, body=bytes(spider.bro.page_source, encoding='utf-8'))
            return response
        else:
            return None

源码去重规则(布隆过滤器)

1.源码去重规则:如果爬取过的地址,就不会再爬了
2.调度器可以去重----->使用了集合
	要爬取的Request对象,在进入到scheduler调度器排队之前,先执行enqueue_request,它如果return False,这个Request就丢弃掉,不爬了
  如何判断这个Request要不要丢弃掉,执行了self.df.request_seen(request),它来决定的----->RFPDupeFilter类中的方法---->request_seen--->会返回True或False---->如果这个request在集合中,说明爬过了,就return True,如果不在集合中,就加入到集合中,然后返回False

3.调度器源码
  from scrapy.core.scheduler import Scheduler
    # 这个方法如果return True表示这个request要爬取,如果return False表示这个网址就不爬了(已经爬过了)
      def enqueue_request(self, request: Request) -> bool:
          # request当次要爬取的地址对象
          if self.df.request_seen(request):
              # 有的请情况,在爬虫中解析出来的网址,不想爬了,就就可以指定
              # yield Request(url=url, callback=self.detail_parse, meta={'item': item},dont_filter=True)
              # 如果符合这个条件,表示这个网址已经爬过了 
              return False
          return True
    
    
    
  # self.df 去重类 是去重类的对象 RFPDupeFilter
      -在配置文件中如果配置了:DUPEFILTER_CLASS = 'scrapy.dupefilters.RFPDupeFilter'表示,使用它作为去重类,按照它的规则做去重
      -RFPDupeFilter的request_seen
         def request_seen(self, request: Request) -> bool:
          # request_fingerprint 生成指纹
          fp = self.request_fingerprint(request) #request当次要爬取的地址对象
          #判断 fp 在不在集合中,如果在,return True
          if fp in self.fingerprints:
              return True
          #如果不在,加入到集合,return False
          self.fingerprints.add(fp)
          return False

    
  # 传进来是个request对象,生成的是指纹
    -爬取的网址:https://www.cnblogs.com/teach/p/17238610.html?name=lqz&age=19
      -和         https://www.cnblogs.com/teach/p/17238610.html?age=19&name=lqz
      -它俩是一样的,返回的数据都是一样的,就应该是一条url,就只会爬取一次
      -所以 request_fingerprint  就是来把它们做成一样的(核心原理是把查询条件排序,再拼接到后面)
    
   
4.生成指纹,指纹是什么? 生成的指纹放到集合中去重
	www.cnblogs.com?name=lqz&age=19
	www.cnblogs.com?age=19&name=lqz
	上面的两种地址生成的指纹是一样的
  
  # 测试指纹
  from scrapy.utils.request import RequestFingerprinter
  from scrapy import Request

  fingerprinter = RequestFingerprinter()
  request1 = Request(url='http://www.cnblogs.com?name=lqz&age=20')
  request2 = Request(url='http://www.cnblogs.com?age=20&name=lqz')

  res1 = fingerprinter.fingerprint(request1).hex()
  res2 = fingerprinter.fingerprint(request2).hex()
  print(res1)
  print(res2)
        
        
5.集合去重,集合中放 
  # a一个bytes
  # 假设爬了1亿条url,放在内存中,占空间非常大
  a6af0a0ffa18a9b2432550e1914361b6bffcff1a
  a6af0a0ffa18a9b2432550e191361b6bffc34f1a

6.想一种方式,极小内存实现去重--->布隆过滤器

总结:scrapy的去重规则

1.根据配置的去重类RFPDupeFilter的request_seen方法,如果返回True,就不爬了,如果返回False就爬
	后期咱们可以使用自己定义的去重类,实现去重
    
    
2.更小内存实现去重
	-如果是集合:存的数据库越多,占内存空间越大,如果数据量特别大,可以使用布隆过滤器实现去重

3.布隆过滤器:https://zhuanlan.zhihu.com/p/94668361
	bloomfilter:是一个通过多哈希函数映射到一张表的数据结构,能够快速的判断一个元素在一个集合内是否存在,具有很好的空间和时间效率。(典型例子,爬虫url去重)
  原理: BloomFilter 会开辟一个m位的bitArray(位数组),开始所有数据全部置 0 。当一个元素(www.baidu.com)过来时,能过多个哈希函数(h1,h2,h3....)计算不同的在哈希值,并通过哈希值找到对应的bitArray下标处,将里面的值 0 置为 1 。

    
4.Python中使用布隆过滤器
	测试布隆过滤器,可以自动扩容指定错误率,底层数组如果大于了错误率会自动扩容
  
  from pybloom_live import ScalableBloomFilter
  bloom = ScalableBloomFilter(initial_capacity=100, error_rate=0.001, mode=ScalableBloomFilter.LARGE_SET_GROWTH)
  url = "www.cnblogs.com"
  url2 = "www.liuqingzheng.top"
  bloom.add(url)
  bloom.add(url2)
  print(url in bloom)
  print(url2 in bloom)

  from pybloom_live import BloomFilter
  bf = BloomFilter(capacity=10)
  url = 'www.baidu.com'
  bf.add(url)
  bf.add('aaaa')
  bf.add('ggg')
  bf.add('deww')
  bf.add('aerqaaa')
  bf.add('ae2rqaaa')
  bf.add('aerweqaaa')
  bf.add('aerwewqaaa')
  bf.add('aerereweqaaa')
  bf.add('we')

  print(url in bf)
  print("wa" in bf)



5.如果有去重的情况,就可以使用集合--->但是集合占的内存空间大,如果到了亿级别的数据量,想一种更小内存占用,而去重的方案----?布隆过滤器
	布隆过滤器:通过不同的hash函数,加底层数组实现的极小内存去重
	python中如何使用:pybloom_live  
		-指定错误率
    -指定大小

   
6.使用redis实现布隆过滤器
	-编译redis--->把第三方扩展布隆过滤器编译进去,才有这个功能
	-https://zhuanlan.zhihu.com/p/94668736

7.重写scrapy的过滤类

分布式爬虫

1.原来scrapy的Scheduler维护的是本机的任务队列(待爬取的地址)+本机的去重队列(放在集合中)--->在本机内存中
2.如果把scrapy项目,部署到多台机器上,多台机器爬取的内容是重复的
	所以实现分布式爬取的关键就是,找一台专门的主机上运行一个共享的队列比如Redis,
然后重写Scrapy的Scheduler,让新的Scheduler到共享队列存取Request,并且去除重复的Request请求,所以总结下来,实现分布式的关键就是三点:
 	1.多台机器共享队列
  2.重写Scheduler,让其无论是去重还是任务都去访问共享队列
  3.为Scheduler定制去重规则(利用redis的集合类型)
    
3.scrapy-redis实现分布式爬虫
	公共的去重
  公共的待爬取地址队列
    
    
4.使用步骤
	1.把之前爬虫类,继承class CnblogsSpider(RedisSpider):
	2.去掉起始爬取的地址,加入一个类属性
    	class CnblogsSpider(RedisSpider):
          name = "cnblogs"
          allowed_domains = ["www.cnblogs.com"] # 允许爬取的域
          # 去掉起始爬取的地址--->起始爬取的地方,统一放到redis中了
          # 3 设置一个类属性 redis_key,随便起名字
          redis_key = 'myspider:start_urls'  # redis列表的key,后期我们需要手动插入起始地址
        
	3.配置文件中配置
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"  # scrapy redis去重类,使用redis的集合去重
    # 不使用原生的调度器了,使用scrapy_redis提供的调度器,它就是使用了redis的列表
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    REDIS_HOST = 'localhost'                            # 主机名
    REDIS_PORT = 6379                                   # 端口
    ITEM_PIPELINES = {
      # 'mysfirstscrapy.pipelines.MyCnblogsPipeline': 300,
      'mysfirstscrapy.pipelines.MyCnblogsMySqlPipeline': 301,
      'scrapy_redis.pipelines.RedisPipeline': 400,
    }
        
4.再不同多台机器上运行scrapy的爬虫,就实现了分布式爬虫

Linux介绍

文档:https://zhuanlan.zhihu.com/p/429509333


1. 什么是操作系统
Operating System(操作系统) 简称OS
Windows,MacOS,Linux都是操作系统


2.什么是BootLoader
在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境
一般在计算机启动的时候,选择启动Linux还是Windows的BootLoader是GRUB
如果没有选择,GRUB会在几秒后启动默认的操作系统
双操作系统启动流程如下图


3.Linux和Windows的软件
windows系统下的软件,不能在Linux上运行,Linux上的软件不能在windows上运行
Linux上的软件,基本上都是免费的
Linux上软件,更新更频繁,且免费
Linux上软件,效率更高


4.操作系统发展
  # 1984年,微软发布了第一个操作系统-->MS-DOS
    -1980年,西雅图电脑产品公司(Seattle Computer Products)的一名24岁的程序员蒂姆·帕特森(Tim Paterson)花费了四个月时间编写出了86-DOS操作系统
    -在1981年7月27日,比尔盖茨完全获得了一个叫做Seattle Computer Systems(西雅图计算机系统公司)的“Quick and Dirty Operating System”,简称QDOS的授权,花费5w美元。后来该操作系统被称作MS-DOS


	# 同时代,1969年(1970年,计算机元年)起,也有一款比较出名的操作系统叫Unix
    -1968年 Multics项目
    -MIT、Bell实验室、美国通用电气有限公司走到了一起,致力于开发Multics项目。到后期由于开发进度不是很好,MIT和Bell实验室相继离开这个项目的开发,最终导致项目搁浅。
    -1970年(Unix元年,时间戳) Unix诞生
    -当时在开发Multics项目的时候,实验室中有一个开发成员开发了一款游戏(travel space:遨游太空),因为两个实验室相继离开项目开发,导致这名开发人员没法玩游戏,后来他提议组织人员重新在Multics项目之上重新的开发,也就出现了1970年的Unix。当时Unix操作系统是使用的汇编语言(机器语言)开发的。
    -1973年 用C语言重写Unix
    -因为汇编语言有一个最大的局限性:对于计算机硬件过于依赖。导致移植性不好,所以后期在1973年使用了C语言对其进行重新开发。
    -1975年 Bell实验室允许大学使用Unix。
    -1975年,bell实验室允许大学使用Unix操作系统用于教学作用,而不允许用于商业用途。

	# 在1984年,微软发布DOS的同时,理查德·马修·斯托曼(Richard Matthew Stallman, RMS)创立了GUN项目 
     -GNU项目 (牛羚),GNU is not Unix的缩写,目的是创建一个类Unix的操作系统,因为unix不是免费的,商业收费,刚开始学校教学免费使用,后来不免费了,价格比较贵(MacOS是类Unix操作系统)
   -理查德·马修·斯托曼:1953年出生,自由软件运动的精神领袖、GNU计划以及自由软件基金会(Free Software Foundation)的创立者、著名黑客,代表作:Emacs编辑器,GCC编译器,GDB调试器

	 # 自由的和免费的
    -自由的意味着源代码必须公开(windows和macos是私有的)
    -自由软件大部分是免费的,但是可以复制,修改,出售

	# 1991年 Linux的开发作者,Linux之父,李纳斯·托瓦兹。Linux诞生时是荷兰在校大学生。
    -1991年 0.0.1版本
    -李纳斯当时学校使用的就是Unix操作系统,然后其对系统的底层代码进行了修改,放到了学校为学生开放的网站上,原先他把文件命名写成了Linus’s Unix,后期网络管理发现之后觉得这个名字不好,自己手动的将名字改成Linux。随后其他同学下载之后发现这个版本还是挺好用的,随后都把自己代码贡献给李纳斯。
    -1992年 0.0.2版本
    -1994年 1.0版本
    -2003年 2.6版本
	# Linux吉祥物企鹅
    -李纳斯以前在澳大利亚被一只企鹅咬过
    
    
    
7.Linux和GNU的联系
    这两个项目是互补的,Linus其实就写了一个类Unix内核
    1991年GNU项目已经创建了不少操作系统外网软件,比如cp命令,rm命令,GCC,GDB等--》好比Linux就是人的骨骼,GUN就是血肉
    # 后来完善Linux的工作就由Linus和广大开源社区的黑客们
    # GNU项目+Linux内核=完整的操作系统,我们现在叫的Linux一般都是指GUN项目+Linux内核
    
    
8. Linux内核
上述所提及的版本号并不是分支版本,而是指Linux的内核版本。
Linux内核网站(现在最新5.x版本,3.x多一些,原来2.x多,现在docker要跑在3上)
https://www.kernel.org/


9.各个操作系统的关系
# MacOS和Linux是基于Unix的意思是复刻了Unix的运行模式,源代码是不通的
# 目前Windows的版本是基于革命性的Windows NT内核


10.Linux发行版和区别
# 因为Linux是开源自由软件,所以基于开源的代码可以定制属于自己的Linux系统,所以Linux的版本特别多

11.Linux不同发行版的区别(centos  乌班图 麒麟。。)
  -安装方式不一样,有的简单,有的复杂
  -安装应用程序的方式也不一样 (yum    apt-get)
  -预装的应用程序不一样 ()

12.不同发行版使用的Linux内核一样
    -我们现在说的Linux其实都是指的是发行版(Distribution version),就是使用Linux内核加上各种GNU的库文件、应用程序,构造而成的操作系统
    -可以想象成同一个人(Linux内核),穿不通的衣服裙子羽绒服(软件)

13.不同发行版有的免费,有的收费

  不同发行版
      -Red Hat:性能稳定,老牌的Linux发行版,RHEL收费,是red hat的企业版,源代码是开放的,收费是因为长期升级更新服务
    -现在Red Hat分两个系列:一个是red hat公司提供收费技术支持的RHEL,另一个是社区开放的免费版Fedora,每半年发行一次,由于发行频繁导致性能不太稳定,企业一般不选用Fedora
    -Centos:算是RHEL的克隆版,社区企业级操作系统, 改与Redhat, 完全开源,兼具社区和企业特性,融合了Fedora和redhat优点,长期支持,大规模使用稳定,企业普遍使用,特别适合做服务器
    -Deepin:深度,中国发行
    -Debian:迄今为止,最遵循GUN规范的Linux系统
    -Ubuntu :Debian一个后继或分支,社区维护, 现在主要做手机系统和电脑桌面系统。
  graph TD;

      Linux--> Debian
      Linux--> RedHat
      Linux--> Deepin深度

      RedHat--> RHEL
      RedHat--> CentOS
      RedHat--> Fedora

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论