Python爬虫-请求模块Urllib

Python爬虫-请求模块Urllib

Python3中的Urllib 模块中包含多个功能的子模块,具体内容如下:
urllib.request:用于实现基本HTTP请求的模块。
urllib.error:异常处理模块,如果在发送网络请求时出现了错误,可以捕获异常进行异常的有效处理。
urllib.parse:用于解析URL的模块。
urllib.robotparser:用于解析robots.txt文件,判断网站是否可以爬取信息。

使用 urlopen()方法发送请求

urllib.request模块提供了urlopen()方法,用于实现最基本的HTTP请求,然后接收服务端所返回的响应数据。urlopen()方法的语法格式如下:

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

url:需要访问网站的URL完整地址。
data:该参数默认为None,通过该参数确认请求方式,如果是None,表示请求方式为GET,否则请求方式为POST,在发送POST请求时,参数data 需要以字典形式的数据作为参数值,并且需要将字典类型的参数值转换为字节类型的数据才可以实现POST请求。
timcout:以秒为单位,设置超时。
cafile、capath:指定一组 HTTPS请求受信任的CA证书,cafile指定包含CA证书的单个文件,capath指定证书文件的目录。
cadefault:CA证书默认值。
context:描述SSL选项的实例。

HTTPResponse 常用的方法与属性获取信息

import urllib.request    # 导入request子模块
url = 'https://www.python.org/'
response = urllib.request.urlopen(url=url)  # 发送网络请求
print('响应状态码为:',response.status)
print('响应头所有信息为:',response.getheaders())
print('响应头指定信息为:',response.getheader('Accept-Ranges'))
# 读取HTML代码并进行utf-8解码
print('Python官网HTML代码如下:\n',response.read().decode('utf-8'))

运行:

响应状态码为: 200
响应头所有信息为: [('Connection', 'close'), ('Content-Length', '50771'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'SAMEORIGIN'), ('Via', '1.1 varnish, 1.1 varnish'), ('Accept-Ranges', 'bytes'), ('Date', 'Sat, 17 Aug 2024 04:05:29 GMT'), ('Age', '883'), ('X-Served-By', 'cache-iad-kiad7000025-IAD, cache-nrt-rjtf7700020-NRT'), ('X-Cache', 'HIT, HIT'), ('X-Cache-Hits', '461, 64'), ('X-Timer', 'S1723867530.760647,VS0,VE0'), ('Vary', 'Cookie'), ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload')]
响应头指定信息为: bytes

使用urlopen()方法发送POST请求

import urllib.request    # 导入urllib.request模块
import urllib.parse      # 导入urllib.parse模块
url = 'https://www.httpbin.org/post'    # post请求测试地址
# 将表单数据转换为bytes类型,并设置编码方式为utf-8
data = bytes(urllib.parse.urlencode({'hello':'python'}),encoding='utf-8')
response = urllib.request.urlopen(url=url,data=data)  # 发送网络请求
print(response.read().decode('utf-8'))    # 读取HTML代码并进行

运行:

{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "hello": "python"
  },
  "headers": {
    "Accept-Encoding": "identity",
    "Content-Length": "12",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "www.httpbin.org",
    "User-Agent": "Python-urllib/3.7",
    "X-Amzn-Trace-Id": "Root=1-66c02297-6c016ea61ad2e00e078c48d7"
  },
  "json": null,
  "origin": "61.136.223.36",
  "url": "https://www.httpbin.org/post"
}

设置网络超时
捕获超时异常处理网络超时

import urllib.request  # 导入urllib.request模块
import urllib.error  # 导入urllib.error模块
import socket  # 导入socket模块

url = 'https://www.python.org/'  # 请求地址
try:
    # 发送网络请求,设置超时时间为0.1秒
    response = urllib.request.urlopen(url=url, timeout=0.1)
    print(response.read().decode('utf-8'))  # 读取HTML代码并进行utf-8解码
except urllib.error.URLError as error:  # 处理异常
    if isinstance(error.reason, socket.timeout):  # 判断异常是否为超时异常
        print('当前任务已超时,即将执行下一任务!')

运行:

当前任务已超时,即将执行下一任务!

