《零基础入门学习Python》第055讲:论一只爬虫的自我修养3:隐藏

0. 请写下这一节课你学习到的内容:格式不限,回忆并复述是加强记忆的好方式!

上节课我们说过了,有一些网站比较痛恨爬虫程序,它们不喜欢被程序所访问,所以它们会检查链接的来源,如果说来源不是正常的途径,那么它就会把你给屏蔽掉,所以呢,要让我们的程序可以持续的干活,要可以投入生产,我们就需要对代码进行隐藏,让它看起来更像是普通人浏览器的正常点击。

我们知道,服务器检查链接是通过检查 链接中的 Headers 中的 User Agent 来判断你是来自于代码还是来自于浏览器,像我们的Python,你用Python默认的Headers 中的 User Agent 是Python 加上版本号,服务器一检查是Python,就会把你屏蔽掉。我们可以修改 Headers 来模拟正常的浏览器访问。

先看一下文档:

urllib.request.Request 有一个 headers 的参数,通过修改 headers 参数,你可以设置自己的 headers,这个参数是一个字典,你可以通过两种途径来设置:一种是你直接设置一个字典,然后作为参数传给 Request,或者第二种,在Request 生成之后,调用 add_header() 将其加进去。我们使用上节课的例子来尝试一下:

第一种 代码清单:

 
  1. #translation.py

  2. import urllib.request

  3. import urllib.parse

  4. import json

  5. print("---------这是一个Python翻译器---------")

  6. content = input('请输入需要翻译的内容:')

  7. url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule"

  8. #直接从审查元素中copy过来的url会报错,必须把translate_o中的_o 删除才可以

  9. #url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"

  10. head = {}

  11. head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'

  12. data = {} #这里就是把 Form Data 中的内容贴过来

  13. data['i'] = content

  14. data['from'] = 'AUTO'

  15. data['to'] = 'AUTO'

  16. data['smartresult'] = 'dict'

  17. data['client'] = 'fanyideskweb'

  18. data['salt'] = '15445124815349'

  19. data['sign'] = 'a824eba4c23c6f541ffadfee26b1e500'

  20. data['ts'] = '1544512481534'

  21. data['bv'] = 'bbb3ed55971873051bc2ff740579bb49'

  22. data['doctype'] = 'json'

  23. data['version'] = '2.1'

  24. data['keyfrom'] = 'fanyi.web'

  25. data['action'] = 'FY_BY_REALTIME'

  26. data['typoResult'] = 'false'

  27. #需要使用urllib.parse.urlencode() 把data转换为需要的形式

  28. data = urllib.parse.urlencode(data).encode('utf-8')

  29. req = urllib.request.Request(url, data, head)

  30. response = urllib.request.urlopen(url, data)

  31. html = response.read().decode('utf-8')

  32. target = json.loads(html)

  33. print('翻译结果:%s' %(target['translateResult'][0][0]['tgt']))

第二种 代码清单:

 
  1. #translation.py

  2. import urllib.request

  3. import urllib.parse

  4. import json

  5. print("---------这是一个Python翻译器---------")

  6. content = input('请输入需要翻译的内容:')

  7. url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule"

  8. #直接从审查元素中copy过来的url会报错,必须把translate_o中的_o 删除才可以

  9. #url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"

  10. #head = {}

  11. #head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'

  12. data = {} #这里就是把 Form Data 中的内容贴过来

  13. data['i'] = content

  14. data['from'] = 'AUTO'

  15. data['to'] = 'AUTO'

  16. data['smartresult'] = 'dict'

  17. data['client'] = 'fanyideskweb'

  18. data['salt'] = '15445124815349'

  19. data['sign'] = 'a824eba4c23c6f541ffadfee26b1e500'

  20. data['ts'] = '1544512481534'

  21. data['bv'] = 'bbb3ed55971873051bc2ff740579bb49'

  22. data['doctype'] = 'json'

  23. data['version'] = '2.1'

  24. data['keyfrom'] = 'fanyi.web'

  25. data['action'] = 'FY_BY_REALTIME'

  26. data['typoResult'] = 'false'

  27. #需要使用urllib.parse.urlencode() 把data转换为需要的形式

  28. data = urllib.parse.urlencode(data).encode('utf-8')

  29. req = urllib.request.Request(url, data)

  30. req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36')

  31. response = urllib.request.urlopen(url, data)

  32. html = response.read().decode('utf-8')

  33. target = json.loads(html)

  34. print('翻译结果:%s' %(target['translateResult'][0][0]['tgt']))

