当前位置: 首页 > news >正文

Python爬虫第5节-urllib的异常处理、链接解析及 Robots 协议分析

目录

一、处理异常

1.1 URLError

1.2 HTTPError

二、解析链接

2.1 urlparse()

2.2 urlunparse()

2.3 urlsplit()

2.4 urlunsplit()

2.5 urljoin()

2.6  urlencode()

2.7  parse_qs()

2.8 parse_qsl()

2.9 quote()

2.10 unquote()

三、分析网站Robots协议

3.1 Robots协议

3.2 爬虫名称

3.3 robotparser


一、处理异常

        上一节,我们学习了如何发送网络请求。但在实际使用中,网络情况往往不稳定,很容易出现异常。要是对这些异常不管不顾,程序就可能报错,甚至直接终止运行。所以,对异常进行处理是很有必要的。 

        在Python的urllib库中,`error`模块专门定义了`request`模块在运行时可能产生的各种异常。也就是说,当`request`模块执行出现问题时,就会抛出`error`模块里预先定义好的异常 。

1.1 URLError

        `URLError`类包含在urllib库的`error`模块里,它从`OSError`类继承而来,是`error`模块里处理异常的基础类。只要是`request`模块运行过程中产生的异常,都可以通过捕获`URLError`类来处理。`URLError`类有个`reason`属性,借助它能够获取到报错的具体原因。 

下面通过实例来看:

from urllib import request, error
try:response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.URLError as e:print(e.reason)

        我们尝试打开一个不存在的页面,正常情况下应该会报错。但通过捕获`URLError`这个异常,运行结果如下:

Not Found

        程序没直接报错,而是输出了上面那些内容。这么做,一方面能防止程序因异常而终止运行,另一方面也实现了对异常的有效处理。 

1.2 HTTPError

        `HTTPError`隶属于`URLError`子类,主要用来处理HTTP请求时出现的错误,像认证请求失败这类问题。它包含3个属性:
- `code`:给出HTTP状态码,比如404意味着网页找不到,500代表服务器内部出错。
- `reason`:和父类功能相同,都是为了给出错误的成因。
- `headers`:返回请求头信息。

下面通过几个实例来了解:

from urllib import request, error
try:response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.HTTPError as e:print(e.reason, e.code, e.headers, sep='\n')

运行结果如下:

Not Found
404
Server:nginx/1.4.6(Ubuntu)
Date:Wed,03 Aug 2016 08:54:22 GMT
Content-Type:text/html;charset=UTF-8
Transfer-Encoding:chunked
Connection:close
X-Powered-By:PHP/5.5.9-1ubuntu4.14
Vary: Cookie
Expires:wed,11 Jan 1984 05:00:00 GMT
Cache-Control:no-cache,must-revalidate,max-age=0
Pragma:no-cache
Link:<https://cuiqingcai.com/wp-json/>;rel="https://api.w.org/"

        同样是访问该网址,这里捕获了`HTTPError`异常,并输出了`reason`、`code`和`headers`属性。由于`URLError`是`HTTPError`的父类,因此可以先捕获子类错误,再捕获父类错误。

上述代码更优的写法如下:

from urllib import request, error
try:response = request.urlopen('https://cuiqingcai.com/index.htm')
except error.HTTPError as e:print(e.reason, e.code, e.headers, sep='\n')
except error.URLError as e:print(e.reason)
else:print('Request Successfully')

        按照这种方式,程序会优先捕获`HTTPError`异常,借此获取错误状态码、错误原因、请求头`headers`等信息。要是捕获的不是`HTTPError`异常,程序就会捕获`URLError`异常,并输出对应的错误原因。最后,借助`else`语句来处理程序正常运行时的逻辑,这算得上是一种比较好的异常处理办法。

        需要注意,`reason`属性返回的内容并非总是字符串,有时也可能是一个对象。

看下面的实例:

import socket
import urllib.request
import urllib.error
try:response = urllib.request.urlopen('https://www.baidu.com', timeout=0.01)
except urllib.error.URLError as e:print(type(e.reason))if isinstance(e.reason, socket.timeout):print('TIME OUT')

        这里我们直接设置超时时间,强制抛出`timeout`异常。运行结果如下:

<class'socket.timeout'>
TIME OUT

        从运行结果能看到,`reason`属性返回的是`socket.timeout`类。基于这一点,我们可以借助`isinstance()`方法来判断它的类型,从而对异常进行更细致的分析。

        至此我们了解了`error`模块的使用方法。在编写程序时,合理地捕获异常,不仅能更准确地判断异常类型,还能增强程序的稳定性,减少错误发生。

二、解析链接

        前面讲过,urllib库包含`parse`模块。这个模块制定了处理URL的标准接口,能实现URL各部分的提取、整合,以及链接的转换。`parse`模块支持处理多种协议的URL,像`file`、`fp`、`gopher` ,还有日常常用的`http`、`https`,以及`imap`、`mailto`等。接下来这节,会介绍`parse`模块里一些常用方法,帮助大家体会这些方法在处理URL时有多方便。

2.1 urlparse()

该方法可实现URL的识别和分段。先通过实例来看:

from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html;user?id=5#comment')
print(type(result), result)

        这里利用`urlparse()`方法对一个URL进行了解析。首先输出解析结果的类型,然后输出结果。运行结果如下:

<class 'urllib.parse.ParseResult'>
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')

        运行后能看到,`urlparse()`方法返回的结果是`ParseResult`类型对象,这个对象包含6个部分,分别为`scheme`、`netloc`、`path`、`params`、`query`和`fragment`。

        以`http://www.baidu.com/index.html;user?id=5#comment`这个URL为例,`urlparse()`方法把它拆成了6个部分。仔细观察会发现,解析URL时存在特定分隔符:`://`前面的内容是`scheme`,代表协议类型;第一个`/`前面的是`netloc`,也就是域名,`/`后面的则是`path`,即访问路径;分号`;`前面的是`params`,用来表示参数;问号`?`后面是`query`查询条件,常见于GET类型URL;井号`#`后面是锚点,能直接定位到页面内部特定位置。

        由此可知,标准URL格式为`scheme://netloc/path;params?query#fragment`,只要是标准URL,都能通过`urlparse()`方法进行拆分。

        除了上述基本解析方式,`urlparse()`方法还有其他配置。下面来看它的API用法:`urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)`,该方法有3个参数:

        - `urlstring`:这是必须填写的参数,就是需要解析的URL。
        - `scheme`:默认协议类型(如`http`、`https`)。当URL中没有协议信息时,就会将此参数值作为默认协议 。

        -`allow_fragments`:指的是是否忽略`fragment`。要是把它设成`False`,`fragment`部分就会被忽略,它会被当成`path`、`parameters`或者`query`的一部分来解析,`fragment`部分就没内容了。 

通过实例来看:

from urllib.parse import urlparse
result = urlparse('www.baidu.com/index.html;user?id=5#comment', scheme='https')
print(result)

运行结果如下:

ParseResult(scheme='https', netloc='', path='www.baidu.com/index.html', params='user', query='id=5', fragment='comment')

        能看到,给的URL开头没有`scheme`信息,但指定了默认的`scheme`参数后,返回结果里的`scheme`就是`https`。

        要是URL本身带有`scheme`,比如这样的代码:

result = urlparse("http://www.baidu.com/index.html;user?id=5#comment", scheme='https')

运行结果会是:

ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5', fragment='comment')

        这说明,`scheme`参数只有在URL里没有`scheme`信息时才起作用。要是URL里有`scheme`信息,就会把解析出来的`scheme`返回。

        `allow_fragments`这个参数决定是否忽略`fragment`。如果把它设成`False`,`fragment`部分就不单独算了,会把它当成`path`、`parameters`或者`query`的一部分,`fragment`部分就没内容了。

下面通过实例来看:

from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html;user?id=5#comment', allow_fragments=False)
print(result)
```
运行结果如下:
```
ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=5#comment', fragment='')

        假设URL中不包含`params`和`query`,再通过实例看一下:

from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html#comment', allow_fragments=False)
print(result)

运行结果如下:

ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html#comment', params='', query='', fragment='')

        可以发现,当URL中不包含`params`和`query`时,`fragment`便会被解析为`path`的一部分。

        返回结果`ParseResult`实际上是一个元组,我们既可以用索引顺序来获取,也可以用属性名获取。示例如下:

from urllib.parse import urlparse
result = urlparse('http://www.baidu.com/index.html#comment', allow_fragments=False)
print(result.scheme, result[0], result.netloc, result[1], sep='\n')

        这里分别用索引和属性名获取了`scheme`和`netloc`,其运行结果如下:

http
http
www.baidu.com
www.baidu.com

可以发现,二者结果一致,两种方法都能成功获取。

2.2 urlunparse()

        有了`urlparse()`,相应地就有了它的反向方法`urlunparse()`。它接受的参数是一个可迭代对象,但它的长度必须是6,否则会抛出参数数量不足或过多的问题。先通过实例来看:

from urllib.parse import urlunparse
data = ['http', 'www.baidu.com', 'index.html', 'user', 'a=6', 'comment']
print(urlunparse(data))

        这里参数`data`使用了列表类型。当然,也可以用其他类型,比如元组或者特定的数据结构。运行结果如下:

http://www.baidu.com/index.html;user?a=6#comment

        这样就成功实现了URL的构造。

2.3 urlsplit()

        这个方法和`urlparse()`方法非常相似,只不过它不再单独解析`params`这一部分,只返回5个结果。上面例子中的`params`会合并到`path`中。示例如下:

from urllib.parse import urlsplit
result = urlsplit('http://www.baidu.com/index.html;user?id=5#comment')
print(result)

运行结果如下:

SplitResult(scheme='http', netloc='www.baidu.com', path='/index.html;user', query='id=5', fragment='comment')

        可以发现,返回结果是`SplitResult`,它其实也是一个元组类型,既可以用属性获取值,也可以用索引来获取。示例如下:

from urllib.parse import urlsplit
result = urlsplit('http://www.baidu.com/index.html;user?id=5#comment')
print(result.scheme, result[0])

运行结果如下:

http
http

2.4 urlunsplit()

        与`urlunparse()`类似,它也是将链接各个部分组合成完整链接的方法,传入的参数也是一个可迭代对象,例如列表、元组等,唯一的区别是长度必须为5。示例如下:

from urllib.parse import urlunsplit
data = ['http', 'www.baidu.com', 'index.html', 'a=6', 'comment']
print(urlunsplit(data))

运行结果如下:
 

http://www.baidu.com/index.html?a=6#comment

2.5 urljoin()

        使用`urlunparse()`和`urlunsplit()`方法,能实现链接的合并。不过,使用这两个方法时,需要有一个特定长度的对象,并且链接的各个部分必须清晰区分开来。

        除了上述两种方法,`urljoin()`也能用来生成链接。使用`urljoin()`方法时,第一个参数是`base_url`(基础链接),第二个参数是新链接。这个方法会分析`base_url`中的`scheme`(协议)、`netloc`(域名)和`path`(路径),若新链接中缺少这些部分,它会用`base_url`中的对应部分进行补充,最后返回生成的链接。

下面通过几个实例来看:

from urllib.parse import urljoin
print(urljoin('http://www.baidu.com', 'FAQ.html'))
print(urljoin('http://www.baidu.com', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html'))
print(urljoin('http://www.baidu.com/about.html', 'https://cuiqingcai.com/FAQ.html?question=2'))
print(urljoin('http://www.baidu.com?wd=abc', "https://cuiqingcai.com/index.php"))
print(urljoin('http://www.baidu.com', "?category=2#comment"))
print(urljoin('www.baidu.com', "?category=2#comment"))
print(urljoin('www.baidu.com#comment', "?category=2"))


运行结果如下:

http://www.baidu.com/FAQ.html
https://cuiqingcai.com/FAQ.html
https://cuiqingcai.com/FAQ.html
https://cuiqingcai.com/FAQ.html?question=2
https://cuiqingcai.com/index.php
http://www.baidu.com?category=2#comment
www.baidu.com?category=2#comment
www.baidu.com?category=2

        可以发现,`base_url`提供了`scheme`、`netloc`和`path`三项内容。如果这三项在新的链接里不存在,就予以补充;如果新的链接存在,就使用新链接的部分。而`base_url`中的`params`、`query`和`fragment`不起作用。

        通过`urljoin()`方法,我们可以轻松实现链接的解析、拼合与生成。

2.6  urlencode()

        这里再介绍一个常用方法——`urlencode()`,它在构造GET请求参数时非常有用。示例如下:

from urllib.parse import urlencode
params = {'name': 'germey', 'age': 22}
base_url = 'http://www.baidu.com?'
url = base_url + urlencode(params)
print(url)

        这里首先声明了一个字典来表示参数,然后调用`urlencode()`方法将其序列化为GET请求参数。运行结果如下:

http://www.baidu.com?name=germey&age=22

        可以看到,参数成功地由字典类型转化为GET请求参数。这个方法非常常用。有时为了更方便地构造参数,我们会事先用字典来表示。要转化为URL的参数时,只需调用该方法即可。

2.7  parse_qs()

        有了序列化,必然就有反序列化。如果我们有一串GET请求参数,利用`parse_qs()`方法,就可以将它转回字典。示例如下:

from urllib.parse import parse_qs
query = 'name=germey&age=22'
print(parse_qs(query))

运行结果如下:

{'name': ['germey'], 'age': ['22']}

        可以看到,这样就成功转回为字典类型了。

2.8 parse_qsl()

        另外,还有一个`parse_qsl()`方法,它用于将参数转化为元组组成的列表。示例如下:

from urllib.parse import parse_qsl
query = 'name=germey&age=22'
print(parse_qsl(query))

运行结果如下:

[('name', 'germey'), ('age', '22')]

        可以看到,运行结果是一个列表,而列表中的每一个元素都是一个元组,元组的第一个内容是参数名,第二个内容是参数值。

2.9 quote()

        该方法可以将内容转化为URL编码的格式。URL中带有中文参数时,有时可能会导致乱码问题,此时用这个方法可以将中文字符转化为URL编码。示例如下:

from urllib.parse import quote
keyword = '壁纸'
url = 'https://www.baidu.com/s?wd=' + quote(keyword)
print(url)

        这里我们声明了一个中文的搜索文字,然后用`quote()`方法对其进行URL编码,最后得到的结果如下:
 

https://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8

2.10 unquote()

        有了`quote()`方法,当然还有`unquote()`方法,它可以进行URL解码。示例如下:

from urllib.parse import unquote
url = 'https://www.baidu.com/s?wd=%E5%A3%81%E7%BA%B8'
print(unquote(url))

        这是上面得到的URL编码后的结果,这里利用`unquote()`方法还原,结果如下:

https://www.baidu.com/s?wd=壁纸

        可以看到,利用`unquote()`方法可以方便地实现解码。

        本节中,我们介绍了`parse`模块的一些常用URL处理方法。有了这些方法,我们可以方便地实现URL的解析和构造,建议熟练掌握。

三、分析网站Robots协议

        借助urllib库的`robotparser`模块,我们能对网站的Robots协议展开分析。在这一节,我们就来简要认识一下这个模块的使用方法。

3.1 Robots协议

        Robots协议又叫爬虫协议、机器人协议,其正式名称是网络爬虫排除标准(Robots Exclusion Protocol)。该协议的作用是告知爬虫和搜索引擎,网站中哪些页面能被抓取,哪些不能被抓取。Robots协议一般以`robots.txt`文本文件的形式存在,并且通常放置在网站的根目录下。

        当搜索爬虫访问某个网站时,会首先查看该网站根目录下有没有`robots.txt`文件。要是有这个文件,搜索爬虫就会依据文件里规定的爬取范围进行页面抓取;要是没找到这个文件,搜索爬虫就会访问网站所有可直接访问的页面 。

        下面我们看一个`robots.txt`的样例:

User-agent: *
Disallow: /
Allow: /public/

        这样设置后,所有搜索爬虫就只能爬取`public`目录了。把上面这些内容保存成`robots.txt`文件,放到网站根目录下,和网站入口文件(像`index.php`、`index.html`、`index.jsp`这类)放在一块儿。

        `User-agent`用来表示搜索爬虫的名称,设置成`*`就意味着这个协议对所有搜索爬虫都有效。例如设置成:

User-agent: Baiduspider

        这就说明设置的规则只对百度爬虫起作用。要是有多个`User-agent`记录,那对应的多个爬虫的爬取行为都会受到限制,不过至少得有一条`User-agent`记录。

        `Disallow`用来指定不允许抓取的目录,比如设置成`/`,就表示所有页面都不能抓取。

        `Allow`一般和`Disallow`搭配使用,很少单独用,它的作用是排除一些限制。这里设置成`/public/`,意思就是除了`public`目录可以抓取,其他页面都不允许抓取。

下面再看几个例子:

- 禁止所有爬虫访问任何目录,代码这么写:

User-agent: *
Disallow: /

- 允许所有爬虫访问任何目录,代码是这样:

User-agent: *
Disallow:

        直接把`robots.txt`文件留空也是可以的。

- 禁止所有爬虫访问网站的某些目录,代码如下:

User-agent: *
Disallow: /private/
Disallow: /tmp/

- 只允许某一个爬虫访问,代码这么设置:

User-agent: WebCrawler
Disallow:
User-agent: *
Disallow: /

        这些都是`robots.txt`文件常见的写法。

3.2 爬虫名称

        大家或许会好奇,爬虫的名字是怎么来的?为啥要叫这些名字呢?其实,爬虫名都是有固定规范的。比如百度的爬虫,就叫`BaiduSpider`。下面这张表,列举了一些常见搜索爬虫的名字,以及它们对应的网站 。

3.3 robotparser

        认识Robots协议后,就能借助`robotparser`模块解析`robots.txt`文件了。`robotparser`模块里有个`RobotFileParser`类,通过它可以依据某网站的`robots.txt`文件,判断某个爬虫有没有权限爬取该网站的网页。

        这个类使用起来很容易,在创建对象时,只要在构造方法中传入`robots.txt`文件的链接就行。它的声明是`urllib.robotparser.RobotFileParser(url='')`。

        要是创建对象时没传入链接,默认链接为空,后续也能使用`seturl()`方法来设置链接。

        下面讲讲这个类常用的几个方法:
        - `seturl()`:专门用来设置`robots.txt`文件的链接。要是创建`RobotFileParser`对象时已经传入了链接,就没必要再用这个方法设置了。
        - `read()`:能读取`robots.txt`文件并进行分析。要注意,这个方法会执行读取和分析操作,如果不调用它,后续的爬取权限判断都会返回`False`,所以务必调用这个方法。该方法不会返回具体内容,但会完成文件读取操作。
        - `parse()`:用于解析`robots.txt`文件,向它传入`robots.txt`文件的某些行内容,它会按照`robots.txt`的语法规则对这些内容进行分析。
        - `can_fetch()`:使用时需传入两个参数,第一个是`User - agent`,第二个是待抓取的URL。这个方法会判断搜索引擎能否抓取该URL,返回结果为`True`或`False`。
        - `mtime()`:返回上次抓取和分析`robots.txt`文件的时间。对于长时间进行分析和抓取操作的搜索爬虫而言,定期检查并抓取最新的`robots.txt`文件十分重要,这个方法就能派上用场。
        - `modified()`:同样对长时间分析和抓取的搜索爬虫很有用,它会把当前时间设置为上次抓取和分析`robots.txt`文件的时间。

下面我们用实例来看一下:

from urllib.robotparser import RobotFileParser
rp = RobotFileParser()
rp.seturl('http://www.jianshu.com/robots.txt')
rp.read()
print(rp.can_fetch('*', 'http://www.jianshu.com/p/b67554025d7d'))
print(rp.can_fetch('*', 'http://www.jianshu.com/search?q=python&page=1&type=collections'))

        这里以简书为例,首先创建`RobotFileParser`对象,然后通过`seturl()`方法设置了`robots.txt`的链接。当然,不用这个方法的话,可以在声明时直接用如下方法设置:

rp = RobotFileParser('http://www.jianshu.com/robots.txt')

        接着利用`can_fetch()`方法判断了网页是否可以被抓取。运行结果如下:

True
False

        这里同样可以使用`parse()`方法执行读取和分析,示例如下:

from urllib.robotparser import RobotFileParser
from urllib.request import urlopen
rp = RobotFileParser()
rp.parse(urlopen('http://www.jianshu.com/robots.txt').read().decode('utf-8').split('\n'))
print(rp.can_fetch('*', 'http://www.jianshu.com/p/b67554025d7d'))
print(rp.can_fetch('*', 'http://www.jianshu.com/search?q=python&page=1&type=collections'))

运行结果一样:

True
False

        到这里,我们介绍了`robotparser`模块的基本使用方法,还举了一些例子。借助这个模块,我们能轻松判断出哪些页面能被抓取,哪些页面不能被抓取。 

参考学习书籍:Python 3网络爬虫开发实战

相关文章:

Python爬虫第5节-urllib的异常处理、链接解析及 Robots 协议分析

目录 一、处理异常 1.1 URLError 1.2 HTTPError 二、解析链接 2.1 urlparse() 2.2 urlunparse() 2.3 urlsplit() 2.4 urlunsplit() 2.5 urljoin() 2.6 urlencode() 2.7 parse_qs() 2.8 parse_qsl() 2.9 quote() 2.10 unquote() 三、分析网站Robots协议 3.1 R…...

STM32——DAC转换

DAC简介 DAC&#xff0c;全称&#xff1a;Digital-to-Analog Converter&#xff0c;扑指数字/模拟转换器 ADC和DAC是模拟电路与数字电路之间的桥梁 DAC的特性参数 1.分辨率&#xff1a; 表示模拟电压的最小增量&#xff0c;常用二进制位数表示&#xff0c;比如&#xff1a…...

因果推断【Causal Inference】(一)

文章目录 1. 什么是因果推断&#xff1f;2. 为什么要提出因果推断&#xff1f;Motivation&#xff1a;辛普森悖论Scenario 1Scenario 2 3. 【Note】相关性≠因果3.1 混淆(Confounding)——共同原因3.2 样本选择偏差(Selection Bias)——共同结果 4. 潜在结果(Potential Outcome…...

人工智能通识速览(Part5. 大语言模型)

五、大语言模型 1.NLP 自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;是人工智能领域的一个重要分支&#xff0c;专注于研究 计算机如何理解、生成和处理人类语言。它的目标是让机器能够像人类一样“读懂”文本或语音&#xff0c;并执 行翻译、问答、摘…...

优化 Django 数据库查询

优化 Django 数据库查询 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 优化 Django 数据库查询**理解 N+1 查询问题****`select_related`:外键的急加载**示例何时使用 `select_re…...

MCP AI:下一代智能微服务控制平台 (.NET Core)

平台概述 MCP AI (Microservice Control Platform AI) 是基于.NET Core构建的下一代智能微服务控制平台&#xff0c;旨在为企业级微服务架构提供智能化、自动化的管理和控制能力。 核心特性 智能服务编排 AI驱动的动态服务路由 自适应负载均衡算法 预测性扩展与收缩 统一…...

计算机网络基础:系列教程汇总

计算机网络基础:系列教程汇总 一、前言二、计算机网络基础概要三、计算机网络基础3.1 计算机网络基础:揭开网络世界的神秘面纱3.2 计算机网络基础:剖析网络的构成要素3.3 计算机网络基础:认识网络拓扑结构3.4 计算机网络基础:解析网络协议3.5 计算机网络基础:了解网络类型…...

互联网三高-高性能之JVM调优

1 运行时数据区 JVM运行时数据区是Java虚拟机管理的内存核心模块&#xff0c;主要分为线程共享和线程私有两部分。 &#xff08;1&#xff09;线程私有 ① 程序计数器&#xff1a;存储当前线程执行字节码指令的地址&#xff0c;用于分支、循环、异常处理等流程控制‌ ② 虚拟机…...

学习比较JVM篇(六):解读GC日志

一、前言 在之前的文章中&#xff0c;我们对JVM的结构、垃圾回收算法、垃圾回收器做了一些列的讲解&#xff0c;同时也使用了JVM自带的命令行工具进行了实际操作。今天我们继续讲解JVM。 我们学习JVM的目的是为了了解JVM&#xff0c;然后优化对应的参数。那么如何了解JVM运行…...

说说你对python的理解,有什么特性?

Python是一种高级、解释型、通用的编程语言&#xff0c;由Guido van Rossum于1991年首次发布。经过30多年的发展&#xff0c;Python已成为最受欢迎的编程语言之一&#xff0c;在Web开发、数据分析、人工智能、自动化运维等多个领域都有广泛应用。 Python的核心特性 1. 简洁优…...

【C语言】编译和链接

一、编译环境和运行环境 在ANSI C的任何一种实现中&#xff0c;存在着两个不同的环境&#xff1a; 1、翻译环境&#xff1a;在翻译环境中&#xff0c;其会通过编译和链接两个大的步骤&#xff0c;其中编译又分为了预处理&#xff08;这 个我们后面还会详细讲解&#x…...

Spark,IDEA编写Maven项目

IDEA中编写Maven项目 1.打开IDEA新建项目 2.选择java语言&#xff0c;构建系统选择Maven 3.IDEA中配置Maven 注&#xff1a;这些文件都是我们老师帮我们在网上找了改动后给我们的&#xff0c;大家可自行在网上查找 编写代码测试HDFS连接 1.在之前创建的pom.xml文件中添加下列…...

【HFP】蓝牙HFP服务层连接与互操作性核心技术研究

目录 一、互操作性设计哲学 二、服务级别连接&#xff08;SLC&#xff09;架构设计 2.1 连接建立流程总览 2.2 核心交互时序图 2.3 关键阶段技术实现 2.4 RFCOMM连接&#xff1a;通信的基石 2.5 特征交换与编解码协商 2.6 指示器状态同步 三、状态同步机制深度优化 3…...

VSCode使用Remote-SSH连接服务器时启动失败glibc不符合

问题 远程主机可能不符合glibc和libstdc VS Code服务器的先决条件 原因 VSCode更新后&#xff0c;如果服务端GLIBC低于v2.28.0版本将不再满足需求 查看服务端GLIBC版本&#xff1a; ~$ ldd --version ldd (Ubuntu GLIBC 2.23-0ubuntu11.3) 2.23解决 下载V1.85版本 下载链…...

InceptionNeXt:When Inception Meets ConvNeXt论文翻译

论文名称&#xff1a;InceptionNeXt:WhenInceptionMeetsConvNeXt 论文地址&#xff1a;https://arxiv.org/pdf/2303.16900.pdf 摘要&#xff1a; 受视觉Transformer(ViTs)长距离建模能力的启发&#xff0c;大核卷积因能扩大感受野、提升模型性能而受到广泛研究与应用&#x…...

windows下,cursor连接MCP服务器

1.下载并安装node 安装后&#xff0c;在cmd命令框中&#xff0c;输入命令node -v可以打印版本号&#xff0c;证明安装完成 2.下载MCP服务器项目 在MCP服务器找到对应项目&#xff0c;这里以server-sequential-thinking为例子 在本地cmd命令窗口&#xff0c;使用下面命令下载…...

从零开始:使用 kubeadm 部署 Kubernetes 集群的详细指南

使用kubeadmin 部署k8s集群 目录 硬件要求 前期准备 Master 检查 API 服务器证书 清理并重新初始化 查 kubeadm 初始化日志 配置 crictl 的 endpoint 硬件要求 主机名 ip 硬件最低要求 建议&#xff0c;跑的块 master 10.1.1.7 2核&#xff0c;2G 内存给个6G node2 …...

rancher 采用ingerss ssl 部署nginx+php项目

rancher 采用ingerss ssl 部署nginxphp项目 一、创建nginx dockerfile&#xff0c;上传到阿里云镜像仓库&#xff08;公有&#xff0c;不需要密码&#xff09; 二、 创建php7.4 dockerfile&#xff0c;需要必须扩展&#xff0c; 上传到阿里云镜像仓库&#xff08;公有&#x…...

开源聚合平台 Websoft9:开源创新已成为中小企业数字化转型、数据驱动企业的基础

引言&#xff1a;开源软件正在重塑企业数字化未来 根据2024年OpenLogic报告&#xff0c;94.57%的企业已使用开源软件&#xff0c;其中34.07%的机构加大了对开源技术的投入。开源软件凭借其灵活性、成本优势和生态协作能力&#xff0c;成为中小企业&#xff08;SMB)数字化转型的…...

IntelliJ IDEA 中通义灵码插件使用指南

IntelliJ IDEA 中通义灵码插件使用指南 通义灵码&#xff08;TONGYI Lingma&#xff09;是阿里云推出的一款基于通义大模型的智能编码辅助工具&#xff0c;支持 IntelliJ IDEA 等主流 IDE。它提供了代码补全、自然语言生成代码、单元测试生成、代码注释与解释等功能&#xff0…...

如何免费使用Meta Llama 4?

周六, Meta发布了全新开源的Llama 4系列模型。 架构介绍查看上篇文章。 作为开源模型,Llama 4存在一个重大限制——庞大的体积。该系列最小的Llama 4 Scout模型就拥有1090亿参数,如此庞大的规模根本无法在本地系统运行。 不过别担心!即使你没有GPU,我们也找到了通过网页…...

introduceHLSL

最近打算好好学习一下ue的shader&#xff0c;跟着下面的视频&#xff0c;打算每天至少更新一集 https://www.youtube.com/watch?vlsXB1PQdGx0&t494s 通过下面的蓝图方式我们就可以得到一个变化的材质 alpha参数的生成实际上就是下面的式子 custom节点允许直接的写入hlsl…...

Module模块化

导出&#xff1a;export关键字 export var color "red"; 重命名导出 在模块中使用as用导出名称表示本地名称。 import { add } from "./05-module-out.js"; 导入&#xff1a; import关键字 导入单个绑定 import { sum } from "./05-module-out.js&…...

使用 Rsync + Lsyncd 实现 CentOS 7 实时文件同步

文章目录 &#x1f300;使用 Rsync Lsyncd 实现 CentOS 7 实时文件同步前言介绍架构图&#x1f9f1;系统环境&#x1f527;Rsync配置&#xff08;两台都需安装&#xff09;关闭SELinux&#xff08;两台都需&#xff09; &#x1f4e6;配置目标端&#xff08;client&#xff09…...

软件工程第三章习题

一、选择题 1. (1)答案&#xff1a;D 解析&#xff1a;可行性研究是对项目在技术、经济、操作等多方面进行全面评估论证&#xff0c;也称为项目论证 。技术可行性研究、操作可行性研究、经济可行性研究只是可行性研究的部分内容&#xff0c;不能涵盖整体概念。 2. (2)答案&…...

基于ElasticSearch的向量检索技术实践

基于ElasticSearch的向量检索技术实践 作者&#xff1a;Tableau 原文地址&#xff1a;https://zhuanlan.zhihu.com/p/620260383 图片、视频、语音、文本等非结构化数据可以通过人工智能技术&#xff08;深度学习算法&#xff09;提取特征向量&#xff0c;然后通过对这些特征向量…...

Spring Boot 项目日志系统全攻略:Logback、Log4j2、Log4j与SLF4J整合指南

Spring Boot 项目日志系统全攻略&#xff1a;Logback、Log4j2、Log4j与SLF4J整合指南 日志系统是应用程序不可或缺的组成部分&#xff0c;良好的日志实践能极大提升开发调试和线上问题排查的效率。本文将全面介绍Spring Boot项目中各种日志框架的配置与使用方案&#xff0c;包…...

【设计模式】责任链模式

简介 很多公司都有请假的流程&#xff0c;当员工提交请假申请时&#xff0c;请求会沿着 组长 → 经理 → CEO 的链条传递&#xff0c;直到有对应层级的领导处理。 适用场景 一个请求需要多个对象中的一个或多个处理&#xff08;如审批流程、过滤器链&#xff09;。处理对象和…...

智能气候前沿:AI Agent结合机器学习与深度学习在全球气候变化驱动因素预测

全球气候变化已成为21世纪最严峻的环境挑战&#xff0c;其复杂的驱动因素如温室气体排放、气溶胶浓度、野火、海冰融化以及农业和生态系统变化等&#xff0c;交织影响着全球的气候格局。 第一&#xff1a;气候变化驱动因素与数据科学基础 1.1气候变化 全球气候变化 中国碳中…...

es 原生linux部署集群

背景 目的&#xff1a; 1. 理解不同部署方式的架构差异 2. 对比环境配置的复杂度 3. 评估性能与资源管理 4. 探索扩展性与高可用性 5. 学习安全与隔离机制 6. 实践监控与维护 7. 掌握混合部署与云原生场景 实验的最终目标 技能提升&#xff1a; 全面掌握Elasticsear…...

Springboot 同时支持不同的数据库,Oracle,Postgresql

## 关键字 Java&#xff0c;Springboot&#xff0c;Vscode&#xff0c;支持多种数据库 ## 背景环境 我在实际项目开发工程中遇到这样一个问题&#xff0c;用户 A 使用 Oracle 数据库&#xff0c;用户 B 使用 Postgresql 数据库&#xff0c;但是用户 AB 都使用我们的项目。所以…...

go --- go run main.go 和 go run .

目录 go run main.gogo run .示例 go run main.go 功能&#xff1a;只编译和运行指定的文件&#xff08;main.go&#xff09;&#xff0c;忽略同目录下的其他文件。适用场景&#xff1a; 当你只需要运行一个独立的文件&#xff0c;且该文件不依赖其他文件时。适合单文件程序或…...

关于Spring MVC中@RequestMapping注解的详细解析,涵盖其核心功能、属性、使用场景及最佳实践

以下是关于Spring MVC中RequestMapping注解的详细解析&#xff0c;涵盖其核心功能、属性、使用场景及最佳实践&#xff1a; 1. 基础概念 RequestMapping是Spring MVC的核心注解&#xff0c;用于将HTTP请求映射到控制器&#xff08;Controller&#xff09;的方法上。它支持类级…...

deepseek使用记录26——从体力异化到脑力异化

我们的一切发现和进步&#xff0c;似乎结果是使物质力量具有理智生命&#xff0c;而人的生命则化为愚钝的物质力量。AI快速发展的现实中&#xff0c;人面临着比工业革命更深刻的异化。在工业革命中&#xff0c;人的身躯沦为了机器的一部分&#xff0c;而现在人的脑袋沦为了AI的…...

Ubertool 的详细介绍、安装指南及使用说明

Ubertool&#xff1a;多协议网络分析与调试平台 一、Ubertool 简介 Ubertool 是一款开源的 多协议网络分析工具&#xff0c;专为物联网&#xff08;IoT&#xff09;、嵌入式系统和工业自动化领域设计。它支持蓝牙、Wi-Fi、LoRa、CAN总线等多种通信协议的实时监控、数据包捕获…...

用 HTML、CSS 和 jQuery 打造多页输入框验证功能

在网页开发中&#xff0c;输入框验证是至关重要的一环&#xff0c;它能确保用户输入的数据符合特定要求&#xff0c;提升交互的准确性与流畅性。今天&#xff0c;我们就来深入剖析一个运用 HTML、CSS 和 jQuery 实现多页输入框验证的精彩实例&#xff0c;带你领略前端开发中表单…...

在CentOS上安装Docker需要注意的事项

文章目录 前言Docker Engine如何设置仓库设置镜像加速器获取镜像加速器地址 写在前面&#xff1a;大家好&#xff01;我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正&#xff0c;感谢大家的不吝赐教。我的唯一博客更新地址是&#xff1a;https://ac-…...

Chrome 135 版本新特性

Chrome 135 版本新特性 一、Chrome 135 版本浏览器更新 ** 1. 第三方托管账户注册迁移到 OIDC 授权码流程** Chrome 135 将账户注册的登录页面从营销网站迁移到动态网站&#xff0c;同时也将 OpenID Connect (OIDC) 的隐式流程迁移到授权码流程。这样做的目的是进一步提升第…...

CMake实战指南一:add_custom_command

CMake 进阶&#xff1a;add_custom_command 用法详解与实战指南 在 CMake 构建系统中&#xff0c;add_custom_command 是一个灵活且强大的工具&#xff0c;允许开发者在构建流程中插入自定义操作。无论是生成中间文件、执行预处理脚本&#xff0c;还是在目标构建前后触发额外逻…...

K8S学习之基础七十五:istio实现灰度发布

istio实现灰度发布 上传镜像到harbor 创建两个版本的pod vi deployment-v1.yaml apiVersion: apps/v1 kind: Deployment metadata:name: appv1labels:app: v1 spec:replicas: 1selector:matchLabels:app: v1apply: canarytemplate:metadata:labels:app: v1apply: canaryspec…...

7-1 列出连通集

作者 陈越 单位 浙江大学 给定一个有 n 个顶点和 m 条边的无向图&#xff0c;请用深度优先遍历&#xff08;DFS&#xff09;和广度优先遍历&#xff08;BFS&#xff09;分别列出其所有的连通集。假设顶点从 0 到 n−1 编号。进行搜索时&#xff0c;假设我们总是从编号最小的顶点…...

XML Schema 指示器

XML Schema 指示器 引言 XML Schema 是一种用于定义 XML 文档结构的语言,它能够确保 XML 文档的合法性。在 XML 文档的解析和应用中,XML Schema 指示器(XML Schema Indicator)扮演着至关重要的角色。本文将详细介绍 XML Schema 指示器的概念、作用、应用场景以及如何使用…...

Linux内核中TCP协议栈的实现:tcp_close函数的深度剖析

引言 TCP(传输控制协议)作为互联网协议族中的核心协议之一,负责在不可靠的网络层之上提供可靠的、面向连接的字节流服务。Linux内核中的TCP协议栈实现了TCP协议的全部功能,包括连接建立、数据传输、流量控制、拥塞控制以及连接关闭等。本文将深入分析Linux内核中tcp_close…...

17-产品经理-创建发布

点击“发布”-“创建发布”。 填写发布名称&#xff0c;选择测试的版本。还可以设置此次发布是否为“里程碑”。 点击“保存”后&#xff0c;进入该发布详情页面。需要为此次发布关联需求、已解决BUG、以及遗留BUG。可以通过设置条件&#xff0c;进行“搜索”&#xff0c;然后批…...

了解Spring的统一功能

目录 一、统一数据返回格式 1.引入统一数据返回格式 2.学习使用统一数据返回格式 support方法 beforeBodyWrite方法 统一数据返回格式具体逻辑 使用统一数据返回格式存在的问题 解决方法&#xff1a; 统一数据返回格式的优点 统一数据返回格式代码实现&#xff08;包含了…...

123213

根据道路在道路网的地位、交通功能、对沿线的服务功能划分可分为快速路、主干路、次干路及支路 快速路完全为交通功能服务, 主干路以交通功能为主, 次干路是城市区域性的交通干道&#xff0c;为区域交通集散服务&#xff0c;兼有服务功能&#xff0c;结合主干路组成干路网 …...

通过 axios 请求回来的 HTML 字符串渲染到 Vue 界面上并添加样式

1. 通过 axios 获取数据 使用 axios 发起请求&#xff0c;获取返回的 HTML 字符串数据。 2. 在 Vue 中处理和渲染数据 由于 HTML 字符串中可能包含一些标签和样式&#xff0c;直接插入到 Vue 的模板中可能会导致样式问题。可以通过以下方式处理&#xff1a; 方法一&#xf…...

P1162 填涂颜色(BFS)

题目描述 由数字 0 组成的方阵中&#xff0c;有一任意形状的由数字 1 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 2。例如&#xff1a;66 的方阵&#xff08;n6&#xff09;&#xff0c;涂色前和涂色后的方阵如下&#xff1a; 如果从某个 0 出发&#xff0c;只向上下…...

【笔记】VS中C#类库项目引用另一个类库项目的方法

VS中C#类库项目引用另一个类库项目的方法 在 C# 开发中&#xff0c;有时我们需要在一个类库项目中引用另一个类库项目&#xff0c;但另一个项目可能尚未编译成 DLL。在这种情况下&#xff0c;我们仍然可以通过 Visual Studio 提供的项目引用功能进行依赖管理。 &#x1f3af; …...

进程内存分布--之smaps呈现memory-layout.cpp内存分布

上一篇介绍了&#xff1a;进程内存分布--之单线程代码来内存分布呈现memory-layout.cpp 这里我们使用smaps将更加形象的的体现内存分布&#xff0c;smaps文件是Linux的proc文件系统提供的一种可以查看内存资源使用情况的方法,Linux系统中运行的库、堆、栈等信息都可在smaps中查…...