《零基础入门学习Python》第054讲:论一只爬虫的自我修养2:实战

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

今天我们决定在实战中来进行学习,会举两个例子,第一个例子是我们会下载一只猫,第二个例子是我们用Python来模拟浏览器通过在线的谷歌翻译进行文本的翻译。

如果你认为上节课我只是简单介绍了一下 urlopen() 函数的用法,那你就错了,上节课我已经说了,相关的文档在哪里,要教你的东西在文档里都有,OK,我们来第一个例子吧。

(一)使用Python下载一只猫

我们常说,林子大了,什么鸟都有。互联网这么大,那当然不管什么样的奇葩网站都会有。我们今天举的例子就是要访问一个 {placekitten} - Placeholder kitten images for developers,这个网站是为猫农量身定制的一个站点,网站后面你只需要加上 /宽度/高度,就可以得到一只相应宽度和高度的猫的图片。这些图片都是JPG格式的,你可以通过右键将其简单保存到桌面上。

我们第一个例子就是使用Python实现刚才的操作,事实上我们上节课教过的内容也是完全足够的,我们新建一个 download_cat.py 文件。

首先,我们需要 import urllib.request,然后使用urlopen() 函数得到 response,得到的 cat_img 可以用一个文件保存,我们命名这个文件为 cat_500_600.jpg,我们说过,图片也是文件,它也是二进制数据组成的,我们这里用 ‘wb’ 将收到的二进制数据写入 jpg 格式的文件就可以了。

 
  1. #download_cat.py

  2. import urllib.request

  3. response = urllib.request.urlopen("http://placekitten.com/500/600")

  4. cat_img = response.read()

  5. with open('cat_500_600.jpg', 'wb') as f:

  6. f.write(cat_img)

运行之后,就在桌面上有了一张 名为 cat_500_600.jpg 的图片。我们接着继续解释一下上面的代码:

上节课,我们说过,urlopen() 函数中的 url 参数可以是字符串,也可以是 Request object,其实,在上面的程序中,我们传入的是地址字符串,它也是将地址字符串转换为 Request 对象,然后再将对象传入 urlopen() 函数。因此,

response = urllib.request.urlopen("http://placekitten.com/500/600")

等价于

 
  1. req = urllib.request.Resquest("http://placekitten.com/500/600")

  2. response = urllib.request.urlopen(req)

另外,urlopen() 函数返回的 response 其实是一个对象(object),看下图文档解释,因此你可以使用 read() 方法来读取内容,

文档还告诉我们,除了可以使用 read() 方法之外,还可以是使用 geturl() 、info()  和 getcode() 方法,我们试一下这三个函数分别返回什么:

我们运行 download_cat.py 之后,调用这几个方法:

 
  1. >>>

  2. =========== RESTART: C:\Users\XiangyangDai\Desktop\download_cat.py ===========

  3. >>> response.geturl()

  4. 'http://placekitten.com/500/600'

  5. >>> response.info()

  6. <http.client.HTTPMessage object at 0x00000150F729AB70>

  7. >>> print(response.info())

  8. Date: Tue, 11 Dec 2018 06:57:33 GMT

  9. Content-Type: image/jpeg

  10. Content-Length: 20921

  11. Connection: close

  12. Set-Cookie: __cfduid=d2f9e8e46b6e9940463cf24baf0b7f0fb1544511453; expires=Wed, 11-Dec-19 06:57:33 GMT; path=/; domain=.placekitten.com; HttpOnly

  13. Access-Control-Allow-Origin: *

  14. Cache-Control: public, max-age=86400

  15. Expires: Wed, 12 Dec 2018 06:57:33 GMT

  16. CF-Cache-Status: HIT

  17. Accept-Ranges: bytes

  18. Vary: Accept-Encoding

  19. Server: cloudflare

  20. CF-RAY: 48760ec5d6fc99c1-LAX

  21. >>> response.getcode()

  22. 200

