爬虫基本库的使用(urllib库的详细解析)

        学习爬虫,其基本的操作便是模拟浏览器向服务器发出请求,那么我们需要从哪个地方做起呢?请求需要我们自己构造吗? 我们需要关心请求这个数据结构怎么实现吗? 需要了解 HTTP、TCP、IP层的网络传输通信吗? 需要知道服务器如何响应以及响应的原理吗?

        可能你无从下手,不过不用担心,Python的强大之处就是提供了功能齐全的类库来帮助我们实现这些需求。最基础的 HTTP 库有 urllib、requests、httpx等。(由于篇幅限制,本帖只讲解urllib库,Request和httpx后续会陆续更新)

        拿 urllib 这个库来说,有了它,我们只需要关心请求的链接是什么,需要传递的参数是什么,以及如何设置可选的请求头,而无须深入到底层去了解到底是怎样传输和通信的。有了 urllib库,只用两行代码就可以完成一次请求和响应的处理过程,得到网页内容,是不是感觉方便极了?

目录

urllib的使用

1、发送请求

(1) urlopen

(2)Request

2、异常处理

3、解析链接

(1)urlparse

(2)urlunparse

(3)urlsplit

(4)urlunsplit

4、分析Robots协议

(1) Robots 协议

(2) robotparser


urllib的使用

        首先介绍一个 Python库,叫作urllib,利用它就可以实现HTTP请求的发送,而且不需要关心 HTTP 协议本身甚至更底层的实现,我们要做的是指定请求的 URL、请求头、请求体等信息。此外urllib还可以把服务器返回的响应转化为Python 对象,我们通过该对象便可以方便地获取响应的相关信息,如响应状态码、响应头、响应体等。

注意 :在Python 2 中, 有urllib和 urllib2两个库来实现 HTTP 请求的发送。 而在Python 3 中, urllib2库已经不存在了,统一为了 urllib。

        首先,我们了解一下 urllib库的使用方法,它是 Python 内置的 HTTP 请求库,也就是说不需要额外安装,可直接使用。urllib 库包含如下4 个模块。

  •  request:这是最基本的 HTTP 请求模块,可以模拟请求的发送。就像在浏览器里输入网址然后按下回车一样,只需要给库方法传入 URL 以及额外的参数,就可以模拟实现发送请求的过程了。
  • error:异常处理模块。如果出现请求异常,那么我们可以捕获这些异常,然后进行重试或其他操作以保证程序运行不会意外终止。
  • parse:一个工具模块。提供了许多URL 的处理方法,例如拆分、解析、合并等。
  • robotparser: 主要用来识别网站的 robots. txt文件, 然后判断哪些网站可以爬, 哪些网站不可以,它其实用得比较少。

1、发送请求

        使用urllib库的 request模块,可以方便地发送请求并得到响应。urllib. request模块提供了最基本的构造 HTTP请求的方法,利用这个模块可以模拟浏览器的请求发起过程, 同时它还具有处理授权验证(Authentication )、重定向(Redirection)、浏览器Cookie 以及其他一些功能。

(1) urlopen

下面以百度为例,抓取该网页:

import urllib.request
url = 'https://www.baidu.com'
response = urllib.request.urlopen(url)
# 获取网页源代码
print("网页源代码:")
print(response.read().decode('utf-8'))
# 获取响应状态码
print("响应状态码:")
print(response.status)
# 获取响应头
print("响应头:")
print(response.getheaders())

运行结果:

