爬虫基本库的使用(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())

运行结果:

网页源代码:


	


	


响应状态码:
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异常。

运行结果如下:


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 urlparse

result = 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 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 参数,返回了结果 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 urlparse

result = 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 urlparse

result = 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 urlparse

result = 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 urlunparse

data = ['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 urlsplit

result = 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 urlsplit

result = 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 urlunsplit

data = ['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 urljoin

print(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.html

https://cuiqingcai.com/FAQ.html

https://cuiqingcai.com/FAQ.html

https://cuiqingcai.com/FAQ.html?question=2

https://cuiqingcai.com/index.php

https://www.baidu.com?category=2#comment

www.baidu.com?category=2#comment

www.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 RobotFileParser

rp = 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: /bh

User-agent: Googlebot

Disallow: /baidu

Disallow: /s?

Disallow: /shiften/

Disallow: /homepage/

Disallow: /cpro

Disallow: /ulink?

Disallow: /link?

Disallow: /home/news/data/

Disallow: /bh

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

from urllib. request import urlopen

from urllib. robotparser import RobotFileParser

rp= 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/'))

运行结果是一样的:

True

True

False

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

你可能感兴趣的:(爬虫,python)