Python爬虫自动化从入门到精通第2天(urllib库的使用)

文章介绍了Python内置的urllib库在爬虫中的应用,包括urlopen()方法的使用,HTTPResponse对象的常见方法,如何构造Request对象以进行更复杂的HTTP请求,以及如何设置代理服务器和超时时间。此外,还讨论了在网络请求中可能遇到的URLError和HTTPError异常的捕获处理。
摘要由CSDN通过智能技术生成

urllib库概述

urllib库是Python内置的HTTP请求库,它可以看作处理URL的组件集合。urllib库包含四大模块:
(1)urllib.request: 请求模块
(2)urllib.error: 异常处理模块
(3)urllib.parse: URL解析模块
(4)urllib.robotparser:robots.txt协议

快速使用urllib库爬取网页

爬取网页其实就是通过URL获取网页信息,这段网页信息的实质就是一段附加了JavaScript和CSS的HTML代码。如果把网页比作一个人,那么HTML就是他的骨架,JavaScript是他的肌肉,CSS是他的衣服。由此看来,网页最重要的数据部分是存在于HTML中的。

快速爬取一个网页

urllib库的使用比较简单,下面是使用urllib快速爬取一个网页,具体代码如下:

import urllib.request

# 调用urllib.request库的urlopen()方法,并传入一个url
response = urllib.request.urlopen("https://www.baidu.com")

# 使用read()方法读取获取到的网页内容
html = response.read().decode('UTF-8')

# 打印网页内容
print(html)

上述代码就是一个简单的爬取网页案例,爬取的网页结果如下:
在这里插入图片描述

实际上,如果在浏览器上打开百度首页,右击选择“查看网页源代码”命令,就会发现刚才打印出来的内容一模一样。也就是说,上述案例仅仅用了几行代码就把百度首页的全部代码下载下来了。

分析urlopen()方法

上一小节在爬取网页的时候,有一句核心的爬虫代码,如下所示:

response = urllib.request.urlopen('http://www.baidu.com')

代码调用的是urllib.request模块中的urlopen()方法,他传入了一个百度首页的URL,用的协议是HTTP,这是urlopen()方法最简单的用法。其实urlopen()方法可以接受多个参数,该方法的定义格式如下:

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

上述方法定义中的参数详细介绍如下:
(1)url:表示目标资源在网站中的位置,可以是一个表示URL地址的字符串,也可以是一个urllib.request对象。
(2)data:用来指明向服务器发送请求的额外信息。HTTP协议是Python支持的众多网络通信协议(如HTTP、HTTPS、FIP等)中唯一使用data参数的。也就是说,只有打开http网址时,data参数才有作用。data默认为None,此时是以GET的方式发送请求,当用户设置data参数时,需要将发送的请求方式改为POST。
(3)timeout:可选参数,该参数用于设置超时时间,单位是秒。
(4)cafile/capath/cadefault:用于实现可信任的CA证书的HTTPS请求,这些参数很少使用。
(5)context:实现SSL加密传输,该参数很少使用。

使用HTTPResponse对象

使用urllib.request模块中的urlopen()方法发送请求后,服务器返回的响应内容封装在一个HTTPResponse类型的对象中。示例代码如下:

import urllib.request

response = urllib.request.urlopen("http://www.baidu.com")

print(type(response))

执行示例代码,输出结果为:
在这里插入图片描述
从输出结果可以看出,HTTPResponse类属于Http.client模块,该类提供了获取URL、状态码、响应内容等一系列方法。常见的方法如下:
(1)geturl():用于获取响应内容的URL,该方法可以验证发送的HTTP请求是否被重新调配。
(2)info():返回页面的元信息。
(3)getcode():返回HTTP请求的响应状态码

下面使用一段代码演示这几个方法的使用,具体如下:

import urllib.request

response = urllib.request.urlopen("http://www.baidu.com")

# 获取响应信息对应的URL
print(response.geturl())

# 获取响应码
print(response.getcode())

# 获取页面元信息
print(response.info())

执行上述代码,其输出结果如下:
在这里插入图片描述

构造Request对象