网页源代码:
<html>
<head><script>location.replace(location.href.replace("https://","http://"));</script>
</head>
<body><noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>
响应状态码:
200
响应头:
[('Accept-Ranges', 'bytes'), ('Cache-Control', 'no-cache'), ('Content-Length', '227'), ('Content-Security-Policy', "frame-ancestors 'self' https://chat.baidu.com http://mirror-chat.baidu.com https://fj-chat.baidu.com https://hba-chat.baidu.com https://hbe-chat.baidu.com https://njjs-chat.baidu.com https://nj-chat.baidu.com https://hna-chat.baidu.com https://hnb-chat.baidu.com http://debug.baidu-int.com;"), ('Content-Type', 'text/html'), ('Date', 'Tue, 20 Feb 2024 02:54:13 GMT'), ('P3p', 'CP=" OTI DSP COR IVA OUR IND COM "'), ('P3p', 'CP=" OTI DSP COR IVA OUR IND COM "'), ('Pragma', 'no-cache'), ('Server', 'BWS/1.1'), ('Set-Cookie', 'BD_NOT_HTTPS=1; path=/; Max-Age=300'), ('Set-Cookie', 'BIDUPSID=30561DE24C7F0F5FF9E66FE3886A5240; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com'), ('Set-Cookie', 'PSTM=1708397653; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com'), ('Set-Cookie', 'BAIDUID=30561DE24C7F0F5FFA6A431818DB782D:FG=1; max-age=31536000; expires=Wed, 19-Feb-25 02:54:13 GMT; domain=.baidu.com; path=/; version=1; comment=bd'), ('Traceid', '1708397653049913601018294765874260519959'), ('X-Ua-Compatible', 'IE=Edge,chrome=1'), ('X-Xss-Protection', '1;mode=block'), ('Connection', 'close')]

        使用urloen方法已经可以完成对简单网页的GET请求抓取,该方法的API为:

urllib. request.urlopen(url, data=None, [timeout,]*, cafile=None, capath=None, cadefault=False, context=None)

        可以发现,除了第一个参数用于传递URL 之外,我们还可以传递其他内容,例如 data(附加数据)、timeout (超时时间) 等。接下来就详细说明一下 urlopen 方法中几个参数的用法。

  • data 参数

        data参数是可选的。在添加该参数时,需要使用bytes方法将参数转化为字节流编码格式的内容,即bytes类型。另外,如果传递了这个参数,那么它的请求方式就不再是 GET,而是 POST了。

  • timeout 参数 

        timeout 参数用于设置超时时间,单位为秒,意思是如果请求超出了设置的这个时间,还没有得到响应,就会抛出异常。如果不指定该参数,则会使用全局默认时间。这个参数支持HTTP、HTTPS、FTP 请求。 

  •  其他参数

        除了 data 参数和 timeout 参数, urlopen方法还有 context参数,该参数必须是 ss1. SSLContext类型,用来指定 SSL的设置。此外, cafile和 capath 这两个参数分别用来指定 CA证书和其路径, 这两个在请求 HTTPS 链接时会有用。cadefault参数现在已经弃用了, 其默认值为 False。

        至此,我们讲解了 urlopen 方法的用法,通过这个最基本的方法,就可以完成简单的请求和网页抓取。

(2)Request

        利用urlopen方法可以发起最基本的请求,但它那几个简单的参数并不足以构建一个完整的请求。如果需要往请求中加入Headers等信息,就得利用更强大的 Request 类来构建请求了。

        首先,我们用实例感受一下 Request 类的用法:

import urllib. request
request= urllib.request.Request(' https://python.org')
response = urllib. request. urlopen(request)
print(response. read(). decode('utf-8'))

        可以发现,我们依然是用urlopen方法来发送请求,只不过这次该方法的参数不再是 URL,而是一个Request 类型的对象。通过构造这个数据结构,一方面可以将请求独立成一个对象,另一方面可更加丰富和灵活地配置参数。

        下面我们看一下可以通过怎样的参数来构造 Request 类,构造方法如下:

