爬虫学习-基础库的使用(urllib库)

目录

一、urllib库介绍

二、request模块使用

        (1)urlopen

        ①data参数

        ②timeout参数

        (2)request

        (3)高级用法

          ①验证

        ②代理

        ③Cookie

三、处理异常

        ①URLError

        ②HTTPError

四、解析链接

        ①urlparse

        ②urlunparse

        ③urlsplit

        ④urlunsplit

        ⑤urljoin

        ⑥urlencode

        ⑦parse_qs

        ⑧parse_qsl

        ⑨quote         

        ⑩unquote

五、分析 Robots协议

        ①Robots 协议


一、urllib库介绍

        urllib是Python的内置的HTTP请求库,不需要另外下载,可直接使用。urllib库包含以下四个模块:

        ①request:最基本的HTTP请求模块。可以模拟请求的发送。就像在浏览器李输入网址然后按下回车一样,只需要给库方法传入URL以及额外的参数,就可以发送请求的过程了。

        ②error:异常处理模块。如果出先请求异常,那么我们可以捕获这些异常,然后进行重试或其他操作以保证程序运行不会意外停止。

        ③parse:工具模块。提供了许多URL的处理方法,例如拆分、解析、合并等。

        ④robotparser:主要用于识别网站的robots.txt文件,然后判断哪些网站可以爬取,哪些网站不可以,但是实际使用很少。

二、request模块使用

        (1)urlopen

        urllib.request模块提供了最基本的构造HTTP请求的方法,利用这个模块可以模拟浏览器的请求发起过程,同时它还具有处理授权验证(Authentication)、重定向(Redirection)、浏览器Cookie以及其他一些功能。下面以Python官网为例,把这个网页抓取下来。

import urllib.requestif __name__ == '__main__':response = urllib.request.urlopen('https://www.python.org')print(type(response))                     # 查看response类型print(response.read().decode('utf-8'))    # 输入response内容,设置编码格式为utf-8

        可以看出,响应是一个HTTPResponse类型的对象,主要包含read、redinto、getheader、getheaders、fileno等方法,以及msg、version、status、reason、debuglevel、closed等属性。

        得到响应后,我们把它赋值给response变量,然后就可以调用上述方法和属性,得到返回的一系列信息了。

        例如调用read方法可以得到响应的网页内容、调用status可以得到响应结果的状态码(200表示请求成功,404表示网页未找到等)

        例如以下代码:

import urllib.request
if __name__ == '__main__':response = urllib.request.urlopen('https://www.python.org')print(response.status)              # 返回状态码print(response.getheaders())        # 响应头信息print(response.getheader('Server')) # 获取只当参数的值

        其中前两个输出分别是响应的状态码和响应的头信息;最后一个输出是调用getheader方法,并传入参数Server,获取响应头中Server的值,结果是nginx,意思是服务器是Nginx搭建的。

        利用最基本的urlopen方法,可以完成对简单网页的GET请求抓取,但是如果想给链接传递一些参数,又该如何实现呢?首先看一下urlopen方法的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请求。下面用示例来看一下。

import urllib.request
import urllib.parse
if __name__ == '__main__':data = bytes(urllib.parse.urlencode({'name': 'germey'}),encoding='utf-8')response = urllib.request.urlopen('https://www.httpbin.org/post', data=data)print(response.read().decode('utf-8'))

        这里我们传递了一个参数name,值是germey,需要将它转码为bytes类型。转码时采用了bytes方法,该方法的第一个参数得是str(字符串)类型因此用urllib.parse模块里的urlencode方法将字典参数转化为字符串;第二个参数用于指定编码格式,这里指定为utf-8。

        此处我们请求的站点www.httpbin.org,它可以提供HTTP请求测试。本次我们请求的URL为https://www.httpbin.org/post,这个链接可以用来测试POST请求,能够输出请求的一些信息,其中就包含我们传递的data参数。

        上面示例运行结果如下:

        ②timeout参数

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

        下面通过示例来看一下:

import urllib.request
if __name__ == '__main__':response = urllib.request.urlopen('https://www.httpbin.org/get', timeout=0.1)print(response.read())

        这里我们设置超时时间为0.1秒,程序在运行了0.1秒后,服务器依然没有响应,于是抛出了URLError异常。该异常属于urllib.error模块,错误原因是超时。

        因此可以通过设置一个超时时间,实现当一个网页长时间未响应时,就跳过对它的抓取。此外利用try except 语句也可以实现,相关代码如下:

import socket
import urllib.request
import urllib.error
if __name__ == '__main__':try:response = urllib.request.urlopen('https://www.httpbin.org/get', timeout=0.1)except urllib.error.URLError as e:if isinstance(e.reason, socket.timeout):print('TIME OUT')

        ③其他参数

        除了data参数和timeout参数,urlopen还要context参数,该参数必须是ssl.SSLContext类型,用来指定SSL的设置。

        此外,cafile和capath这两个参数分别用来指定CA证书和其路径,这两个在请求HTTPS链接时会有用,cadefault参数现在已经弃用,其默认值为False。

        (2)request

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

        首先,先看一下Request类的实际用法:

import urllib.request
if __name__ == '__main__':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
if __name__ == '__main__':url = 'https://www.httpbin.org/post'headers = {'User-Agent':'Mozilla / 5.0(Windows NT 10.0;Win64;x64) AppleWebKit / 537.36(KHTML, likeGecko) Chrome / 119.0.0.0Safari / 537.36','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'))

        这里我们通过4个参数构建了一个Request类,其中的url即请求URL,headers中指定了User-Agent和Host,data用urlencode方法和bytes方法把字典数据转成字节流格式。另外,指定了请求方式为POST。

        运行结果如下:

        (3)高级用法

        我们已经可以构建请求了,那么对于一些高级的操作(例如cookie的处理、代理设置等),又该如何实现呢?此时就需要更强大的高级,Handler登场了。简而言之,Handler可以理解为各种处理器,由专门处理登录验证的,处理Cookie的、处理代理设置的。利用这些Handler,我们几乎可以实现HTTP请求中所有的功能。

        首先介绍一下urllib.request模块里的BaseHandler类,这是其他所有Handler类的父类。它提供了最基本的方法,例如default_open、protocol_request等。

        会由各种Handler子类继承BaseHandler类,接下来举几个子类例子如下:

        ①HTTPDefaultErrorHandler用于处理HTTP响应错误,所有错误都会抛出HTTPError类型的异常。

        ②HTTPRedirectHandler用于处理重定向。

        ③HTTPCookieProcessor用于处理Cookie。

        ④ProxyHandler用于设置代理,代理默认为空。

        ⑤HTTPPasswordMgr用于管理密码,它维护着用户名和密码的对照表。

        ⑥HTTPBasicAuthHandler用于管理认证,如果一个链接在打开时需要验证,那么可以使用这个类来解决认证问题。

        另外一个比较重要的类是OpenerDirector,我们可以称为Opener。我们用过的urlopen方法,实际上就是urllib库为我们提供的一个opener。
  那么,为什么要引入Opener呢?因为需要实现更高级的功能。之前使用的 Request类和 urlopen类相当于类库已经封装好的极其常用的请求方法,利用这两个类可以完成基本的请求, 但是现在我们需要实现更高级的功能,就需要深入一层进行配置,使用更底层的实例来完成操作,所以这里就用到了Opener。
  Opener类可以提供open方法,该方法返回的响应类型和 urlopen方法如出一辙。那么, Opener类和Handler类有什么关系呢?简而言之就是, 利用Handler类来构建Opener类。
下面用几个实例来看看 Handler 类和Opener类的用法。

          ①验证

        在访问某些网站是,例如https://ssr3.scrape.center,可能会弹出这样的认证窗口,如图所示。

        遇到这种情况,就表示这个网站启用了基本身份验证,英文名叫做HTTPbasic Access Authentication,这是一种登录验证方式,允许网页浏览器或其他客户端程序在请求网站是提供用户名和口令形式的身份凭证。

        那么爬虫如何请求这样的页面呢?借助HTTPBasicAuthHandler模块就可以完成,相关代码如下:

from urllib.request import HTTPBasicAuthHandler, HTTPPasswordMgrWithDefaultRealm, build_opener
from urllib.error import URLError
if __name__ == '__main__':username = 'admin'password = 'admin'url = 'https://ssr3.scrape.center/'p = HTTPPasswordMgrWithDefaultRealm()       # 实例对象p.add_password(None, url, username, password)auth_handler = HTTPBasicAuthHandler(p)opener = build_opener(auth_handler)# 异常接收try:result = opener.open(url)html = result.read().decode('utf-8')print(html)except URLError as e:print(e.reason)

        这里首先实例化了一个HTTPBasicAuthHandler对象auth_handler,其参数是HTTPPasswordMgr-WithDefaultRealm对象,它利用add_password方法添加用户名和密码,这样就建立了一个用来处理验证的Handler类。 然后将刚建立的auth_handler类当作参数传入build——opener方法,构建一个Opener,这个Opener在发送请求时就相当于已经验证成功了。最后利用Opener类中的open方法打开链接,即可完成验证。这里获取的结果就是验证成功后的页面源码内容。

        ②代理

        做爬虫的时候,免不了要使用代理,如果要添加代理,可以这样做。

from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener
if __name__ == '__main__':proxy_handler = ProxyHandler({'http':'http://127.0.0.1:8080','https':'https://127.0.0.1:8080'})opener = build_opener(proxy_handler)try:response = opener.open('https://www.baidu.com')print(response.read().decode('utf-8'))except URLError as e:print(e.reason)

        这里我们需要事先在本地搭建一个HTTP代理,并让其允许在8080端口上。上面使用了ProxyHandler,其参数是一个字典,键名是协议类型(例如HTTP或者HTTPS等),键值是代理链接,可以添加多个代理。

        ③Cookie

        处理Cookie需要用到相应的handler。

        先看实例如何获取Cookie,相关代码如下:

import http.cookiejar, urllib.request
if __name__ == '__main__':  cookie = http.cookiejar.CookieJar()handler = urllib.request.HTTPCookieProcessor(cookie)opener = urllib.request.build_opener(handler)response = opener.open('https://www.baidu.com')for item in cookie:print(item.name + "=" + item.value)

        首先,必须声明一个CookieJar对象。然后需要利用HTTPCookieProcessor构建一个Handler,最后利用build_opener方法构建Opener,执行Open函数即可。

        运行结果如下:

        这里可以看到,分别输出了每个Cookie条目的名称和值。既然能输出,那么可不可以输出文件格式的内容呢?我们指定Cookie实际也是以文本形式保存到。因此答案是肯定的,这里通过下面的实例来看看。

import urllib.request, http.cookiejar
if __name__ == '__main__':filename = 'cookie.txt'cookie = http.cookiejar.MozillaCookieJar(filename)handler = urllib.request.HTTPCookieProcessor(cookie)opener = urllib.request.build_opener(handler)response = opener.open('https://www.baidu.com')cookie.save(ignore_discard=True, ignore_expires=True)

        这时需要将CookieJar缓存MozillaCookieJar,他会在生成文件时用到,是CookieJar的子类,可以用来处理跟Cookie和文件有关的事件,例如读取和保存Cookie,可以将Cookie保存为Mozilla型浏览器的Cookie格式。

        上面代码运行结果如下:

        另外,LWPCookieJar统一可以读取和保存COokie,知识Cookie文件的保存格式和MozillaCookieJar不一样,他会保存LWP(libwww-perl)格式