当使用urlopen()方法发送一个请求时,如果希望执行更为复杂的操作(如增加HTTP报头),则必须创建一个Request对象来作为urlopen()方法的参数。下面同样以百度首页为例,演示如何使用Request对象来爬取数据。示例代码如下:

import urllib.request

# 将url作为Request()方法的参数,构造并返回一个Request对象
request = urllib.request.Request('http://www.baidu.com')

# 将Request对象作为urlopen()方法的参数,发送给服务器并接受响应
response = urllib.request.urlopen(request)

# 使用read()方法读取获取到的网页内容
html = response.read().decode('UTF-8')

# 打印网页内容
print(html)

在使用urllib库发送URL时,推荐使用构造Request对象的方法。因为在发送请求时,除了必须设置的url参数外,还可能会加入更多的内容,例如下面参数:
(1)data:默认为空,该参数表示提交表单数据,同时HTTP请求方法将从默认的GET方式改为POST方式。
(2)header:默认为空,该参数时一个字典类型,包含了需要发送的HTTP报头的键值对。

下面也是一个构造Request对象的案例,该案例在构造Request对象时传入data和headers参数(对于一些需要登录的网站,如果不是从浏览器发出的请求,是不能获得响应内容的。针对这种情况,需要将爬虫程序发出的请求伪装成一个浏览器发出的请求。伪装浏览器需要自定义请求报头,也就是在发送Request请求时,加入特定的Headers。可以通过查看网页,也可以通过调用Request.add_header()即可,如果想查看已有的Headers,可以通过调用Request_header()查看。)具体代码如下:

import urllib.request
import urllib.parse
url = 'http://www.baidu.com'

'''
# 添加自定义请求
# 调用Request.add_header()添加/修改一个特定的header
request.add_header('connection','keep-alive')
# 通过调用Request.get_header()查看header信息
request.get_header(header_name = 'connection')

'''

# 添加特定Headers---请求伪装
header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'}

dict_demo = {'name':'baidu'}

# 编码转换
data = bytes(urllib.parse.urlencode(dict_demo).encode('UTF-8'))

# 将url作为Request()方法的参数,构造并返回一个Request对象
request = urllib.request.Request(url,data=data,headers=header)

# 将Request对象作为urlopen()方法的参数,发送给服务器并接受响应
response = urllib.request.urlopen(request)

# 使用read()方法读取获取到的网页内容
html = response.read().decode('UTF-8')

# 打印网页内容
print(html)

上述案例可以实现百度首页的爬取。通过构造Request对象的方式,服务器会根据发送的请求返回对应的响应内容,这种做法在逻辑上也是非常清晰明确的。

代理服务器

很多网站会检测某段时间某个IP的访问次数,如果同一IP访问过于频繁,那么该网站会禁止来自该IP的访问。针对这个情况,可以使用代理服务器,每隔一段时间换一个代理。如果某个IP被禁止,可以换成其他IP继续爬取数据,从而可以有效解决被网站禁止访问的情况,代理多用于防止”防爬虫“机制。

简单的自定义opener

opener是urllib.request.OpenerDirector类的对象,之前一直使用搞得urlopen就是模块构建好的一个opener,但是它不支持代理、cookie等其他的HTTP/HTTPS高级功能。所以,如果想要设置代理,不能使用自带的urlopen,而是要自定义opener对象。自定义opener需要执行下列3个步骤:

  • 使用相关的Handler处理器创建特定功能的处理器对象。
  • 通过urllib.request.build_opener()方法使用这些处理器对象创建自定义的opener对象。
  • 使用自定义的opener对象,调用open()方法发送请求。这里需要注意的是,如果程序中所有的请求都使用自定义opener,可以使用urllib2.install_opener()将自定义的opener对象定义为全局opener,表示之后凡是调用urlopen,都将使用自定义的opener.

下面实现一个最简单的自定义opener,具体代码如下:

import urllib.request

# 构建一个HTTPHandler处理器对象,支持处理HTTP请求
http_handler = urllib.request.HTTPHandler()

# 调用urllib2.build_opener()方法,创建支持处理HTTP请求的opener对象
opener = urllib.request.build_opener(http_handler)

# 构建Request请求
request = urllib.request.Request('http://www.baidu.com/')