class urllib. request. Request(url, data=None, headers={},
origin req host=None, unverifiable=False, method=None)
  •  第一个参数url用于请求 URL,这是必传参数,其他的都是可选参数。
  • 第二个参数data如果要传数据,必须传bytes类型的。如果数据是字典,可以先用urllib. parse 模块里的 urlencode方法进行编码。
  • 第三个参数 headers 是一个字典,这就是请求头,我们在构造请求时,既可以通过 headers 参数直接构造此项,也可以通过调用请求实例的 add header方法添加。
  • 添加请求头最常见的方法就是通过修改 User-Agent 来伪装浏览器。默认的 User-Agent 是Python-urllib,我们可以通过修改这个值来伪装浏览器。例如要伪装火狐浏览器,就可以把User-Agent 设置为:Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11
  • 第四个参数origin req host指的是请求方的 host 名称或者 IP 地址。
  • 第五个参数 unverifiable表示请求是否是无法验证的,默认取值是 False,意思是用户没有足够的权限来接收这个请求的结果。例如,请求一个HTML 文档中的图片,但是没有自动抓取图像的权限,这时unverifiable 的值就是 True。
  • 第六个参数method是一个字符串,用来指示请求使用的方法,例如GET、POST和 PUT等。

下面我们传入多个参数尝试构建 Request 类: 

from urllib import request, parse
url = 'https://www.httpbin.org/post'
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)',
'Host': '  www.httpbin.org'
}
dict = {'name': 'germey'}
data = bytes(parse. urlencode(dict), encoding='utf-8')
req = request. Request(url=url, data=data, headers=headers, method='POST')
response = request. urlopen(req)
print(response. read(). decode('utf-8'))

 运行结果:

{"args": {}, "data": "", "files": {}, "form": {"name": "germey"}, "headers": {"Accept-Encoding": "identity", "Content-Length": "11", "Content-Type": "application/x-www-form-urlencoded", "Host": "www.httpbin.org", "User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)", "X-Amzn-Trace-Id": "Root=1-65d41be7-0337942e592a7e7a53c9107b"}, "json": null, "origin": "118.212.215.166", "url": "https://www.httpbin.org/post"
}

        观察结果可以发现, 我们成功设置了 data、headers 和 method。

        通过 add header方法添加 headers 的方式如下:

req = request. Request(url=url, data=data, method='POST')
req  add header('User Agent', 'Mozilla/4 0(compatible; MSIE 5 5; Windows NT)')

        有了 Request类,我们就可以更加方便地构建请求,并实现请求的发送啦。

2、异常处理

        我们已经了解了如何发送请求,但是在网络不好的情况下,如果出现了异常,该怎么办呢? 这时要是不处理这些异常,程序很可能会因为报错而终止运行,所以异常处理还是十分有必要的。

        urllib库中的 error模块定义了由 request模块产生的异常。当出现问题时, request模块便会抛出 error模块中定义的异常。

  •  URLError

        URLError类来自 urllib库的 error模块,继承自OSError类,是error异常模块的基类, 由 request 模块产生的异常都可以通过捕获这个类来处理。它具有一个属性reason,即返回错误的原因。

下面用一个实例来看一下:

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

我们打开了一个不存在的页面,照理来说应该会报错,但是我们捕获了 URLError这个异常。

运行结果如下:

Not Found

程序没有直接报错,而是输出了错误原因,这样可以避免程序异常终止,同时异常得到了有效处理。

  • HTTPError

        HTTPError是URLError的子类,专门用来处理HTTP请求错误,例如认证请求失败等。它有如下3个属性。

  •  code:返回HTTP状态码,例如404表示网页不存在,500表示服务器内部错误等。
  • reason:同父类一样,用于返回错误的原因。
  • headers: 返回请求头。

下面我们用几个实例来看看:

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

运行结果如下: 