geturl() 得到的就是你访问的具体的地址;

info() 得到的是一个 HTTPMessage 的对象,你可以将它打印出来,包含了 远程服务器返回的 Head 信息;

getcode() 返回的是 Http 的状态码,200 表示 OK,就是正常响应。

(二)利用在线有道翻译来翻译文本

我们怎样编写Python 程序模拟浏览器,让它翻译呢?我们首先要介绍的是审查元素这个功能。基本上现在所有的浏览器都会自带这样这个调试插件,以360浏览器为例,右键选择-审查元素,或者直接按 F12,就会显示审查元素窗口。

我们要看的是 Network 这一块,当我们点下自动翻译按钮时,在下面会看到有很多 Method,其中有 Get , 有Post ,这些内容都是浏览器与客户端的通信内容,在客服端与服务器之间进行请求的时候,两种最常用的方法:一种就是Get,一种就是 Post,在定义上来说,Get是指从服务器请求获得数据,而Post是向指定服务器提交被处理的数据,当然在现实情况中,Get也常常用作提交数据。但是我们这里有 Post,刚刚我们是提交数据,提交 I love you!这个语句让它翻译,我们点进去:

我们看到有 Headers 和 Preview 等,我们先看一下 Preview

我们看到这里有我们所需要的结果,说明我们就找对地方了,但是在编写程序之前,我们还是有必要讲解一下 Headers 中的内容:

Request URL:http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule,有人会认为 urlopen()函数打开的应该是 有道翻译_文本、文档、网页、在线即时翻译 这个地址,其实在内部嵌入的是前面的这个地址,你要实现翻译的机制是在这。

Request Method:POST,请求的方法是 Post 的形式。

Status Code:200 OK,状态码 200 表示正常响应。如果是 404 就是页面不见了。更多关于HTTP状态码的信息请查阅:

HTTP状态码大全

Remote Address 是服务器的 IP 地址加上打开的端口号。

Resquest Headers:是客服端(这里就是浏览器,用 Python代码的时候就是我们的代码)发送请求的Headers,这个常常用于服务端来判断是否非人类访问,什么意思呢?假设我们写一个 Python 代码,然后用这个代码批量的访问网站的数据,这样子,服务器的压力就很大了,所以呢,服务器一般是不欢迎非人类的访问的。一般我们就是使用Resquest Headers里面的User-Agent来识别是浏览器访问还是代码访问,大家可以看到,这里的User-Agent显示的系统的架构是(Windows NT 10.0; WOW64),后面你还包括浏览器的核心及其版本号等信息。如果你使用Python 访问的话,这个User-Agent默认就是 Python URL 3.5,这样就可能被屏蔽掉。(不过呢,如果服务器君以为这样就可以阻挡我们前进的脚步的话,他就太天真了,这个User-Agent是可以进行自定义的,嘻嘻,后面会给大家介绍)

Form Data:其实就是我们这个Post提交的主要内容,在 i 这里看到了提交的待翻译的内容。

介绍到这里就已经够用了,接下来看看文档,了解Python如何提交Post呢?

urllib.request.urlopen(urldata=None, [timeout, ]*cafile=Nonecapath=Nonecadefault=Falsecontext=None)

Open the URL url, which can be either a string or a Request object.

data must be a bytes object specifying additional data to be sent to the server, or None if no such data is needed. data may also be an iterable object and in that case Content-Length value must be specified in the headers. Currently HTTP requests are the only ones that use data; the HTTP request will be a POST instead of a GET when the data parameter is provided.

data should be a buffer in the standard application/x-www-form-urlencoded format. The urllib.parse.urlencode() function takes a mapping or sequence of 2-tuples and returns an ASCII text string in this format. It should be encoded to bytes before being used as the data parameter.