复杂的网络请求

通过上一节的学习可以得知,urlopen()方法能够发送一个最基本的网络请求,但这并不是一个完整的网络请求。如果要构建一个完整的网络请求,还需要在请求中添加 Headers、Cookies以及代理IP等内容,这样才能更好的模拟一个浏览器所发送的网络请求。Request类则可以构建一个多种功能的请求对象,其语法格式如下:

urllib. request. Request(url, data-None, headers-{}, origin_req_host-None, unverifiable=False, method=None)

url:需要访问网站的URL完整地址。
data:该参数默认为None,通过该参数确认请求方式,如果是None,表示请求方式为GET,否则请求方式为POST。在发送POST请求时,参数data需要以字典形式的数据作为参数值,并且需要将字典类型的参数值转换为字节类型的数据才可以实现 POST请求。
headers:设置请求头部信息,该参数为字典类型。添加请求头信息最常见的用法就是修改User-Agent来伪装成浏览器。例如,headers ={‘User-Agent’:‘Mozilla/5.0(Windows NT 10.0;
WOW64)AppleWebKit/537.36(KHTML,like Gecko)Chrome/83.0.4103.61 Safari/537.36’},表示伪装谷歌浏览器进行网络请求。
origin_req_host:用于设置请求方的host名称或者是IP。
unverifiable:用于设置网页是否需要验证,默认是False。
method:用于设置请求方式,如GET、POST等,默认为GET请求。
设置请求头信息
如果需要设置请求头信息,首先通过 Request类构造一个带有 headers 请求头信息的 Request 对象,然后为urlopen()方法传入 Request对象,再进行网络请求的发送。示例代码如下:

import urllib.request  # 导入urllib.request模块
import urllib.parse    # 导入urllib.parse模块
url = 'https://www.httpbin.org/post'  # 请求地址
# 定义请求头信息
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36'}
# 将表单数据转换为bytes类型,并设置编码方式为utf-8
data = bytes(urllib.parse.urlencode({'hello':'python'}),encoding='utf-8')
# 创建Request对象
r = urllib.request.Request(url=url,data=data,headers=headers,method='POST')
response = urllib.request.urlopen(r)  # 发送网络请求
print(response.read().decode('utf-8'))  # 读取HTML代码并进行utf-8解码

运行:

{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "hello": "python"
  },
  "headers": {
    "Accept-Encoding": "identity",
    "Content-Length": "12",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "www.httpbin.org",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36",
    "X-Amzn-Trace-Id": "Root=1-66c024ad-1d1900532e58a6e548b8eacc"
  },
  "json": null,
  "origin": "61.136.223.36",
  "url": "https://www.httpbin.org/post"
}

异常处理
在实现网络请求时,可能会出现很多异常错误,Urllib模块中的urllib.error 子模块,包含了URLError与 HTTPError两个比较重要的异常类。
调用reason,属性处理URLError异常

import urllib.request    # 导入urllib.request模块
import urllib.error      # 导入urllib.error模块
try:
    # 向不存在的网络地址发送请求
    response = urllib.request.urlopen('http://site2.rjkflm.com:666/123index.html')
except urllib.error.URLError as error:    # 捕获异常信息
    print(error.reason)                    # 打印异常原因

运行:

[Errno 11001] getaddrinfo failed

HTTPError类是URLError类的子类,主要用于处理HTTP请求所出现的异常,该类有以下三个属性:
code:返回HTTP状态码。
reason:返回错误原因。
headers:返回请求头。
双重异常的捕获
由于 HTTPError 是 URLError的子类,有时 HTTPError类会有捕获不到的异常,所以可以先捕获子类HTTPError的异常,然后再去捕获父类URLError的异常,这样可以起到双重保险的作用。示例代码如下:

import urllib.request    # 导入urllib.request模块
import urllib.error      # 导入urllib.error模块
try:
    # 向不存在的网络地址发送请求
    response = urllib.request.urlopen('https://www.python.org/',timeout=0.1)
except urllib.error.HTTPError as error:    # HTTPError捕获异常信息
    print('状态码为:',error.code)                      # 打印状态码
    print('HTTPError异常信息为:',error.reason)         # 打印异常原因
    print('请求头信息如下:\n',error.headers)           # 打印请求头