Not Found
404
Server: GitHub.com
Content-Type: text/html; charset=utf-8
Access-Control-Allow-Origin: *
ETag: "64d39a40-24a3"
Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; img-src data:; connect-src 'self'
x-proxy-cache: MISS
X-GitHub-Request-Id: C988:38DF71:2CD1E:3F291:65D4231A
Accept-Ranges: bytes
Date: Tue, 20 Feb 2024 03:57:15 GMT
Via: 1.1 varnish
Age: 0
X-Served-By: cache-icn1450083-ICN
X-Cache: MISS
X-Cache-Hits: 0
X-Timer: S1708401435.117679,VS0,VE185
Vary: Accept-Encoding
X-Fastly-Request-ID: ebbb650d9a42388fbffef33aa8977ba03d9fd797
X-Cache-Lookup: Cache Miss
Content-Length: 9379
X-NWS-LOG-UUID: 15553444116395185930
Connection: close
X-Cache-Lookup: Cache Miss

        依然是打开同样的网址, 这里捕获了 HTTPError异常, 输出了 reason、code 和 headers 属性。

        因为 URLError 是 HTTPError的父类,所以可以先选择捕获子类的错误,再捕获父类的错误。上述代码的更好写法如下:

from urllib import request, error
try:
response = request.urlopen('    https://cuiqingcai.com/404')
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,获取它的错误原因、状态码、请求头等信息。如果不是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 'TimeoutError'>
TIME OUT

        reason属性的结果是socket.timeout类。所以这里可以用isinstance方法来判断它的类型,做出更详细的异常判断。

3、解析链接

        前面说过,urllib库里还提供了 parse 模块,这个模块定义了处理URL的标准接口,例如实现URL 各部分的抽取、合并以及链接转换。它支持如下协议的 URL处理: file、ftp、gopher、hdl  、http、imap、 mailto、 mms、 news、 nntp、 prospero、 rsync、 rtsp、 rtspu、 sftp、 sip、 sips、 snews、 svn、 svn+ssh、telnet 和 wais。

        下面我们将介绍parse 模块中的常用方法,看一下它的便捷之处。

(1)urlparse

        该方法可以实现URL的识别和分段,这里先用一个实例来看一下:

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

        这里我们利用urlparse方法对一个 URL进行了解析,然后输出了解析结果的类型以及结果本身。

运行结果如下:

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

        可以看到,解析结果是一个ParseResult类型的对象, 包含6部分,分别是scheme、netloc、path、params、 query和 fragment。再观察一下上述实例中的 URL:

https://www.baidu.com/index.html;user?id=5   #comment

        可以发现, urlparse 方法在解析 URL 时有特定的分隔符。例如:// 前面的内容就是 scheme, 代表协议。第一个/ 符号前面便是 netloc, 即域名; 后面是path, 即访问路径。分号;后面是 params,代表参数。问号?后面是查询条件 query, 一般用作 GET 类型的 URL。井号#后面是锚点 fragment,用于直接定位页面内部的下拉位置。

        于是可以得出一个标准的链接格式,具体如下:

scheme://netloc/path;params? query#fragment

        一个标准的URL 都会符合这个规则,利用urlparse方法就可以将它拆分开来。除了这种最基本的解析方式外,urlparse方法还有其他配置吗? 接下来,看一下它的 API用法:

urllib. parse. urlparse(urlstring, scheme='', allow fragments=True)

        可以看到, urlparse 方法有3 个参数。

  •  urlstring: 这是必填项, 即待解析的 URL。
  • scheme: 这是默认的协议(例如 http 或https等)。如果待解析的 URL 没有带协议信息, 就会将这个作为默认协议。我们用实例来看一下:
from urllib. parse import urlparseresult = 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 参数,返回了结果 https。

        假设带上协议信息:

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中不包含协议信息的时候才生效。如果URL中有,就会返回解析出的 scheme。

  •  allow fragments: 是否忽略 fragment。如果此项被设置为 False, 那么 fragment 部分就会被忽略, 它会被解析为 path、params 或者 query的一部分, 而 fragment 部分为空。

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

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

运行结果如下:

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

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

from urllib. parse import urlparseresult = urlparse('https://www.baidu.com/index.html#comment', allow fragments=False)print(result)

运行结果如下:

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

        可以发现, 此时 fragment 会被解析为 path的一部分。返回结果 ParseResult 实际上是一个元组,既可以用属性名获取其内容,也可以用索引来顺序获取。

