Python网络爬虫基本库的使用(大章)

本文详细介绍了Python中用于网络爬虫的urllib库,包括urllib.request模块的使用,如urlopen、data参数、timeout设置,以及异常处理。接着讲解了urllib.parse模块的URL解析方法,如urlencode、parse_qs等。此外,还讨论了urllib.error模块中的异常处理。然后,文章转向requests库,展示了其基础用法、POST请求、响应对象、文件上传、会话维持、SSL验证等功能。最后,简要提及了正则表达式的基础知识和httpx库的使用,强调了httpx对HTTP/2.0协议的支持。
摘要由CSDN通过智能技术生成

学习爬虫,最基本的操作就是模拟浏览器向服务器发出请求。Pyhton提供了功能齐全的类库来帮助我们实现这些需求。接下来,就让我们从最基础的部分开始了解HTTP库的使用方法吧。

urllib 的使用

版本:在Python2中,有urllib和urllib2两个库来实现请求的发送。而在python3中,已经不存在urllib2这个库了,统一为urllib。

简介:urllib是python内置的http请求库,也就是说不需要额外安装即可使用。它包含如下四个模块。

request:它是最基本的 HTTP 请求模块,可以用来模拟发送请求。就像在浏览器里输入网址然后回车一样,只需要给库方法传入URL及额外的参数,就可以模拟实现这个过程了

parse :一个工具模块,提供了许多 URL 处理方法,比如拆分、解析、合并等

error :常处理模块,如果出现请求错误,我们可以捕获这些异常,然后进行重试或其他操作以保证程序不会意外终止

robotparser :主要是用来识别网站的 robots.txt 文件,然后判断哪些网站可以爬,哪些网站不可以爬,它其实用得比较少
1、请求模块:urllib.request
urllib.request.urlopen()

urlopen()方法中的url参数可以是字符串,也可以是一个Request对象
作用 :向网站发起一个请求并获取响应
字节流 = response.read()
字符串 = response.read().decode(“utf-8”)

# url可以是字符串
import urllib.request

resp = urllib.request.urlopen('https://www.baidu.com')
print(resp.read().decode('utf-8'))  # read()获取响应对象的内容,内容是bytes字节流,需要转换成字符串

接下来,我们可以看看它返回的是什么,通过type()方法输出响应的类型:

import urllib.request

resp = urllib.request.urlopen('https://www.baidu.com')
print(type(resp))

>>> <class 'http.client.HTTPResponse'>
# 可以发现,它是一个HTTPResponse类型的对象,包含一些方法及属性
# 得到这个对象后,我们可以调用这些方法和属性,得到相应的一系列信息

例如,通过调用read()方法可以得到返回的网页内容,调用status属性或getcode()方法可以得到返回的状态码,调用geturl() 返回实际数据的URL(防止重定向问题)。

# 下面再通过一个实例来看看:

import urllib.request

resp = urllib.request.urlopen('http://www.baidu.com')
print(resp.status)      # 获取响应的状态码 和 getcode()作用相同
print(resp.getheaders())  # 获取响应头相关信息(元组列表)
print(resp.getheader('Server'))  # 获取具体的名称对应的值,"Server"大小写不区分

运行结果如下:
在这里插入图片描述
可见,前两个输出分别输出了响应状态码和响应的头信息,最后一个输出通过调用getheader()方法并传递一个参数,获得了响应头中的Server值,表示服务器是用Nginx搭建的。

如果想给链接传递一些参数,该怎样实现呢?

首先看一下urllib()函数的API:

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

可以发现,除了第一个参数可以传递URL之外,我们还可以传递其他内容,比如data(附加数据)、timeout(超时时间)等。

data参数:POST请求

data参数是可选的,如果要添加这个参数,则需要以bytes类型提交,可以通过bytes()方法转化,不能是str类型

也可以在Request方法中添加data参数 urllib.request.Request(url,data=data)

import urllib.request, urllib.parse

data = bytes(urllib.parse.urlencode('字典'), encoding='utf-8')   # 将字符串类型数据转换为bytes类型,该方法的第一个参数需要是str类型,第二个参数指定编码格式
resp = urllib.request.urlopen(url, data=data)
print(resp.read())
timeout参数:设置请求超时时间

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

#设置请求超时时间
import urllib.request

resp = urllib.request.urlopen('https://www.baidu.com', timeout=0.1)
print(resp.read().decode('utf-8'))

>>> urllib.error.URLError: <urlopen error timed out>

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

因此,我们可以通过设置这个超时时间来控制一个网页如果长时间未响应,就跳过它的抓取。这可以利用try except语句来实现,相关代码如下:

import urllib.request

try:
    resp = urllib.request.urlopen('https://www.baidu.com', timeout=0.1)
except urllib.error.URLError as e:
    print('TIME OUT')

这里我们请求https://www.baidu.com,设置超时时间为0.1秒,然后捕获该异常,并打印输出TIME OUT。
通过设置 timeout 这个参数来实现超时处理,有时还是很有用的
其他参数

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

前面讲解了 urlopen()方法的用法,通过这个最基本的方法,我们可以完成简单的请求和网页抓取。若需更加详细的信息,可以参见官方文档 https://docs.python.org/3/library/urllib.request.html

urllib.request.Request()