上面蓝色文字已经写得很清楚了(这些内容来自urllib的Python文档的urllib.request部分),urlopen有一个data参数,如果这个参数被赋值,那么它就是以POST的形式取代GET的形式,也就是说,如果data = None的话,就默认是以GET的形式。这里还说了,data参数必须是基于application/x-www-form-urlencoded的格式,它还很贴心的告诉我们,你可以使用urllib.parse.urlencode()函数将字符串转换为所需要的形式。

事实上,我们有了这两段话的描述,我们就可以来写代码了:(命名为:translation.py)

 
  1. #translation.py

  2. import urllib.request

  3. import urllib.parse

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

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

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

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

  8. data['i'] = '我爱你'

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  26. print(html)

运行结果为:

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

  2. {"type":"ZH_CN2EN","errorCode":0,"elapsedTime":0,"translateResult":[[{"src":"我爱你","tgt":"I love you"}]]}

结果倒是可以了,只是这样的结果是给程序员看的,如果是给用户看,那也太不友好了。(另外,如果大家对于编码还有什么困惑的,可以查看:Python编码问题的解决方案总结),我们打印出来的是一个字符串,有人就说,我们可以通过字符串查找的形式把 tgt 找出来,但这样太被动了。

其实,这是一个 json 结构,json 是一种轻量级的数据交换结构,说白了,这里就是用字符串的形式把 Python 的输出结果给封装起来,这个字符串里面包含的其实是一个字典,"translateResult" 里面的值是一个列表的列表的字典,我们可以使用下面的方法来解决:

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

  2. {"type":"ZH_CN2EN","errorCode":0,"elapsedTime":0,"translateResult":[[{"src":"我爱你","tgt":"I love you"}]]}

  3. >>> import json

  4. >>> json.loads(html)

  5. {'errorCode': 0, 'type': 'ZH_CN2EN', 'elapsedTime': 0, 'translateResult': [[{'tgt': 'I love you', 'src': '我爱你'}]]}

  6. >>> target = json.loads(html)

  7. >>> type(target)

  8. <class 'dict'>

  9. >>> target['translateResult'][0][0]['tgt']

  10. 'I love you'

综上,我们就可以把我们的翻译程序美化一下:

 
  1. #translation.py

  2. import urllib.request

  3. import urllib.parse

  4. import json

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

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

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

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

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

  10. data['i'] = content

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  28. target = json.loads(html)

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

运行结果:

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

  2. 请输入需要翻译的内容:人生苦短,我学Python

  3. 翻译结果:Life is too short, I learn Python

我们的要求实现了,但是这样的代码还不能应用到我们的生产实践中,因为你这样搞多了,服务器就会发现非人类的 User Agent 频繁访问,就会把你屏蔽掉了。还有就是发现这个IP怎么访问的这么频繁,就把你拉黑了。其实这些问题,Python都是有解决方法的,欲知详情如何,请听下回分解。


测试题

0. urlopen() 方法的 timeout 参数用于设置什么?

答:timeout 参数用于设置连接的超时时间,单位是秒。

1. 如何从 urlopen() 返回的对象中获取 HTTP 状态码?

答:

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

  2. code = response.getcode()

2. 在客户端和服务器之间进行请求-响应时,最常用的是哪两种方法?

答:GET 和 POST。

3. HTTP 是基于请求-响应的模式,那是客户端发出请求,服务端做出响应;还是服务端发出请求,客户端做出响应呢?

答:发出请求的永远是客户端,做出响应的永远是服务端。

4. User-Agent 属性通常是记录什么信息?

答:普通浏览器会通过该内容向访问网站提供你所使用的浏览器类型、操作系统、浏览器内核等信息的标识。

5. 如何通过 urlopen() 使用 POST 方法像服务端发出请求?

答:urlopen 函数有一个 data 参数,如果给这个参数赋值,那么 HTTP 的请求就是使用 POST 方式;如果 data 的值是 None,也就是默认值,那么 HTTP 的请求就是使用 GET 方式。

6. 使用字符串的什么方法将其它编码转换为 Unicode 编码?