实例如下:

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

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

https
https
www.baidu.com
www.baidu.com

可以发现,两种获取方式都可以成功获取,且结果是一致的。

(2)urlunparse

        有了 urlparse 方法, 相应就会有它的对立方法urlunparse, 用于构造 URL。这个方法接收的参数是一个可迭代对象,其长度必须是 6,否则会抛出参数数量不足或者过多的问题。先用一个实例看一下:

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

运行结果如下:

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

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

(3)urlsplit

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

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

运行结果如下:

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

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

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

运行结果如下:

https https

(4)urlunsplit

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

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

运行结果如下:

https://www.baidu.com/index.html?a=6#commenturljoin

        urlunparse和 urlunsplit 方法都可以完成链接的合并,不过前提都是必须有特定长度的对象,链接的每一部分都要清晰分开。

        除了这两种方法,还有一种生成链接的方法,是 urljoin。我们可以提供一个 base url(基础链接)作为该方法的第一个参数,将新的链接作为第二个参数。urljoin 方法会分析 base url的 scheme、netloc 和path这3个内容,并对新链接缺失的部分进行补充,最后返回结果。

下面通过几个实例看一下:

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

运行结果如下:

https://www.baidu.com/FAQ.htmlhttps://cuiqingcai.com/FAQ.htmlhttps://cuiqingcai.com/FAQ.htmlhttps://cuiqingcai.com/FAQ.html?question=2https://cuiqingcai.com/index.phphttps://www.baidu.com?category=2#commentwww.baidu.com?category=2#commentwww.baidu.com?category=2

       可以发现, base url提供了三项内容: scheme、netloc和 path。如果新的链接里不存在这三项,就予以补充; 如果存在,就使用新的链接里面的,base url中的是不起作用的。通过urljoin 方法,我们可以轻松实现链接的解析、拼合与生成。

4、分析Robots协议

        利用 urllib库的 robotparser 模块,可以分析网站的 Robots 协议。我们再来简单了解一下这个模块的用法。

(1) Robots 协议

        Robots 协议也称作爬虫协议、机器人协议,全名为网络爬虫排除标准(Robots Exclusion Protocol),用来告诉爬虫和搜索引擎哪些页面可以抓取、哪些不可以。它通常是一个叫作 robots. txt的文本文件,一般放在网站的根目录下。

        搜索爬虫在访问一个站点时,首先会检查这个站点根目录下是否存在 robots. txt文件,如果存在,就会根据其中定义的爬取范围来爬取。如果没有找到这个文件,搜索爬虫便会访问所有可直接访问的页面。

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

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

        这限定了所有搜索爬虫只能爬取 public 目录。将上述内容保存成robots. txt文件,放在网站的根目录下, 和网站的入口文件(例如index. php、 index. html和 index. jsp等) 放在一起。上面样例中的User-agent描述了搜索爬虫的名称,这里将其设置为*,代表 Robots协议对所有爬取爬虫都有效。例如,我们可以这样设置:

User-agent: Baiduspider

        这代表设置的规则对百度爬虫是有效的。如果有多条User-agent记录,则意味着有多个爬虫会受到爬取限制,但至少需要指定一条。

        Disallow指定了不允许爬虫爬取的目录,上例设置为 /,代表不允许爬取所有页面。Allow一般不会单独使用,会和Disallow一起用,用来排除某些限制。上例中我们设置为/public/,结合Disallow的设置,表示所有页面都不允许爬取,但可以爬取 public 目录。

        下面再来看几个例子。禁止所有爬虫访问所有目录的代码如下:

User-agent: *Disallow: /

        允许所有爬虫访问所有目录的代码如下:

User-agent: *Disallow:

        另外,直接把robots. txt文件留空也是可以的。禁止所有爬虫访问网站某些目录的代码如下:

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

        只允许某一个爬虫访问所有目录的代码如下:

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

        以上是 robots. txt的一些常见写法。