import urllib.request, http.cookiejar
if __name__ == '__main__':filename = 'cookie.txt'# cookie = http.cookiejar.MozillaCookieJar(filename)cookie = http.cookiejar.LWPCookieJar(filename)handler = urllib.request.HTTPCookieProcessor(cookie)opener = urllib.request.build_opener(handler)response = opener.open('https://www.baidu.com')cookie.save(ignore_discard=True, ignore_expires=True)

        运行结果如下:

        由此看来,不同格式cookie文件差异还是比较大的。那么生成Cookie文件后,怎样从其中读取呢?以下面代码为例,对LWPCookieJar格式Cookie文件读取。

import urllib.request, http.cookiejar
if __name__ == '__main__':cookie = http.cookiejar.LWPCookieJar()cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)handler = urllib.request.HTTPCookieProcessor(cookie)opener = urllib.request.build_opener(handler)response = opener.open('https://www.baidu.com')print(response.read().decode('utf-8'))

三、处理异常

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

        ①URLError

        URLError类来之urllib库的error模块,继承自OSError类,时error异常模块的基类,由request模块产生的异常都可以通过捕获这个类来处理。

        它有一个属性reason,即返回错误的原因。

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

from urllib import request, error
if __name__ == '__main__':try:response = request.urlopen('https://cuiqingcai.com/404')except error.HTTPError as e:print(e.reason, e.code, e.headers, sep='\n')# reason:返回错误的原因# code:返回HTTP状态码# headers:返回请求头

        我们打开了一个不存在的页面,按理说应该会报错,但是我们捕获了URLError这个异常,运行结果如下:

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

        ②HTTPError

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

        code:返回HTTP状态码,例如404表示网页不存在,500表示服务器内部错误等。

        reason:同父类一样,用于返回错误的原因。

        headers:返回请求头。

        下面通过实例看看:

from urllib import request, error
if __name__ == '__main__':try:response = request.urlopen('https://cuiqingcai.com/404')except error.HTTPError as e:print(e.reason, e.code, e.headers, sep='\n')# reason:返回错误的原因# code:返回HTTP状态码# headers:返回请求头

        运行结果入下:

        依旧是打开相同的网址,这里捕获了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, sep= '\n')
except error.URLError as e:print(e.reason)
else:print('request successful')

        这样就可以做到先捕获HTTPError,获取它的错误原因、状态码、请求头等信息。如果不是HTTPError异常,就会捕获URLError异常,输出错误原因。最后else语句来处理正常的逻辑。这是一个较好的异常处理写法。

        有时候,reason属性返回的不一定是字符串,也可能是一个对象。再看下面的实例:

import socket
import urllib.request
import urllib.error
if __name__ == '__main__':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异常。

        运行结果如下:

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

四、解析链接

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

        下面介绍parse模块的常用方法,看一下它的特别之处。

        ①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类型的对象,包含6部分,分别是 scheme、netloc、path.params、query和fragment。再观察一下上述实例中的 URL:

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

        可以发现, urlparse方法在解析URL时有特定的分隔符。例如:// 前面的内容就是 scheme,代表协议。第一个/符号前面便是 netloc,即域名;后面是 path,即访问路径。分号;后面是 parans,代表参数。问号?后面是查询条件 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)

运行结果如下:

        可以发现,这里提供的URL不包含最前面的协议信息,但是通过默认的scheme 参数,返回了结果 https。

        假设带上协议信息:

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

  可见,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)

        运行结果如下:

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

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

运行结果如下:

        可以发现,此时 fragment 会被解析为 path的一部分。

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

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

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

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

        ②urlunparse

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

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

        这里参数 data用了列表类型。当然,也可以用其他类型,例如元组或者特定的数据结构。

        运行结果如下:

        

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

        ③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,这其实也是一个元组,既可以用属性名获取其值,也可以用索引获取。实例如下:

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

        运行结果如下:

        ④urlunsplit

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

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

        运行结果如下:

        ⑤urljoin

        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'))

        运行结果如下:

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

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

        ⑥urlencode

        这里我们再介绍一个常用的方法——urlencode,它在构造 GET 请求参数的时候非常有用,实例如下:

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

        这里首先声明了一个字典 params,用于将参数表示出来,然后调用 urlencode方法将 params 序列化为 GET 请求的参数。

        运行结果如下:

        可以看到,参数已经成功地由字典类型转化为GET请求参数。

        urlencode方法非常常用。有时为了更加方便地构造参数,我们会事先用字典将参数表示出来,然后将字典转化为URL的参数时,只需要调用该方法即可。

        ⑦parse_qs

        有了序列化,必然会有反序列化。利用 parse_qs 方法,可以将一串 GET请求参数转回字典,实例如下:

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

        运行结果如下:

        可以看到, URL的参数成功转回为字典类型。

        ⑧parse_qsl

        parse_qsl方法用于将参数转化为由元组组成的列表,实例如下:

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