答:decode。decode 的作用是将其他编码的字符串转换成 unicode 编码,相反,encode 的作用是将 unicode 编码转换成其他编码的字符串。

7. JSON 是什么鬼?

答:JSON 是一种轻量级的数据交换格式,说白了这里就是用字符串把 Python 的数据结构封装起来,便与存储和使用。


动动手

0. 配合 EasyGui,给“下载一只猫“的代码增加互动:

  • 让用户输入尺寸;
  • 如果用户不输入尺寸,那么按默认宽400,高600下载喵;
  • 让用户指定保存位置。

程序实现如下图:

代码清单:

 
  1. import easygui as g

  2. import urllib.request

  3. def main():

  4. msg = "请填写喵的尺寸"

  5. title = "下载一只喵"

  6. fieldNames = ["宽:", "高:"]

  7. fieldValues = []

  8. size = width, height = 400, 600

  9. fieldValues = g.multenterbox(msg, title, fieldNames, size)

  10. while 1:

  11. if fieldValues == None:

  12. break

  13. errmsg = ""

  14. try:

  15. width = int(fieldValues[0].strip())

  16. except:

  17. errmsg += "宽度必须为整数!"

  18. try:

  19. height = int(fieldValues[1].strip())

  20. except:

  21. errmsg += "高度必须为整数!"

  22. if errmsg == "":

  23. break

  24. fieldValues = g.multenterbox(errmsg, title, fieldNames, fieldValues)

  25. url = "http://placekitten.com/g/%d/%d" % (width, height)

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

  27. cat_img = response.read()

  28. filepath = g.diropenbox("请选择存放喵的文件夹")

  29. if filepath:

  30. filename = '%s/cat_%d_%d.jpg' % (filepath, width, height)

  31. else:

  32. filename = 'cat_%d_%d.jpg' % (width, height)

  33. with open(filename, 'wb') as f:

  34. f.write(cat_img)

  35. if __name__ == "__main__":

  36. main()

1. 写一个登录豆瓣的客户端。

这道题可能要难为大家了,因为需要 N 多你没学过的知识!

不过我也不打算让你断送希望,下边是一个可行的 Python 2 的代码片段,请修改为 Python 3 版本。其中一些库和知识点你可能还没学过,但凭借着过人的自学能力,你可以在不看答案的情况下完成任务的,对吗?

程序实现如下图:

Python2 实现的代码:

 
  1. # -- coding:gbk --

  2. import re

  3. import urllib, urllib2, cookielib

  4. loginurl = 'https://www.douban.com/accounts/login'

  5. cookie = cookielib.CookieJar()

  6. opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))

  7. params = {

  8. "form_email":"your email",

  9. "form_password":"your password",

  10. "source":"index_nav" #没有的话登录不成功

  11. }

  12. #从首页提交登录

  13. response=opener.open(loginurl, urllib.urlencode(params))

  14. #验证成功跳转至登录页

  15. if response.geturl() == "https://www.douban.com/accounts/login":

  16. html=response.read()

  17. #验证码图片地址

  18. imgurl=re.search('<img id="captcha_image" src="(.+?)" alt="captcha" class="captcha_image"/>', html)

  19. if imgurl:

  20. url=imgurl.group(1)

  21. #将图片保存至同目录下

  22. res=urllib.urlretrieve(url, 'v.jpg')

  23. #获取captcha-id参数

  24. captcha=re.search('<input type="hidden" name="captcha-id" value="(.+?)"/>' ,html)

  25. if captcha:

  26. vcode=raw_input('请输入图片上的验证码:')

  27. params["captcha-solution"] = vcode

  28. params["captcha-id"] = captcha.group(1)

  29. params["user_login"] = "登录"

  30. #提交验证码验证

  31. response=opener.open(loginurl, urllib.urlencode(params))

  32. ''' 登录成功跳转至首页 '''

  33. if response.geturl() == "http://www.douban.com/":

  34. print 'login success ! '

