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,全称:Digital-to-Analog Converter,扑指数字/模拟转换器 ADC和DAC是模拟电路与数字电路之间的桥梁 DAC的特性参数 1.分辨率: 表示模拟电压的最小增量,常用二进制位数表示,比如:…...
因果推断【Causal Inference】(一)
文章目录 1. 什么是因果推断?2. 为什么要提出因果推断?Motivation:辛普森悖论Scenario 1Scenario 2 3. 【Note】相关性≠因果3.1 混淆(Confounding)——共同原因3.2 样本选择偏差(Selection Bias)——共同结果 4. 潜在结果(Potential Outcome…...
人工智能通识速览(Part5. 大语言模型)
五、大语言模型 1.NLP 自然语言处理(Natural Language Processing, NLP)是人工智能领域的一个重要分支,专注于研究 计算机如何理解、生成和处理人类语言。它的目标是让机器能够像人类一样“读懂”文本或语音,并执 行翻译、问答、摘…...
优化 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构建的下一代智能微服务控制平台,旨在为企业级微服务架构提供智能化、自动化的管理和控制能力。 核心特性 智能服务编排 AI驱动的动态服务路由 自适应负载均衡算法 预测性扩展与收缩 统一…...
计算机网络基础:系列教程汇总
计算机网络基础:系列教程汇总 一、前言二、计算机网络基础概要三、计算机网络基础3.1 计算机网络基础:揭开网络世界的神秘面纱3.2 计算机网络基础:剖析网络的构成要素3.3 计算机网络基础:认识网络拓扑结构3.4 计算机网络基础:解析网络协议3.5 计算机网络基础:了解网络类型…...
互联网三高-高性能之JVM调优
1 运行时数据区 JVM运行时数据区是Java虚拟机管理的内存核心模块,主要分为线程共享和线程私有两部分。 (1)线程私有 ① 程序计数器:存储当前线程执行字节码指令的地址,用于分支、循环、异常处理等流程控制 ② 虚拟机…...
学习比较JVM篇(六):解读GC日志
一、前言 在之前的文章中,我们对JVM的结构、垃圾回收算法、垃圾回收器做了一些列的讲解,同时也使用了JVM自带的命令行工具进行了实际操作。今天我们继续讲解JVM。 我们学习JVM的目的是为了了解JVM,然后优化对应的参数。那么如何了解JVM运行…...
说说你对python的理解,有什么特性?
Python是一种高级、解释型、通用的编程语言,由Guido van Rossum于1991年首次发布。经过30多年的发展,Python已成为最受欢迎的编程语言之一,在Web开发、数据分析、人工智能、自动化运维等多个领域都有广泛应用。 Python的核心特性 1. 简洁优…...
【C语言】编译和链接
一、编译环境和运行环境 在ANSI C的任何一种实现中,存在着两个不同的环境: 1、翻译环境:在翻译环境中,其会通过编译和链接两个大的步骤,其中编译又分为了预处理(这 个我们后面还会详细讲解&#x…...
Spark,IDEA编写Maven项目
IDEA中编写Maven项目 1.打开IDEA新建项目 2.选择java语言,构建系统选择Maven 3.IDEA中配置Maven 注:这些文件都是我们老师帮我们在网上找了改动后给我们的,大家可自行在网上查找 编写代码测试HDFS连接 1.在之前创建的pom.xml文件中添加下列…...
【HFP】蓝牙HFP服务层连接与互操作性核心技术研究
目录 一、互操作性设计哲学 二、服务级别连接(SLC)架构设计 2.1 连接建立流程总览 2.2 核心交互时序图 2.3 关键阶段技术实现 2.4 RFCOMM连接:通信的基石 2.5 特征交换与编解码协商 2.6 指示器状态同步 三、状态同步机制深度优化 3…...
VSCode使用Remote-SSH连接服务器时启动失败glibc不符合
问题 远程主机可能不符合glibc和libstdc VS Code服务器的先决条件 原因 VSCode更新后,如果服务端GLIBC低于v2.28.0版本将不再满足需求 查看服务端GLIBC版本: ~$ ldd --version ldd (Ubuntu GLIBC 2.23-0ubuntu11.3) 2.23解决 下载V1.85版本 下载链…...
InceptionNeXt:When Inception Meets ConvNeXt论文翻译
论文名称:InceptionNeXt:WhenInceptionMeetsConvNeXt 论文地址:https://arxiv.org/pdf/2303.16900.pdf 摘要: 受视觉Transformer(ViTs)长距离建模能力的启发,大核卷积因能扩大感受野、提升模型性能而受到广泛研究与应用&#x…...
windows下,cursor连接MCP服务器
1.下载并安装node 安装后,在cmd命令框中,输入命令node -v可以打印版本号,证明安装完成 2.下载MCP服务器项目 在MCP服务器找到对应项目,这里以server-sequential-thinking为例子 在本地cmd命令窗口,使用下面命令下载…...
从零开始:使用 kubeadm 部署 Kubernetes 集群的详细指南
使用kubeadmin 部署k8s集群 目录 硬件要求 前期准备 Master 检查 API 服务器证书 清理并重新初始化 查 kubeadm 初始化日志 配置 crictl 的 endpoint 硬件要求 主机名 ip 硬件最低要求 建议,跑的块 master 10.1.1.7 2核,2G 内存给个6G node2 …...
rancher 采用ingerss ssl 部署nginx+php项目
rancher 采用ingerss ssl 部署nginxphp项目 一、创建nginx dockerfile,上传到阿里云镜像仓库(公有,不需要密码) 二、 创建php7.4 dockerfile,需要必须扩展, 上传到阿里云镜像仓库(公有&#x…...
开源聚合平台 Websoft9:开源创新已成为中小企业数字化转型、数据驱动企业的基础
引言:开源软件正在重塑企业数字化未来 根据2024年OpenLogic报告,94.57%的企业已使用开源软件,其中34.07%的机构加大了对开源技术的投入。开源软件凭借其灵活性、成本优势和生态协作能力,成为中小企业(SMB)数字化转型的…...
IntelliJ IDEA 中通义灵码插件使用指南
IntelliJ IDEA 中通义灵码插件使用指南 通义灵码(TONGYI Lingma)是阿里云推出的一款基于通义大模型的智能编码辅助工具,支持 IntelliJ IDEA 等主流 IDE。它提供了代码补全、自然语言生成代码、单元测试生成、代码注释与解释等功能࿰…...
如何免费使用Meta Llama 4?
周六, Meta发布了全新开源的Llama 4系列模型。 架构介绍查看上篇文章。 作为开源模型,Llama 4存在一个重大限制——庞大的体积。该系列最小的Llama 4 Scout模型就拥有1090亿参数,如此庞大的规模根本无法在本地系统运行。 不过别担心!即使你没有GPU,我们也找到了通过网页…...
introduceHLSL
最近打算好好学习一下ue的shader,跟着下面的视频,打算每天至少更新一集 https://www.youtube.com/watch?vlsXB1PQdGx0&t494s 通过下面的蓝图方式我们就可以得到一个变化的材质 alpha参数的生成实际上就是下面的式子 custom节点允许直接的写入hlsl…...
Module模块化
导出:export关键字 export var color "red"; 重命名导出 在模块中使用as用导出名称表示本地名称。 import { add } from "./05-module-out.js"; 导入: import关键字 导入单个绑定 import { sum } from "./05-module-out.js&…...
使用 Rsync + Lsyncd 实现 CentOS 7 实时文件同步
文章目录 🌀使用 Rsync Lsyncd 实现 CentOS 7 实时文件同步前言介绍架构图🧱系统环境🔧Rsync配置(两台都需安装)关闭SELinux(两台都需) 📦配置目标端(client)…...
软件工程第三章习题
一、选择题 1. (1)答案:D 解析:可行性研究是对项目在技术、经济、操作等多方面进行全面评估论证,也称为项目论证 。技术可行性研究、操作可行性研究、经济可行性研究只是可行性研究的部分内容,不能涵盖整体概念。 2. (2)答案&…...
基于ElasticSearch的向量检索技术实践
基于ElasticSearch的向量检索技术实践 作者:Tableau 原文地址:https://zhuanlan.zhihu.com/p/620260383 图片、视频、语音、文本等非结构化数据可以通过人工智能技术(深度学习算法)提取特征向量,然后通过对这些特征向量…...
Spring Boot 项目日志系统全攻略:Logback、Log4j2、Log4j与SLF4J整合指南
Spring Boot 项目日志系统全攻略:Logback、Log4j2、Log4j与SLF4J整合指南 日志系统是应用程序不可或缺的组成部分,良好的日志实践能极大提升开发调试和线上问题排查的效率。本文将全面介绍Spring Boot项目中各种日志框架的配置与使用方案,包…...
【设计模式】责任链模式
简介 很多公司都有请假的流程,当员工提交请假申请时,请求会沿着 组长 → 经理 → CEO 的链条传递,直到有对应层级的领导处理。 适用场景 一个请求需要多个对象中的一个或多个处理(如审批流程、过滤器链)。处理对象和…...
智能气候前沿:AI Agent结合机器学习与深度学习在全球气候变化驱动因素预测
全球气候变化已成为21世纪最严峻的环境挑战,其复杂的驱动因素如温室气体排放、气溶胶浓度、野火、海冰融化以及农业和生态系统变化等,交织影响着全球的气候格局。 第一:气候变化驱动因素与数据科学基础 1.1气候变化 全球气候变化 中国碳中…...
es 原生linux部署集群
背景 目的: 1. 理解不同部署方式的架构差异 2. 对比环境配置的复杂度 3. 评估性能与资源管理 4. 探索扩展性与高可用性 5. 学习安全与隔离机制 6. 实践监控与维护 7. 掌握混合部署与云原生场景 实验的最终目标 技能提升: 全面掌握Elasticsear…...
Springboot 同时支持不同的数据库,Oracle,Postgresql
## 关键字 Java,Springboot,Vscode,支持多种数据库 ## 背景环境 我在实际项目开发工程中遇到这样一个问题,用户 A 使用 Oracle 数据库,用户 B 使用 Postgresql 数据库,但是用户 AB 都使用我们的项目。所以…...
go --- go run main.go 和 go run .
目录 go run main.gogo run .示例 go run main.go 功能:只编译和运行指定的文件(main.go),忽略同目录下的其他文件。适用场景: 当你只需要运行一个独立的文件,且该文件不依赖其他文件时。适合单文件程序或…...
关于Spring MVC中@RequestMapping注解的详细解析,涵盖其核心功能、属性、使用场景及最佳实践
以下是关于Spring MVC中RequestMapping注解的详细解析,涵盖其核心功能、属性、使用场景及最佳实践: 1. 基础概念 RequestMapping是Spring MVC的核心注解,用于将HTTP请求映射到控制器(Controller)的方法上。它支持类级…...
deepseek使用记录26——从体力异化到脑力异化
我们的一切发现和进步,似乎结果是使物质力量具有理智生命,而人的生命则化为愚钝的物质力量。AI快速发展的现实中,人面临着比工业革命更深刻的异化。在工业革命中,人的身躯沦为了机器的一部分,而现在人的脑袋沦为了AI的…...
Ubertool 的详细介绍、安装指南及使用说明
Ubertool:多协议网络分析与调试平台 一、Ubertool 简介 Ubertool 是一款开源的 多协议网络分析工具,专为物联网(IoT)、嵌入式系统和工业自动化领域设计。它支持蓝牙、Wi-Fi、LoRa、CAN总线等多种通信协议的实时监控、数据包捕获…...
用 HTML、CSS 和 jQuery 打造多页输入框验证功能
在网页开发中,输入框验证是至关重要的一环,它能确保用户输入的数据符合特定要求,提升交互的准确性与流畅性。今天,我们就来深入剖析一个运用 HTML、CSS 和 jQuery 实现多页输入框验证的精彩实例,带你领略前端开发中表单…...
在CentOS上安装Docker需要注意的事项
文章目录 前言Docker Engine如何设置仓库设置镜像加速器获取镜像加速器地址 写在前面:大家好!我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https://ac-…...
Chrome 135 版本新特性
Chrome 135 版本新特性 一、Chrome 135 版本浏览器更新 ** 1. 第三方托管账户注册迁移到 OIDC 授权码流程** Chrome 135 将账户注册的登录页面从营销网站迁移到动态网站,同时也将 OpenID Connect (OIDC) 的隐式流程迁移到授权码流程。这样做的目的是进一步提升第…...
CMake实战指南一:add_custom_command
CMake 进阶:add_custom_command 用法详解与实战指南 在 CMake 构建系统中,add_custom_command 是一个灵活且强大的工具,允许开发者在构建流程中插入自定义操作。无论是生成中间文件、执行预处理脚本,还是在目标构建前后触发额外逻…...
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 条边的无向图,请用深度优先遍历(DFS)和广度优先遍历(BFS)分别列出其所有的连通集。假设顶点从 0 到 n−1 编号。进行搜索时,假设我们总是从编号最小的顶点…...
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-产品经理-创建发布
点击“发布”-“创建发布”。 填写发布名称,选择测试的版本。还可以设置此次发布是否为“里程碑”。 点击“保存”后,进入该发布详情页面。需要为此次发布关联需求、已解决BUG、以及遗留BUG。可以通过设置条件,进行“搜索”,然后批…...
了解Spring的统一功能
目录 一、统一数据返回格式 1.引入统一数据返回格式 2.学习使用统一数据返回格式 support方法 beforeBodyWrite方法 统一数据返回格式具体逻辑 使用统一数据返回格式存在的问题 解决方法: 统一数据返回格式的优点 统一数据返回格式代码实现(包含了…...
123213
根据道路在道路网的地位、交通功能、对沿线的服务功能划分可分为快速路、主干路、次干路及支路 快速路完全为交通功能服务, 主干路以交通功能为主, 次干路是城市区域性的交通干道,为区域交通集散服务,兼有服务功能,结合主干路组成干路网 …...
通过 axios 请求回来的 HTML 字符串渲染到 Vue 界面上并添加样式
1. 通过 axios 获取数据 使用 axios 发起请求,获取返回的 HTML 字符串数据。 2. 在 Vue 中处理和渲染数据 由于 HTML 字符串中可能包含一些标签和样式,直接插入到 Vue 的模板中可能会导致样式问题。可以通过以下方式处理: 方法一…...
P1162 填涂颜色(BFS)
题目描述 由数字 0 组成的方阵中,有一任意形状的由数字 1 构成的闭合圈。现要求把闭合圈内的所有空间都填写成 2。例如:66 的方阵(n6),涂色前和涂色后的方阵如下: 如果从某个 0 出发,只向上下…...
【笔记】VS中C#类库项目引用另一个类库项目的方法
VS中C#类库项目引用另一个类库项目的方法 在 C# 开发中,有时我们需要在一个类库项目中引用另一个类库项目,但另一个项目可能尚未编译成 DLL。在这种情况下,我们仍然可以通过 Visual Studio 提供的项目引用功能进行依赖管理。 🎯 …...
进程内存分布--之smaps呈现memory-layout.cpp内存分布
上一篇介绍了:进程内存分布--之单线程代码来内存分布呈现memory-layout.cpp 这里我们使用smaps将更加形象的的体现内存分布,smaps文件是Linux的proc文件系统提供的一种可以查看内存资源使用情况的方法,Linux系统中运行的库、堆、栈等信息都可在smaps中查…...