运行结果如下:

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

        ⑨quote         

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

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

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

        ⑩unquote

        有了 quote方法,当然就有 unquote方法,它可以进行URL 解码,实例如下:

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

        这里的url是上面得到的 URL 编码结果,利用 unquote方法将其还原,结果如下:

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

五、分析 Robots协议

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

        ①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的一些常见写法。

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

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

相关文章

Kernel(一):基础

本文主要讨论210的kernel基础相关知识。 内核驱动 驱动是内核中的硬件设备管理模块,工作在内核态,程序故障可能导致内核崩溃,程序漏洞会使内核不安全 根文件系统提供根目录,进程存放在根文件系统中,内核启动最后会装载根文件系统 应用程序不属于内核,…

1828_ChibiOS中的对象FIFO

全部学习汇总: GreyZhang/g_ChibiOS: I found a new RTOS called ChibiOS and it seems interesting! (github.com) 1. 最初的这个理解,当看到后面之后就知道有点偏差了。其实,这个传输就是一个单纯的FIFO而不是两个FIFO之间的什么操作。 2.…

去掉参数中第一个“,”

记录一下,前端传参中,传给我参数是“categoryIds: ,1731557494586241026,1731569816263311362,1731569855534579713,1731858335179223042,1731858366821052418” 但是后端,因为我的mybati是in查询,所以因为第一个是“,”。所以会导…

sap增强

四代增强 2种显示增强1种隐式增强 隐式增强 光标放在增强点或其中的代码点击修改即可修改代码 显示增强 1.ENHANCEMENT-POINT 在代码修改界面选择空行 光标所在位置 可以创建多个增强实施且激活后都会执行. 2.ENHANCEMENT-SECTION 1,选中程序中空行 2.编辑->创建选项 …

回顾2023 亚马逊云科技 re_Invent,创新AI,一路同行

作为全球云计算龙头企业的亚马逊云科技于2023年11月27日至12月1日在美国拉斯维加斯举办了2023 亚马逊云科技 re:Invent,从2012年开始举办的亚马逊云科技 re:Invent 全球大会,到现如今2023 亚马逊云科技 re:Invent,回顾历届re:Invent大会,亚马…

C++『异常』

✨个人主页: 北 海 🎉所属专栏: C修行之路 🎃操作环境: Visual Studio 2022 版本 17.6.5 文章目录 🌇前言🏙️正文1.异常基本概念1.1.C语言异常处理方式1.2.C异常处理方式 2.异常的使用2.1.异常…

在线网页生成工具GrapesJS

项目地址 https://github.com/GrapesJS/grapesjshttps://github.com/GrapesJS/grapesjs 项目简述 这是一个基于node.js的在线网页生成项目,对简化开发有很大的帮助。 主要使用的语言如下: 编辑页面如下: 使用也很简洁 具体可以看下项目。…

12. MySQL 锁机制

目录 概述 MylSAM引擎 InnoDB引擎 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制(避免争抢)。在数据库中,除传统的计算资源(如CPU、RAM、I/O等)的争用以外,数据也是一种供许多用户共享的资如何保证数据…

2023年第十届GIAC全球互联网架构大会-核心PPT资料下载

一、峰会简介 谈到一个应用,我们首先考虑的是运行这个应用所需要的系统资源。其次,是关于应用自身的架构模式。最后,还需要从软件工程的不同角度来考虑应用的设计、开发、部署、运维等。架构设计对应用有着深远的影响,它的好坏决…