except urllib.error.URLError as error:     # URLError捕获异常信息
    print('URLError异常信息为:',error.reason)

运行:

URLError异常信息为: timed out

解析链接

Urllib 模块中提供了parse 子模块,主要用于解析URL,可以实现 URL 的拆分或者是组合。它支持多种协议的URL处理,如 file、ftp、gopher、hdl、http、https、imap、mailto、mms、news、nntp、prospero、rsync、rtsp、rtspu、sftp、shttp、sip、sips、snews、SVn、svn+ssh、telnet、wais、ws、wss。
拆分 URL
使用urlparse()方法拆分URL

import urllib.parse    #导入urllib.parse模块
parse_result = urllib.parse.urlparse('https://docs.python.org/3/library/urllib.parse.html')
print(type(parse_result))    # 打印类型
print(parse_result)          # 打印拆分后的结果

运行:

<class 'urllib.parse.ParseResult'>
ParseResult(scheme='https', netloc='docs.python.org', path='/3/library/urllib.parse.html', params='', query='', fragment='')

从以上的运行结果中可以看出,调用urlparse()方法将返回一个ParseResult对象此对象,由6部分组成:scheme表示协议,netloc表示域名,path表示访问的路径,params表示参数,query表示查询条件,fragment表示片段标识符。
使用urlsplit()方法拆分URL
urlsplit()方法与urlparse()方法类似,都可以实现URL的拆分。只是urlsplit()方法不再单独拆分params这部分内容,而是将 params合并到path当中,所以返回的结果中只有5部分内容,并且返回的数据类型为 SplitResult。示例代码如下:

import urllib.parse    #导入urllib.parse模块
# 需要拆分的URL
url = 'https://docs.python.org/3/library/urllib.parse.html'
print(urllib.parse.urlsplit(url))     # 使用urlsplit()方法拆分URL
print(urllib.parse.urlparse(url))     # 使用urlparse()方法拆分URL

运行:

SplitResult(scheme='https', netloc='docs.python.org', path='/3/library/urllib.parse.html', query='', fragment='')
ParseResult(scheme='https', netloc='docs.python.org', path='/3/library/urllib.parse.html', params='', query='', fragment='')

组合URL
使用urlunparse()方法组合URL

import urllib.parse    #导入urllib.parse模块
list_url = ['https','docs.python.org','/3/library/urllib.parse.html','','','']
tuple_url = ('https','docs.python.org','/3/library/urllib.parse.html','','','')
dict_url = {'scheme':'https','netloc':'docs.python.org','path':'/3/library/urllib.parse.html','params':'','query':'','fragment':''}
print('组合列表类型的URL:',urllib.parse.urlunparse(list_url))
print('组合元组类型的URL:',urllib.parse.urlunparse(tuple_url))
print('组合字典类型的URL:',urllib.parse.urlunparse(dict_url.values()))

运行:

组合列表类型的URL: https://docs.python.org/3/library/urllib.parse.html
组合元组类型的URL: https://docs.python.org/3/library/urllib.parse.html
组合字典类型的URL: https://docs.python.org/3/library/urllib.parse.html

使用urlunparse()方法组合URL时,需要注意可迭代参数中的元素必须是6个。
使用urlunsplit()方法组合URL

import urllib.parse    #导入urllib.parse模块
list_url = ['https','docs.python.org','/3/library/urllib.parse.html','','']
tuple_url = ('https','docs.python.org','/3/library/urllib.parse.html','','')
dict_url = {'scheme':'https','netloc':'docs.python.org','path':'/3/library/urllib.parse.html','query':'','fragment':''}
print('组合列表类型的URL:',urllib.parse.urlunsplit(list_url))
print('组合元组类型的URL:',urllib.parse.urlunsplit(tuple_url))
print('组合字典类型的URL:',urllib.parse.urlunsplit(dict_url.values()))

运行:

组合列表类型的URL: https://docs.python.org/3/library/urllib.parse.html
组合元组类型的URL: https://docs.python.org/3/library/urllib.parse.html
组合字典类型的URL: https://docs.python.org/3/library/urllib.parse.html