答:Python 3 对比 Python 2 有不少的改变。

在本题中:

  • urllib 和 urllib2 合并,大多数功能放入了 urllib.request 模块;
  • 原来的 urllib.urlencode() 变为 urllib.parse.urlencode().encode(),由于编码的关系,你还需要在后边加上 encode('utf-8');
  • cookielib 被改名为 http.cookiejar;

课堂中我们还没讲,所以这里借机会给大家简单科普一下 cookie 是什么东西:

我们说 HTTP 协议是基于请求响应模式,就是客户端发一个请求,服务端回复一个响应酱紫……

但 HTTP 协议是无状态的,也就是说客户端这会儿给服务端提交了账号密码,服务端回复验证通过,但下一秒客户端说我要访问 XXOO 资源,服务端回复:“啊??你是谁?!”

为了解决这个尴尬的困境,有人就发明出了 cookie。cookie 相当于服务端(网站)用于验证你的身份的密文。于是客户端每次提交请求的时候,服务端通过验证 cookie 即可知道你的身份信息。那么正如你所猜测的,CookieJar 是 Python 用于存放 cookie 的对象。

当然,这里已经给你提供了 Python 2 的代码,你不懂上边这些,也不影响完成作业。

代码清单:

 
  1. import re

  2. import urllib.request

  3. from http.cookiejar import CookieJar

  4. # 豆瓣的登录url

  5. loginurl = 'https://www.douban.com/accounts/login'

  6. cookie = CookieJar()

  7. opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor)

  8. data = {

  9. "form_email":"your email",

  10. "form_password":"your password",

  11. "source":"index_nav"

  12. }

  13. data = {}

  14. data['form_email'] = '你的账号'

  15. data['form_password'] = '你的密码'

  16. data['source'] = 'index_nav'

  17. response = opener.open(loginurl, urllib.parse.urlencode(data).encode('utf-8'))

  18. #验证成功跳转至登录页

  19. if response.geturl() == "https://www.douban.com/accounts/login":

  20. html = response.read().decode()

  21. #验证码图片地址

  22. imgurl = re.search('<img id="captcha_image" src="(.+?)" alt="captcha" class="captcha_image"/>', html)

  23. if imgurl:

  24. url = imgurl.group(1)

  25. # 将验证码图片保存至同目录下

  26. res = urllib.request.urlretrieve(url, 'v.jpg')

  27. # 获取captcha-id参数

  28. captcha = re.search('<input type="hidden" name="captcha-id" value="(.+?)"/>' ,html)

  29. if captcha:

  30. vcode = input('请输入图片上的验证码:')

  31. data["captcha-solution"] = vcode

  32. data["captcha-id"] = captcha.group(1)

  33. data["user_login"] = "登录"

  34. # 提交验证码验证

  35. response = opener.open(loginurl, urllib.parse.urlencode(data).encode('utf-8'))

  36. # 登录成功跳转至首页 '''

  37. if response.geturl() == "http://www.douban.com/":

  38. print('登录成功!')

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL8.0索引新特性

文章目录 1 支持降序索引2 隐藏索引 1 支持降序索引 举例&#xff1a;分别在MySQL 5.7版本和MySQL 8.0版本中创建数据表ts1&#xff0c;结果如下&#xff1a; CREATE TABLE ts1(a int,b int,index idx_a_b(a,b desc) );在MySQL 5.7版本中查看数据表ts1的结构&#xff0c;从结…

IntelliJ IDEA2023中利用maven-archetype-quickstart模板创建项目无src文件夹及maven插件下载过慢问题的解决

目录 介绍问题之解决问题2的解决问题1的解决 介绍 昨天下载并安装了IntelliJ IDEA 2023的最新版&#xff08;以下简称为IDEA 2023&#xff09;&#xff0c;学习利用该IDE编写Java项目及将其与maven结合构建项目。我所安装的maven是去年暑假安装的&#xff0c;版本为Apache Mav…