Leetcode659. 分割数组为连续子序列

Every day a Leetcode 题目来源:659. 分割数组为连续子序列 解法1:哈希 贪心 定义两个哈希表: numsCount:统计数组 nums 中各元素出现次数。tailCount:存储以数字 i 结尾的且符合题意的连续子序列个数。 算法&a…

极兔单号查询,极兔快递物流查询,一键筛选出退回件

批量查询极兔快递单号的物流信息,一键筛选出其中的退回件。 所需工具: 一个【快递批量查询高手】软件 极兔快递单号若干 操作步骤: 步骤1:运行【快递批量查询高手】软件,并登录 步骤2:点击主界面左上角的…

【Bootloader学习理解----跳转优化异常】

笔者接着来介绍一下Bootloader的跳转代码以及优化 1、跳转代码理解 跳转代码可能要涉及到芯片架构的知识,要跳转到对应的位置,还要设置相关的SP 堆栈指针,具体可以参考笔者这篇文章BootLoader的理解与实现。 STM32的跳转代码如下所示: u32 …

基于以太坊的智能合约开发Solidity(基础篇)

参考教程:基于以太坊的智能合约开发教程【Solidity】_哔哩哔哩_bilibili 1、第一个程序——Helloworld: //声明版本号(程序中的版本号要和编译器版本号一致) pragma solidity ^0.5.17; //合约 contract HelloWorld {//合约属性变…

Python轴承故障诊断 (四)基于EMD-CNN的故障分类

目录 前言 1 经验模态分解EMD的Python示例 2 轴承故障数据的预处理 2.1 导入数据 2.2 制作数据集和对应标签 2.3 故障数据的EMD分解可视化 2.4 故障数据的EMD分解预处理 3 基于EMD-CNN的轴承故障诊断分类 3.1 训练数据、测试数据分组,数据分batch 3.2 定义…

stu05-前端的几种常用开发工具

前端的开发工具有很多,可以说有几十种,包括记事本都可以作为前端的开发工具。下面推荐的是常用的几种前端开发工具。 1.DCloud HBuilder(轻量级) HBuilder是DCloud(数字天堂)推出的一款支持HTML5的web开发…

硬件开发笔记(十四):RK3568底板电路LVDS模块、MIPI模块电路分析、LVDS硬件接口、MIPI硬件接口详解

若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/134634186 红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

软考高级备考-系统架构师(机考后新版教材的备考过程与资料分享)

软考高级-系统架构设计师 考试复盘1.考试结果2.备考计划3.个人心得 资料分享 考试复盘 1.考试结果 三科压线过,真是太太太太太太太幸运了。上天对我如此眷顾,那不得不分享下我的备考过程以及一些备考资料,帮助更多小伙伴通过考试。 2.备考…

time模块(python)

一.sleep休眠 [rootrhel8 day04]# vim demo01_time.py import time def banzhuan():print("搬砖")time.sleep(3.5) #让程序休眠3.5秒print("结束")banzhuan()[rootrhel8 day04]# python3 demo01_time.py 搬砖 结束运行时,会发现程序中间暂停…

【3DsMax】制作简单的骨骼动画

效果 步骤 首先准备4个板子模型展开放置好 添加一个4段的骨骼 选中其中的一块板子添加蒙皮命令 在蒙皮的参数面板中,设置每块板子对应哪块骨骼 设置好后你可以发现此时就已经可以通过骨骼来控制模型了 接下来就可以制作动画 点击左下角“时间配置”按钮 设置一下动…

HarmonyOS--ArkTS(1)--基本语法(1)

目录 基本语法概述 声明式UI描述 自定义组件 创建自定义组件 自定义组件的结构--struct ,Component,build()函数 生命周期 基本语法概述 装饰器: 用于装饰类、结构、方法以及变量,并赋予其特殊的含义。如上述示例中Entry、C…