(2) robotparser

        了解 Robots协议之后, 就可以使用robotparser模块来解析robots. txt文件了。该模块提供了一个类 RobotFileParser,它可以根据某网站的 robots. txt文件判断一个爬取爬虫是否有权限爬取这个网页。该类用起来非常简单,只需要在构造方法里传入 robots. txt文件的链接即可。首先看一下它的声明:

urllib. robotparser. RobotFileParser(url='')

        当然,也可以不在声明时传入 robots. txt文件的链接,就让其默认为空,最后再使用set url()方法设置一下也可以。下面列出了 RobotFileParser类的几个常用方法。

  •  set url: 用来设置 robots. txt文件的链接。如果在创建 RobotFileParser 对象时传入了链接,就不需要使用这个方法设置了。
  • read:读取 robots. txt文件并进行分析。注意,这个方法执行读取和分析操作,如果不调用这个方法,接下来的判断都会为False,所以一定记得调用这个方法。这个方法虽不会返回任何内容,但是执行了读取操作。
  • parse: 用来解析robots. txt文件, 传入其中的参数是 robots. txt文件中某些行的内容, 它会按照robots. txt的语法规则来分析这些内容。
  • can fetch:该方法有两个参数,第一个是User-Agent,第二个是要抓取的 URL。返回结果是 True 或False, 表示 User-Agent 指示的搜索引擎是否可以抓取这个URL。
  • Jmtime: 返回上次抓取和分析robots. txt文件的时间, 这对于长时间分析和抓取 robots. txt文件的搜索爬虫很有必要,你可能需要定期检查以抓取最新的 robots. txt文件。
  • modified:它同样对长时间分析和抓取的搜索爬虫很有帮助,可以将当前时间设置为上次抓取和分析 robots. txt文件的时间。

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

from urllib. robotparser import RobotFileParserrp = RobotFileParser()rp.set url('https://www.baidu.com/robots.txt')rp. read()print(rp.can fetch('Baiduspider', 'https://www.baidu.com'))print(rp.can fetch('Baiduspider', 'https://www.baidu.com/homepage/'))print(rp.can fetch('Googlebot', 'https://www.baidu.com/homepage/'))

        这里以百度为例, 首先创建了一个 RobotFileParser 对象 rp, 然后通过 set url 方法设置了robots. txt文件的链接。当然,要是不用set url方法,可以在声明对象时直接用如下方法设置:

rp = RobotFileParser('https://www.baidu.com/robots.txt')

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

True
True
False

        可以看到,这里我们利用Baiduspider可以抓取百度的首页以及 homepage页面,但是 Googlebot就不能抓取 homepage页面。打开百度的 robots. txt文件, 可以看到如下信息:

User-agent: Baiduspider
Disallow: /baidu
Disallow: /s?Disallow: /ulink?Disallow: /link?Disallow: /home/news/data/Disallow: /bhUser-agent: GooglebotDisallow: /baiduDisallow: /s?Disallow: /shiften/Disallow: /homepage/Disallow: /cproDisallow: /ulink?Disallow: /link?Disallow: /home/news/data/Disallow: /bh

        不难看出, 百度的 robots. txt文件没有限制 Baiduspider 对百度 homepage 页面的抓取, 限制了Googlebot对 homepage页面的抓取。这里同样可以使用parse 方法执行对 robots. txt文件的读取和分析,实例如下:

from urllib. request import urlopenfrom urllib. robotparser import RobotFileParserrp= RobotFileParser()rp.parse(urlopen('     https://www.baidu.com/robots.txt').read().decode('utf-8').split('\n'))print(rp.can fetch('Baiduspider', 'https://www.baidu.com'))print(rp.can fetch('Baiduspider', '     https://www.baidu.com/homepage/'))print(rp.can fetch('Googlebot', '       https://www.baidu.com/homepage/'))

运行结果是一样的:

TrueTrueFalse

        本节介绍了 robotparser 模块的基本用法和实例,利用此模块,我们可以方便地判断哪些页面能抓取、哪些页面不能。

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

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