认识主被动无人机遥感数据、预处理无人机遥感数据、定量估算农林植被关键性状、期刊论文插图精细制作与Appdesigner应用开发

目录 第一章、认识主被动无人机遥感数据 第二章、预处理无人机遥感数据 第三章、定量估算农林植被关键性状 第四章、期刊论文插图精细制作与Appdesigner应用开发 更多推荐 遥感技术作为一种空间大数据手段&#xff0c;能够从多时、多维、多地等角度&#xff0c;获取大量的…

【数据结构常见七大排序(一)】—插入排序篇【直接插入排序】And【希尔排序】

目录 1.排序的概念及其运用1.1排序的概念1.2排序运用​​​​​​​​​​​​​​​​​​​​​1.3常见的七大排序 ​​2.直接插入排序2.1基本思想​​2.2直接插入排序2.3动图助解2.4直接插入排序源码​2.5直接插入排序的特性总结 ​​3.希尔排序( 缩小增量排序 )​​3.1希尔…

STM32CubeMX X-CUBE-AI更新模型

如题&#xff0c;我采用一个采用stm32CUBEMX生成了工程&#xff0c;工程里面使用了X-CUBE-AI对自定义的模型进行模型压缩&#xff0c;但是我经常要更新模型&#xff0c;那么怎样更新模型了。这里开博客记录一下。 如图所示&#xff0c;为基于STM32CUBEMX生成的工程文件目录结构…

C/C++ 程序 IDE 开发工具 CLion

下载地址&#xff1a; https://www.jetbrains.com/clion/ https://www.jetbrains.com/clion/ 下载地址&#xff1a; https://www.jetbrains.com/clion/download/ https://www.jetbrains.com/clion/download/ 历史版本&#xff08;老版本&#xff09;下载地址&#xff1a; h…

关于正则表达式的简单介绍以及使用

一、介绍 正则表达式通常被用来检索匹配某种模式&#xff08;规律&#xff09;的文本 日常文本检索&#xff0c;如果单纯检索某个数字&#xff0c;字母&#xff0c;或者单词匹配出来的结果较多&#xff0c;而面对目标文件内容较大的时&#xff0c;我们也不可能肉眼对检索出来的…

leetcode 542. 01 矩阵

给定一个由 0 和 1 组成的矩阵 mat &#xff0c;请输出一个大小相同的矩阵&#xff0c;其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。 两个相邻元素间的距离为 1 。 示例 1&#xff1a; 输入&#xff1a;mat [[0,0,0],[0,1,0],[0,0,0]] 输出&#xff1a;[[0,0,0],…

【Unity2D】设置一物体默认在其他物体之上不被遮挡

比如我想让机器人显示在箱子的前面。 点击箱子&#xff0c;将其层级设置在机器人的后面。 即修改箱子的Order in Layer 在机器人之后 物体默认的Order in Layer 都是0 &#xff0c;将箱子的Order in Layer修改为-1即可 这样将确保先绘制机器人&#xff0c;然后绘制箱子。这样…

C#鼠标拖拽,移动图片实例

最近工作需要做一个鼠标可以拖拽移动图片的功能。 写了几个基本功能&#xff0c;勉强能用。这里记录一下。欢迎大神补充。 这个就是完成的功能。 下边的绿色是一个pictureBox&#xff0c;白色框也是一个pictureBox&#xff0c;他们二者是子父级关系。 绿色是父级&#xff0c…

NAS私有云存储 - 搭建Nextcloud私有云盘并公网远程访问

文章目录 摘要视频教程1. 环境搭建2. 测试局域网访问3. 内网穿透3.1 ubuntu本地安装cpolar3.2 创建隧道3.3 测试公网访问 4 配置固定http公网地址4.1 保留一个二级子域名4.1 配置固定二级子域名4.3 测试访问公网固定二级子域名 摘要 Nextcloud,它是ownCloud的一个分支,是一个文…