我们知道利用urlopen()方法可以实现最基本请求的发起,但这几个简单的参数并不足以构建一个完整的请求。如果请求中需要加入一个Headers等信息,就可以利用更强大的Request类来构建。

首先,我们通过一个实例来感受一下Request的用法:

import urllib.request

request = urllib.request.Request('http://www.baidu.com')
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))

可以发现,我们依然是用urlopen()方法来发送这个请求,只不过这次该方法的参数不再是URL,而是一个Request对象。这样,我们既可以将请求独立成一个对象,还可以更加灵活的配置参数。

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

urllib.request.Request(url, data=None, headers={
   },origin_req_host=None, unverifiable=False,method=None)
常用参数

url 参数用于请求URL,这是必传参数,其他都是可选参数

data 参数如果要传,必须传bytes(字节流)类型的

headers 参数是一个字典,它就是请求头,我们可以在构造请求时通过headers参数直接构造,也可以通过请求实例的add_header()方法添加。(添加请求头最常用的用法就是通过修改UA来伪装浏览器,默认的UA是Python-urllib)

method 参数是一个字符串,用来指示请求使用的方法,比如GET、POST等

下面我们传入多个参数构建请求来看一下:

from urllib import request, parse

headers = {
   'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)   Chrome/72.0.3626.109 Safari/537.36'}
data = bytes(parse.urlencode(dict), encoding='utf-8')
req = request.Request(url=url, data=data, headers=headers, method='POST')   # 构建请求对象
resp = request.urlopen(req)
print(resp.read().decode('utf-8'))

另外,headers也可以用add_header()方法添加:

req = request.Request(url=url, data=data, method='POST')   # 构建请求对象
req.add_header('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)   Chrome/72.0.3626.109 Safari/537.36')  # 为请求对象添加请求头
扩展

在上面的过程,我们虽然可以构造请求,但是对于一些更高级的操作(比如Cookies处理、代理设置等),我们应该怎么办呢?

接下来就需要更强大的工具Handler登场了。我们可以将其理解为各种处理器,又处理代理设置的,有处理登录验证的。利用它们,我们几乎可以做到HTTP请求中所有的事情。

首先介绍一下urllib.request模块里的BaseHandler类,它是所有其他Handler的父类。接下来就有各种Handler子类继承这个BaseHandler类。

另一个比较重要的类就是OPenerDirector,我们可以称之为Opener。我们之前用的urlopen()这个方法,实际上它就是urllib为我们提供的一个Opener。

我们可以利用Handler去构建特殊的Opener,去代替urlopen()方法进行工作。

下面简单举一个例子:

# ProxyHandler:用于设置代理,默认代理为空

from urllib.error import URLError
from urllib.request import ProxyHandler, build_opener

proxy_handler = ProxyHandler({
   
    'http':'120.26.208.102:88'})
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)

在这里,我们使用了ProxyHandler,其参数就是一个字典,键名是协议类型,键值是代理链接,可以添加多个代理。
然后,利用这个Handler构造一个特殊的Opener,之后发送请求即可。

2、解析模块:urllib.parse

它定义了处理URL的标准接口,例如实现URL各部分的抽取、合并以及链接的转换

urlencode()

作用:对字典类型数据进行编码(序列化)

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

import urllib.parse

wd = {
   'wd':'中国'}
result = urllib.parse.urlencode(wd)
print(result)
# wd=%E4%B8%AD%E5%9B%BD
parse_qs()

作用:将请求参数转化为字典类型,可解码

from urllib.parse import parse_qs,urlencode

result = urlencode({
   'wd':'中国','key':'人民币'})
print(result)
print(parse_qs(result))

# wd=%E4%B8%AD%E5%9B%BD&key=%E4%BA%BA%E6%B0%91%E5%B8%81
# {'wd': ['中国'], 'key': ['人民币']}
parse_qsl()

作用:将请求参数转化为元组组成的列表

from urllib.parse import parse_qsl,urlencode

result = urlencode({
   'wd':'中国','key':'人民币'})
print(result)
print(parse_qsl(result))

# wd=%E4%B8%AD%E5%9B%BD&key=%E4%BA%BA%E6%B0%91%E5%B8%81
# [('wd', '中国'), ('key', '人民币')]
quote()

作用:将字符串类型数据进行编码,转化为URL编码的格式

import urllib.parse

wd = '中国'
result = urllib.parse.quote(wd)
print(result)
# %E4%B8%AD%E5%9B%BD
unquote()

作用:对URL进行解码

import urllib.parse

wd = '%E4%B8%AD%E5%9B%BD'
result = urllib.parse.unquote(wd)
print(result)
# 中国
urlparse()

作用:进行URL的识别和分段

from urllib.parse import urlparse

result = urlparse('http://www.baidu.com/index.html;user?id=1#comment')
print(type(result))
print(result)

# <class 'urllib.parse.ParseResult'>
# ParseResult(scheme='http', netloc='www.baidu.com', path='/index.html', params='user', query='id=1', fragment='comment')

可以看到,返回结果是ParseResult类型的对象,包含六个部分,分别是scheme(协议)、netloc(域名)、path(访问路径)、params(参数)、query(查询条件)和fragment(锚点)

所以,可以得到一个标准的链接格式,具体如下:
scheme://netloc/path;params?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参数,返回的结果是https,但是相应的netloc解析为空。

allow_fragment:即是否忽略fragment。如果设置为False,f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值