相关文章

32单片机基础:GPIO输出

目录 简介&#xff1a; GPIO输出的八种模式 STM32的GPIO工作方式 GPIO支持4种输入模式&#xff1a; GPIO支持4种输出模式&#xff1a; 浮空输入模式 上拉输入模式 下拉输入模式 模拟输入模式&#xff1a; 开漏输出模式&#xff1a;&#xff08;PMOS无效&#xff0c;就…

技术心得--如何成为优秀的架构师

关注我&#xff0c;持续分享逻辑思维&管理思维&#xff1b; 可提供大厂面试辅导、及定制化求职/在职/管理/技术辅导&#xff1b; 有意找工作的同学&#xff0c;请参考博主的原创&#xff1a;《面试官心得--面试前应该如何准备》&#xff0c;《面试官心得--面试时如何进行自…

三防加固平板在房地产行业的应用|亿道三防onerugged

近期&#xff0c;有一款引人注目的解决方案——亿道三防onerugged平板电脑&#xff0c;它以其出色的性能和多功能的设计&#xff0c;为房地产行业带来了全新的应用体验。 首先&#xff0c;亿道三防onerugged平板电脑的NFC功能在小区业主身份验证中发挥着重要作用。传统的身份验…

vue3组件通信方式汇总

前言&#xff1a;本文默认读者有JS基础和Vue基础&#xff0c;如果没有这个两个基础&#xff0c;可能阅读比较困难&#xff0c;建议先看下官方文档&#xff0c;当然&#xff0c;也欢迎评论交流&#x1f601; 通信方式总结 常见搭配形式 一、props&#xff08;使用频率最高&#…

HarmonyOS 鸿蒙应用开发(十二、paho-mqtt的mqtt客户端库移植)

PAHO MQTT 是 Eclipse Foundation 的一个开源项目&#xff0c;提供了用于 MQTT 协议的客户端库。这个库为使用 MQTT 协议的应用程序提供了丰富的功能和灵活性。轻量级mqtt服务器mosquitto也是其中有名的一个开源项目。 目录 PAHO MQTT介绍 移植过程 index.d.ts文件修改 写…

SOPHON算能科技新版SDK环境配置以及C++ demo使用过程

目录 1 SDK大包下载 2 获取SDK中的库文件和头文件 2.1 注意事项 2.2 交叉编译环境搭建 2.2.1 首先安装工具链 2.2.2 解压sophon-img包里的libsophon_soc__aarch64.tar.gz&#xff0c;将lib和include的所有内容拷贝到soc-sdk文件夹 2.2.3 解压sophon-mw包里的sophon-mw-s…

hadoop FileSystem是否要close

先来说结论&#xff0c;最好不要close&#xff0c;让hadoop自己close&#xff0c;否则容易把进程里其他获取fs的地方一起关了。这是因为 FileSystem.get(Configuration)做了缓存的原因。当然可以设置 conf.setBoolean("fs.hdfs.impl.disable.cache", true); 就不缓存…

Django后台管理(一)

一、admin介绍 Django 最强大的部分之一是自动管理界面。它从你的模型中读取元数据,提供一个快速的、以模型为中心的界面,受信任的用户可以管理你网站上的内容 官网:https://docs.djangoproject.com/zh-hans/4.1/ref/contrib/admin/ 提示 后台管理系统是管理人员使用,不是…

Python之海象运算符

在 Python 3.8 及更高版本中&#xff0c;引入了一种新的语法特性&#xff0c;称为"海象运算符"&#xff08;Walrus Operator&#xff09;&#xff0c;它使用 : 符号。这个运算符的主要目的是在表达式中同时进行赋值和返回赋值的值。 使用海象运算符可以在一些情况下…

centos7下docker的安装