【《Spring Boot微服务实战(第2版)》——一本关于如何在Spring Boot中构建微服务的全面指南】

使用Spring Boot框架构建基于Java的微服务架构&#xff0c;将应用程序从小型单体架构蜕变为由多个服务组成的事件驱动架构。这个最新版本围绕服务发现、负载均衡、路由、集中式日志、按环境配置和容器化等知识点&#xff0c;循序渐进地讲述微服务架构、测试驱动的开发和分布式系…

Mysql 主从复制、读写分离

目录 一、前言&#xff1a; 二、主从复制原理 2.1 MySQL的复制类型 2.2 MySQL主从复制的工作过程; 2.2.1 MySQL主从复制延迟 2.3 MySQL 有几种同步方式&#xff1a; 三种 2.3.1、异步复制&#xff08;Async Replication&#xff09; 2.3.2、同步复制&#xff08;Sync Re…

centos逻辑分区磁盘扩展

最近碰到服务器磁盘空间不足&#xff0c;需要扩展逻辑分区的需求&#xff0c;特地做下小笔记&#xff0c;方便后续自己回忆。下图是磁盘的相关概念示意图&#xff1a; 1、查看磁盘空间 [rootlocalhost ~]# df -h #查看磁盘空间&#xff0c;根分区的大小是18G&#xff0c;已经用…

力扣 -- 918. 环形子数组的最大和

一、题目&#xff1a; 题目链接&#xff1a;918. 环形子数组的最大和 - 力扣&#xff08;LeetCode&#xff09; 二、解题步骤&#xff1a; 下面是用动态规划的思想解决这道题的过程&#xff0c;相信各位小伙伴都能看懂并且掌握这道经典的动规题目滴。 三、参考代码&#xff1…

PCL点云处理之最小二乘直线拟合(2D| 方法2)(❤亲测可用❤)(二百零一)

PCL点云处理之最小二乘直线拟合(2D| 方法2)(❤亲测可用❤)(二百零一) 一、算法简介二、算法实现1.代码2.结果一、算法简介 在二百章中,我们介绍了一种最小二乘拟合直线点云(2D)的方法,可以获取直线方程系数k,b,这里介绍另一种拟合直线点云的方法,更为简单方便,结果…

MGRE之OSPF实验

目录 题目&#xff1a; 步骤二&#xff1a;拓扑设计与地址规划​编辑 步骤三&#xff1a;IP地址配置 步骤四&#xff1a;缺省路由配置 步骤五&#xff1a;NAT的配置 步骤六&#xff1a;MGRE配置 中心站点R1配置 分支站点配置 中心站点R5 R1配置 分支站点配置 检测&…

S32K1xx SDK(版本:S32_SDK_S32K1xx_RTM_4.0.3 )详细介绍

前言 在学习一款MCU之前&#xff0c;一般我的习惯是先下载官方提供的SDK包进行学习。然后学习了解SDK提供的资源、框架、以及各目录结构文件作用等&#xff0c;下面边学边做笔记记录。 S32K1系列SDK我们可以到下面的NXP官网去获取&#xff1a; https://www.nxp.com.cn/design…

微服务如何治理

微服务远程调用可能有如下问题&#xff1a; 注册中心宕机&#xff1b; 服务提供者B有节点宕机&#xff1b; 服务消费者A和注册中心之间的网络不通&#xff1b; 服务提供者B和注册中心之间的网络不通&#xff1b; 服务消费者A和服务提供者B之间的网络不通&#xff1b; 服务提供者…

一、二维前缀和算法

文章目录 前缀和模板724. 寻找数组的中心下标238. 除自身以外数组的乘积560. 和为 K 的子数组974. 和可被 K 整除的子数组525. 连续数组1314. 矩阵区域和 前缀和模板 一维前缀和&#xff1a; import java.util.*;public class Main {public static void main(String[] args) …