运行结果:

 
  1. =========== RESTART: C:\Users\XiangyangDai\Desktop\translation.py ===========

  2. ---------这是一个Python翻译器---------

  3. 请输入需要翻译的内容:爱

  4. 翻译结果:love

  5. >>> req.headers

  6. {'User-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

我们来回顾一下,修改 headers 有两个途径:

  • 通过 Request 的 headers 参数修改
  • 通过 Request.add_header() 方法修改

修改 User-Agent 可以算是最简单的隐藏方法了,也是切实可行的,不过呢,如果是用 Python 抓取网页,例如批量下载 图片,你一个 IP 地址短时间内连续的进行访问,那么这是不符合正常人类的标准的,而且对服务器带来的压力不小,所以服务器合情合理会把你屏蔽掉,屏蔽的做法也很简单,只需要记录每个IP的访问频率,在单位时间内,如果访问频率超过一个阈值,那么服务器就会认为这个IP很有可能是一个爬虫,那么服务器就会把不管它的User-Agent是什么了,服务器就会返回一个验证码的界面,因为用户会填写验证码,但是爬虫不会,这就会合理的把你的访问给屏蔽掉。

就我们目前的学习水平来说,有两种做法可以解决这种问题,一种就是延迟提交的时间,让我们的爬虫看起来更像是一个正常的人类在浏览(这是没有办法的办法);还有一种就是使用代理。

首先说第一种方法,我们可以使用 time 模块来完成延迟操作:(这种方法的工作效率太慢了

 
  1. #translation.py

  2. import urllib.request

  3. import urllib.parse

  4. import json

  5. import time

  6. print("---------这是一个Python翻译器---------")

  7. while True:

  8. content = input("请输入需要翻译的内容(输入'Q'退出程序):")

  9. if content == 'Q':

  10. break

  11. url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule"

  12. #直接从审查元素中copy过来的url会报错,必须把translate_o中的_o 删除才可以

  13. #url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"

  14. #head = {}

  15. #head['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'

  16. data = {} #这里就是把 Form Data 中的内容贴过来

  17. data['i'] = content

  18. data['from'] = 'AUTO'

  19. data['to'] = 'AUTO'

  20. data['smartresult'] = 'dict'

  21. data['client'] = 'fanyideskweb'

  22. data['salt'] = '15445124815349'

  23. data['sign'] = 'a824eba4c23c6f541ffadfee26b1e500'

  24. data['ts'] = '1544512481534'

  25. data['bv'] = 'bbb3ed55971873051bc2ff740579bb49'

  26. data['doctype'] = 'json'

  27. data['version'] = '2.1'

  28. data['keyfrom'] = 'fanyi.web'

  29. data['action'] = 'FY_BY_REALTIME'

  30. data['typoResult'] = 'false'

  31. #需要使用urllib.parse.urlencode() 把data转换为需要的形式

  32. data = urllib.parse.urlencode(data).encode('utf-8')

  33. req = urllib.request.Request(url, data)

  34. req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36')

  35. response = urllib.request.urlopen(url, data)

  36. html = response.read().decode('utf-8')

  37. target = json.loads(html)

  38. print('翻译结果:%s' %(target['translateResult'][0][0]['tgt']))

  39. time.sleep(5) #暂停5秒钟

第二个方案:使用代理

首先需要知道,代理是什么?

嘿,兄弟,哥们儿访问这个网址有点困难,帮忙解决一下呗!

然后你就把需要访问的网址告诉代理先生,代理帮你访问,然后把他看到的所有内容原封不动的转发给你。

这就是代理。

代理的工作原理就是这么简单,因此呢,服务器看到的IP地址就是代理的IP地址,而不是你的IP地址,这样子你用很多个代理同时发起访问,服务器也没有办法。使用代理的步骤如下:

  • 1.参数是一个字典 {‘类型’ :‘代理ip: 端口号’}

         proxy_support = urllib.request.ProxyHandler({})

         它这个参数就是一个字典,字典的键就是代理的类型(如:http,https...),值就是对应的 ip 或者 域名 +端口号

  • 2.定制、创建 一个 opener

(opener可以看做是私人订制,当你使用 urlopen 打开一个普通网页的时候,你就是在使用默认的 opener 来工作,而这个opener 是可以有我们定制的,例如我们可以给它加上特殊的 headers,或者指定 代理,我们使用下面的语句定制、创建一个    opener)

opener = urllib.request.build_opener(proxy_support)

  • 3a.安装opener

     我们使用 urllib.request.install_opener(opener),把它安装到系统中,这是一劳永逸的做法,因为在此之后,你只要使用普通的 urlopen() 函数,就是使用定制好的 opener 进行工作,如果你不想替换掉默认的 opener,你可以使用下面的语句调用 opener。

  • 3b.调用opener

      opener.open(url)

我们来举个例子:

我们需要代理ip,直接在网上搜索即可。

 
  1. import urllib.request

  2. url = 'http:/www.whatismyip.com.tw' #查询ip的网站

  3. proxy_support = urllib.request.ProxyHandler({'http': '123.206.56.247:80'})

  4. opener = urllib.request.build_opener(proxy_support)

  5. urllib.request.install_opener(opener)

  6. response = urllib.request.urlopen(url)

  7. html = response.read().decode('utf-8')

  8. print(html)


测试题

0. 服务器是如何识访问来自浏览器还是非浏览器的?

答:通过发送的 HTTP 头中的 User-Agent 来进行识别浏览器与非浏览器,服务器还以 User-Agent 来区分各个浏览器。

1. 明明代码跟视频中的栗子一样,一运行却出错了,但在不修改代码的情况下再次尝试运行却又变好了,这是为什么呢?

答: 在网络信息的传输中会出现偶然的“丢包”现象,有可能是你发送的请求服务器没收到,也有可能是服务器响应的信息不能完整送回来……尤其在网络阻塞的时候。所以,在设计一个“称职”的爬虫时,需要考虑到这偶尔的“丢包”现象。

2. Request 是由客户端发出还是由服务端发出?

答:我们之前说 HTTP 是基于“请求-响应”模式,Request 即请求的意思,而 Response 则是响应的意思。由客户端首先发出 Request,服务器收到后返回 Response。

3. 请问如何为一个 Request 对象动态的添加 headers?

答:add_header() 方法往 Request 对象添加 headers。

4. 简单来说,代理服务器是如何工作的?他有时为何不工作了?

答: 将信息传给代理服务器,代理服务器替你向你要访问的服务器发送请求,然后在将服务器返回的内容返回给你。

因为有“丢包”现象发生,所以多了一个中间人就意味着会多一层发生“丢包”的几率,且大多数代理并不只为一个人服务,尤其是免费代理。

PS:大家想做“坏坏”的事情时可以考虑多几层代理,一般来说路由器日志并不会保存很长时间,几层代理后,基本很难查到是谁请求的。

5. HTTP 有好几种方法(GET,POST,PUT,HEAD,DELETE,OPTIONS,CONNECT),请问你如何晓得 Python 是使用哪种方法访问服务器呢?

答:使用 get_method() 方法获取 Request 对象具体使用哪种方法访问服务器。最常用的无非就是 GET 和 POST 了,当 Request 的 data 参数被赋值的时候,get_method() 返回 'POST',否则一般情况下返回 'GET'。

6. 上一节课后题中有涉及到登陆问题,辣么,你还记得服务器是通过什么来确定你是登陆还是没登陆的么?他会持续到什么时候呢?

答: 是 cookie,服务器通过判断你提交的 cookie 来确定访问是否来自”熟人“。

简单来说 cookie 可以分成两类:

  • 一类是即时过期的 cookies,称为“会话” cookies,当浏览器关闭时(这里是 python 的请求程序)自动清除
  • 另一类是有期限的 cookies,由浏览器进行存储,并在下一次请求该网站时自动附带(如果没过期或清理的话)

动动手

小甲鱼打算在这里先给大家介绍一个压箱底的模块 —— Beautiful Soup 4

翻译过来名字有点诡异:漂亮的汤?美味的鸡汤?呃……

好吧,只要你写出一个普罗大众都喜欢的模块,你管它叫“Beautiful Shit”大家也是能接受的……

 

Beautiful Soup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。Beautiful Soup 会帮你节省数小时甚至数天的工作时间。

这玩意儿到底怎么用?

看这 -> 传送门

上边链接是官方的快速入门教程(不用惧怕,这次有中文版了),请大家花差不多半个小时的时间自学一下,然后完成下边题目。

噢,对了,大家可以使用 pip 安装(Python3.4 以上自带的神一般的软件包管理系统,有了它 Python 的模块安装、卸载全部一键搞定!)

打开命令行窗口(CMD) -> 输入 pip install BeautifulSoup4 命令) -> 搞定。

0. 编写一个爬虫,爬百度百科“网络爬虫”的词条

(链接 -> 网络爬虫_百度百科),将所有包含“view”的链接按下边格式打印出来:

提示:题目中需要使用到简单的正则表达式(在官方的快速入门教程有演示),如果你希望马上就深入学习正则表达式,当然可以给你预支一下后边的知识 -> Python3 如何优雅地使用正则表达式

代码清单:

 
  1. import urllib.request

  2. import re

  3. from bs4 import BeautifulSoup

  4. def main():

  5. url = "http://baike.baidu.com/view/284853.htm"

  6. response = urllib.request.urlopen(url)

  7. html = response.read()

  8. soup = BeautifulSoup(html, "html.parser") # 使用 Python 默认的解析器

  9. for each in soup.find_all(href=re.compile("view")):

  10. print(each.text, "->", ''.join(["http://baike.baidu.com", each["href"]]))

  11. # 上边用 join() 不用 + 直接拼接,是因为 join() 被证明执行效率要高很多

  12. if __name__ == "__main__":

  13. main()

1. 直接打印词条名和链接不算什么真本事儿,这题要求你的爬虫允许用户输入搜索的关键词。

然后爬虫进入每一个词条,然后检测该词条是否具有副标题(比如搜索“猪八戒”,副标题就是“(中国神话小说《西游记》的角色)”),如果有,请将副标题一并打印出来:

程序实现效果如下:

代码清单:

 
  1. import urllib.request

  2. import urllib.parse

  3. import re

  4. from bs4 import BeautifulSoup

  5. def main():

  6. keyword = input("请输入关键词:")

  7. keyword = urllib.parse.urlencode({"word":keyword})

  8. response = urllib.request.urlopen("http://baike.baidu.com/search/word?%s" % keyword)

  9. html = response.read()

  10. soup = BeautifulSoup(html, "html.parser")

  11. for each in soup.find_all(href=re.compile("view")):

  12. content = ''.join([each.text])

  13. url2 = ''.join(["http://baike.baidu.com", each["href"]])

  14. response2 = urllib.request.urlopen(url2)

  15. html2 = response2.read()

  16. soup2 = BeautifulSoup(html2, "html.parser")

  17. if soup2.h2:

  18. content = ''.join([content, soup2.h2.text])

  19. content = ''.join([content, " -> ", url2])

  20. print(content)

  21. if __name__ == "__main__":

  22. main()

2. 哗啦啦地丢一堆链接给用户可不是什么好的体验,我们应该先打印 10 个链接,然后问下用户“您还往下看吗?

来,我给大家演示下:

然后为了增加用户体验,代码需要捕获未收录的词条,并提示:

提示:希望你还记得有生成器这么个东东

代码清单:

 
  1. import urllib.request

  2. import urllib.parse

  3. import re

  4. from bs4 import BeautifulSoup

  5. def test_url(soup):

  6. result = soup.find(text=re.compile("百度百科尚未收录词条"))

  7. if result:

  8. print(result[0:-1]) # 百度这个碧池在最后加了个“符号,给它去掉

  9. return False

  10. else:

  11. return True

  12. def summary(soup):

  13. word = soup.h1.text

  14. # 如果存在副标题,一起打印

  15. if soup.h2:

  16. word += soup.h2.text

  17. # 打印标题

  18. print(word)

  19. # 打印简介

  20. if soup.find(class_="lemma-summary"):

  21. print(soup.find(class_="lemma-summary").text)

  22. def get_urls(soup):

  23. for each in soup.find_all(href=re.compile("view")):

  24. content = ''.join([each.text])

  25. url2 = ''.join(["http://baike.baidu.com", each["href"]])

  26. response2 = urllib.request.urlopen(url2)

  27. html2 = response2.read()

  28. soup2 = BeautifulSoup(html2, "html.parser")

  29. if soup2.h2:

  30. content = ''.join([content, soup2.h2.text])

  31. content = ''.join([content, " -> ", url2])

  32. yield content

  33. def main():

  34. word = input("请输入关键词:")

  35. keyword = urllib.parse.urlencode({"word":word})

  36. response = urllib.request.urlopen("http://baike.baidu.com/search/word?%s" % keyword)

  37. html = response.read()

  38. soup = BeautifulSoup(html, "html.parser")

  39. if test_url(soup):

  40. summary(soup)

  41. print("下边打印相关链接:")

  42. each = get_urls(soup)

  43. while True:

  44. try:

  45. for i in range(10):

  46. print(next(each))

  47. except StopIteration:

  48. break

  49. command = input("输入任意字符将继续打印,q退出程序:")

  50. if command == 'q':

  51. break

  52. else:

  53. continue

  54. if __name__ == "__main__":

  55. main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/42824.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【CN-Docker】window11下Docker下开启kubernetes

1. 安装Docker 安装docker步骤如下: 下载Docker启用hyper-v 2.1.powershell,管理员运行Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All安装wsl配置Docker镜像加速地址(阿里云) 4.1. "registry-mirrors": [&quo…

让GPT人工智能变身常用工具-上

1.密码生成器:GPT为您创建安全密码 想象GPT作为您的个人密码生成器,负责从头到尾为您创建复杂且安全的密码。您只需要告诉他您的密码需求,比如密码的长度,是否包含大写字母、小写字母、数字或特殊字符,他会立即为您生成一个复杂但经过深度设计的密码。 例子: 我希望您…

Selenium 修改 HTTP 请求头三种方式

目录 前言: 什么是 HTTP 请求头 需要更改 HTTP 请求请求头 Selenium 修改请求头 Java HTTP 请求框架 代码实战 使用反向代理 使用 Firefox 扩展 下载火狐浏览器扩展 加载火狐扩展 设置扩展首选项 设置所需的功能 完整自动化用例 前言: Sele…

内存函数及其模拟实现

身体扛不住的时候,意志会带你杀出重围 文章目录 一、memcpy函数 函数介绍 模拟实现 二、memmove函数 函数介绍 模拟实现 三、memset函数 函数介绍 模拟实现 大家好,我是纪宁。这篇文章给大家介绍C语言中常见的内存处理函数。 一、memcpy函数 …

blender 基础材质篇

材质展示 材质背景介绍 什么是PBR? PBR 全称为 Physically Based Rendering,译为基于物理属性的引擎渲染,也就是说会把物质的颜色、粗糙度、高光属性等进行分别处理,使物质体现出更真实的感觉; 什么是BRDF&#xff…

Vue.js基础简答题

系列文章目录 后续补充 文章目录 系列文章目录前言一、库与框架的区别是什么?二、Vue.js 的核心特性有哪些?三、什么是数据驱动视图?四、MVVM 模型各部分含义是什么,在 Vue.js 中分别对应哪些功能?五、el 选项的作用是…

安全开发-JS应用原生开发JQuery库Ajax技术加密编码库断点调试逆向分析元素属性操作

文章目录 JS原生开发-文件上传-变量&对象&函数&事件JS导入库开发-登录验证-JQuery库&Ajax技术JS导入库开发-编码加密-逆向调试 JS原生开发-文件上传-变量&对象&函数&事件 1、布置前端页面 2、JS获取提交数据 3、JS对上传格式判断 <script>…

数据仓库发展历史

数据仓库发展历史 一、演变 数据仓库是企业中用于存储、整合和分析数据的关键组件。随着时间的推移&#xff0c;数据仓库经历了三代演化&#xff1a;从需求驱动到平台化、从平台化到智能&#xff08;AI&#xff09;化 二、第一代&#xff08;过时&#xff09; 第一代数据仓…

第四讲:MySQL中DDL一些基本数据类型及表的创建、查询

目录 1、创建表:2、DDL一些基本数据类型&#xff1a; 1、创建表: 部分单词及解析&#xff1a; 1、tables:表 2、comment:评论&#xff0c;解释 3、gender:性别 4、neighbor&#xff1a;邻居 1、创建表&#xff1a;&#xff08;注&#xff1a;在自定义数据库操作&#xff0c;…

【itext7】itext7操作PDF文档之添加表单控件(单行文本框、多行文本框、单选框、复选框、下拉框、按钮)

这篇文章&#xff0c;主要介绍itext7操作PDF文档之添加表单控件&#xff08;单行文本框、多行文本框、单选框、复选框、下拉框、按钮&#xff09;。 目录 一、itext操作PDF表单 1.1、添加单行文本框 1.2、添加多行文本框 1.3、添加单选框 1.4、添加复选框 1.5、添加下拉框…

Pytorch迁移学习使用Resnet50进行模型训练预测猫狗二分类

目录 1.ResNet残差网络 1.1 ResNet定义 1.2 ResNet 几种网络配置 1.3 ResNet50网络结构 1.3.1 前几层卷积和池化 1.3.2 残差块&#xff1a;构建深度残差网络 1.3.3 ResNet主体&#xff1a;堆叠多个残差块 1.4 迁移学习猫狗二分类实战 1.4.1 迁移学习 1.4.2 模型训练 1.…

(css)滚动条样式

(css)滚动条样式 效果&#xff1a; /*滚动条整体样式*/ ::-webkit-scrollbar {width: 2px;/*高宽分别对应横竖滚动条的尺寸*/height: 10px; } ::-webkit-scrollbar-thumb {/*滚动条里面小方块*/border-radius: 10px;width: 2px;height: 60px;background: linear-gradient(0deg,…

CentOS7系统MBR、GRUB2、内核启动流程报错问题

目录 &#x1f969;Linux启动流程 &#x1f969;MBR修复 &#x1f36d;1、模拟损坏 &#x1f36d;2、重启测试 &#x1f36d;3、修复MBR &#x1f36d;4、测试系统 &#x1f969;GRUB2修复 &#x1f36d;1、模拟损坏 &#x1f36d;2、修复GRUB2 &#x1f36d;3、测试系统 &…

03. 自定义镜像 Dockerfile

目录 1、前言 2、构建镜像的方式 2.1、docker commit 2.1.1、先查看下当前的容器 2.1.2、生成该容器镜像 2.1.3、查看镜像列表 2.2、Dockerfile 2.2.1、创建Dockerfile文件 2.2.2、编写Dockerfile文件 2.2.3、构建镜像 2.2.4、使用该镜像生成容器 3、Dockerfile 3…

GO内存模型(同步机制)

文章目录 概念1. 先行发生 编译器重排同步机制init函数协程的创建channelsync 包1. sync.mutex2. sync.rwmutex3. sync.once atomic 参考文献 概念 1. 先行发生 The happens before relation is defined as the transitive closure of the union of the sequenced before and …

【微信小程序】使用iView组件库中的icons资源

要在微信小程序中使用iView组件库中的icons资源&#xff0c;需要先下载并引入iView组件库&#xff0c;并按照iView的文档进行配置和使用。 以下是一般的使用步骤&#xff1a; 下载iView组件库的源码或使用npm安装iView。 在小程序项目的app.json文件中添加iView组件库的引入配…

PHP中常用数组排序算法

一&#xff1a;冒泡排序 1&#xff1a;算法步骤 比较相邻项的值&#xff0c;如果前者比后者大&#xff0c;交换顺序。 进行一轮比较后&#xff0c;最后一个值为最大的值。 进行下一轮比较&#xff0c;比上次少比较一项。 以此类推&#xff0c;比较剩下最后一项的时候&#…

【Linux进程】进程控制(上) {进程创建:fork的用法,fork的工作流程,写时拷贝;进程终止:3种退出情况,退出码,常见的退出方法}

一、进程创建 1.1 fork的初步认识和基本使用 在linux中fork函数是非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 #include <unistd.h> pid_t fork(void);返回值&#xff1a;子进程中返回0&#xff0c;父进…

ORB-SLAM2学习笔记5之EuRoc、TUM和KITTI开源数据运行ROS版ORB-SLAM2生成轨迹

文章目录 0 引言1 数据预处理1.1 EuRoc数据1.2 TUM数据1.3 KITTI数据 2 代码修改2.1 单目2.2 双目2.3 RGB-D 3 运行ROS版ORB-SLAM23.1 单目3.2 双目3.3 RGB-D ORB-SLAM2学习笔记系列&#xff1a; 0 引言 ORB-SLAM2学习笔记1已成功编译安装ROS版本ORB-SLAM2到本地&#xff0c;本…

SQL高级教程第三章

SQL CREATE DATABASE 语句 CREATE DATABASE 语句 CREATE DATABASE 用于创建数据库。 SQL CREATE DATABASE 语法 CREATE DATABASE database_name SQL CREATE DATABASE 实例 现在我们希望创建一个名为 "my_db" 的数据库。 我们使用下面的 CREATE DATABASE 语句&…