背景 总结下docker的一些知识 docker安装&#xff08;有网络版&#xff09; 参考文章我以前试过这个帖子&#xff0c;建议安装高版本的docker&#xff0c;&#xff08;20以上的&#xff0c;不然可能会有一些问题&#xff09; ## 1、安装依赖 [rootiZo7e61fz42ik0Z ~]#yum i…

laravel-admin的3个开发细节调整

在使用laravel-admin开发的过程中&#xff0c;根据官方开发文档Laravel admin | laravel-admin基本都能实现想要的效果&#xff0c;这里补充3个文档上没有描述的细节 Laravel8命令行创建控制器调整 在laravel-admin中可以使用php artisan admin:make UserController --modelAp…

WireShark 安装指南:详细安装步骤和使用技巧

Wireshark是一个开源的网络协议分析工具&#xff0c;它能够捕获和分析网络数据包&#xff0c;并以用户友好的方式呈现这些数据包的内容。Wireshark 被广泛应用于网络故障排查、安全审计、教育及软件开发等领域。接下将讲解Wireshark的安装与简单使用。 目录 Wireshark安装步骤…

Rasa:停止构建“代理”,并推出真正有效的LLM聊天机器人

Rasa:停止构建“代理”,并推出真正有效的LLM聊天机器人 带语言模型的对话式人工智能 (Conversational AI with Language Models CALM) 是一种用于构建可靠对话式人工智能的大模型方法。它是 Rasa 基于多年来帮助企业团队构建面向客户的助手而开发的。 CALM 的工作原理 CAL…

CSP-201809-1-卖菜

CSP-201809-1-卖菜 解题思路 #include <iostream> using namespace std; int main() {int n;cin >> n;int* array new int[n];for (int i 0; i < n; i){cin >> array[i];}cout << (array[0] array[1]) / 2 << " ";for (int i …

目录IO

目录IO 1.mkdir 创建目录文件 mkdir(const char *pathname, mode_t mode); (文件路径,文件的权限) 成功返回 0 失败返回 -1 r: 目录中是否能够查看文件 w: 目录中是否能够新建文件 x: 目录是否能够进入 2.rmdir 删除空目录文件 rmdir(const char *pathname); &am…

vivado FIR Filters

Vivado合成直接从RTL中推导出乘加级联来组成FIR滤波器。这种滤波器有几种可能的实现方式&#xff1b;一个例子是收缩滤波器在7系列DSP48E1 Slice用户指南&#xff08;UG479&#xff09;中进行了描述&#xff0c;并在8抽头偶数中显示对称收缩FIR&#xff08;Verilog&#xff09;…

2.20 Qt day1

一. 思维导图 二. 消化常用类的使用&#xff0c;以及常用成员函数对应的功能 按钮类QPushButton&#xff1a; mywidget.h&#xff1a; #ifndef MYWIDGET_H #define MYWIDGET_H#include <QWidget> #include<QPushButton>//按钮类 #include<QIcon>class MyW…

springboot+vue项目基础开发(17)路由使用

路由 在前端中,路由指的是根据不同的访问路径,展示不同的内容 vue Router的vue.js的官方路由 安装vue Router 再启动 在src下面新建router文件,创建index.js 代码 import {createRouter,createWebHashHistory} from vue-router //导入组件 import Login from @/views/Log…

六轴陀螺仪在游戏手柄中的应用及中国市场展望

随着电子竞技的兴起和虚拟现实技术的发展&#xff0c;游戏手柄作为重要的交互设备&#xff0c;其性能和功能日益受到重视。六轴陀螺仪作为一种高精度的运动传感器&#xff0c;其在游戏手柄中的应用&#xff0c;不仅提升了用户的游戏体验&#xff0c;也为游戏手柄市场带来了新的…

Kubernetes kubeadm 证书到期,更新证书

1.环境说明 lient Version: version.Info{Major:"1", Minor:"19", GitVersion:"v1.19.6", GitCommit:"fbf646b339dc52336b55d8ec85c181981b86331a", GitTreeState:"clean", BuildDate:"2020-12-18T12:09:30Z", G…