# 调用自定义opener对象的open()方法,发送request请求
# 注意区别(不在通过urllib.request.urlopen()发送请求)
response = opener.open(request)

# 获取服务器响应内容
print(response.read())

上述方式发送请求得到的结果和使用urllib.request.urlopen发送的HTTP/HTTPS请求得到的结果是一样的。吐过在HTTPHandler()方法中增加参数debuglever = 1,会将DebugLog打开,这样程序在执行时,会把收包和发包的报头自动打印出来,以方便调式。示例代码如下:

# 构建一个HTTPHandler处理器对象,同时开启Debug Log,debuglevel值设置为1
http_handler = urllib.request.HTTPHandler(debuglevel=1)

设置代理服务器

用户可以使用urllib.request中的ProxyHandler()方法设置代理服务器,下面就通过示例说明如何使用自定义opener来设置代理服务器。代码如下:

import urllib.request

# 构建两个代理Handler,一个有代理IP(通过字典的形式),一个没有
httpproxy_handler = urllib.request.ProxyHandler({'http':'117.41.38.18'})

nullproxy_handler = urllib.request.ProxyHandler()

# 定义一个代理开关
proxy_switch = True

# 通过urllib.request.build_opener()方法使用代理Handler对象创建自定义opener对象
# 根据代理开关是否打开,使用不同的代理模式
if proxy_switch:
    opener = urllib.request.build_opener(httpproxy_handler)
else:
    opener = urllib.request.build_opener(nullproxy_handler)

request = urllib.request.Request('http://www.baidu.com')

# 返回响应
response = opener.open(request)

print(response.read())

获取免费开放的代理基本没有成本,用户可以在一些代理网站上手机这些免费的代理,测试后如果可以用,就把他收集起来用在爬虫上面。这里博主给推荐一个免费好用的高匿名HTTP免费代理IP!!!

超时设置

假设有个需求,要爬取1000个网站,如果其中有100个网站需要等待30s才能返回数据,如果要返回所有的数据,至少需要等待3000s,如此长时间的等待显然是不可能的,为此可以为HTTP请求设置超时时间,一旦超过这个时间,服务器还没有返回响应内容,就会抛出一个超时异常,这个异常需要使用try语句来捕获。
例如,使用快代理(一个开放代理网站)中的IP,他的响应速度需要2秒。此时,如果将超时时间设置为1s,程序就会抛出异常。具体代码如下:

import urllib.request

try:
    url = 'http://www.baidu.com'

    # timeout 设置超时时间
    file = urllib.request.urlopen(url,timeout=1)
    result = file.read()
    print(result)
    
except Exception as error:
    print(error)

运行程序后,输出结果为:

<urlopen  error  timed  out>

常见的网络异常

当使用urlopen()方法发送HTTP请求时,如果urlopen()不能处理返回的响应内容,就会产生错误。这里将针对这两个常见的异常(URLError和HTTPError)以及对他们的错误处理进行简单的介绍。

URLError异常捕获

URLError产生的原因主要有以下几种:

  • 没有连接网络。
  • 服务器连接失败
  • 找不到指定的服务器

代码演示如下:

import urllib.request
import urllib.error

request = urllib.request.Request('https://www.baidu.com')

try:
    urllib.request.urlopen(request,timeout=5)
    
except urllib.error.URLError as error:
    print(error)

运行程序后,输出结果:

<urlopen  error  [Error 11001]  getaddrinfo  failed>

上述报错信息是urlopen error,错误代码是11001。发生错误的原因是没有找到指定的服务器。

HttpError异常和捕获

每个服务器的HTTP响应都有一个数字响应码,这些响应码有些表示无法处理请求内容。如果无法处理,urlopen()会抛出HTTPError。HTTPError是URLError的子类,他的对象拥有一个整型的code属性,表示服务器返回的错误代码。例如:

import urllib.request
import urllib.error

request = urllib.request.Request('https://www.baidu.com/net')

try:
    urllib.request.urlopen(request)

except urllib.error.HTTPError as error:
    print(error.code)

输出结果为:

404

上述输出了404的错误代码,其含义是没有找到这个页面。这里需要说明的是,不同的响应码代表不同的含义,例如100 ~ 200范围的号码表示成功,而错误码的范围在400~599。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ProgramStack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值