连接URL
使用urljoin()方法连接URL

import urllib.parse    #导入urllib.parse模块
base_url = 'https://docs.python.org'   # 定义基础链接
# 第二参数不完整时
print(urllib.parse.urljoin(base_url,'3/library/urllib.parse.html'))
# 第二参数完成时,直接返回第二参数的链接
print(urllib.parse.urljoin(base_url,'https://docs.python.org/3/library/urllib.parse.html#url-parsing'))

运行:

https://docs.python.org/3/library/urllib.parse.html
https://docs.python.org/3/library/urllib.parse.html#url-parsing

URL的编码与解码
URL编码是GET请求中比较常见的,是将请求地址中的参数进行编码,尤其是对于中文参数。parse子模提供了urlencode()方法与 quote()方法用于实现URL的编码,而unquote()方法可以实现对加密后的URL 进行解码操作。
使用urlencode()方法编码请求参数
urlencode()方法接收一个字典类型的值,所以要想将URL 进行编码需要先将请求参数定义为字典类型,然后再调用urlencode()方法进行请求参数的编码。示例代码如下:

import urllib.parse    #导入urllib.parse模块
base_url = 'http://httpbin.org/get?'    # 定义基础链接
params = {'name':'Jack','country':'中国','age':30}  # 定义字典类型的请求参数
url = base_url+urllib.parse.urlencode(params)       # 连接请求地址
print('编码后的请求地址为:',url)

运行:

编码后的请求地址为: http://httpbin.org/get?name=Jack&country=%E4%B8%AD%E5%9B%BD&age=30

地址中“%E4%B8%AD%E5%9B%BD&”内容为中文(中国)转码后的效果。
使用quote()方法编码字符串参数
quote()方法与urlencode()方法所实现的功能类似,但是urlencode()方法中只接收字典类型的参数,而quote()方法则可以将一个字符串进行编码。示例代码如下:

import urllib.parse    #导入urllib.parse模块
base_url = 'http://httpbin.org/get?country='    # 定义基础链接
url = base_url+urllib.parse.quote('中国')        # 字符串编码
print('编码后的请求地址为:',url)

运行:

编码后的请求地址为: http://httpbin.org/get?country=%E4%B8%AD%E5%9B%BD

使用unquote()方法解码请求参数
unquote()方法可以将编码后的URL 字符串逆向解码,无论是通过urlencode()方法或者是 quote()
方法所编码的URL字符串都可以使用 unquote()方法进行解码。示例代码如下:

import urllib.parse    #导入urllib.parse模块
u = urllib.parse.urlencode({'country':'中国'})  # 使用urlencode编码
q=urllib.parse.quote('country=中国')              # 使用quote编码
print('urlencode编码后结果为:',u)
print('quote编码后结果为:',q)
print('对urlencode解码:',urllib.parse.unquote(u))
print('对quote解码:',urllib.parse.unquote(q))

运行:

urlencode编码后结果为: country=%E4%B8%AD%E5%9B%BD
quote编码后结果为: country%3D%E4%B8%AD%E5%9B%BD
对urlencode解码: country=中国
对quote解码: country=中国

URL 参数的转换
使用parse_qs()方法将参数转换为字典类型
请求地址的URL是一个字符串,如果需要将其中的参数转换为字典类型,可以先使用urlsplit()方
法拆分 URL,然后再调用 query属性获取URL 中的参数,最后使用 parse_qs()方法将参数转换为字典类型的数据。示例代码如下:

import urllib.parse    #导入urllib.parse模块
# 定义一个请求地址
url = 'http://httpbin.org/get?name=Jack&country=%E4%B8%AD%E5%9B%BD&age=30'
q = urllib.parse.urlsplit(url).query   # 获取需要的参数
q_dict = urllib.parse.parse_qs(q)      # 将参数转换为字典类型的数据
print('数据类型为:',type(q_dict))
print('转换后的数据:',q_dict)

运行:

数据类型为: <class 'dict'>
转换后的数据: {'name': ['Jack'], 'country': ['中国'], 'age': ['30']}

在这里插入图片描述

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值