Python2与Python3中urllib库的差异及实战用法详解
本文详细解析Python2与Python3中urllib库的模块合并与API变更,重点介绍Python3环境下urllib.request的核心功能。内容涵盖发送GET/POST请求、处理URL参数与中文编码、定制请求头以规避403错误、下载远程资源、配置代理IP以及Cookie会话维持和异常处理机制,为网络爬虫开发提供完整参考。
本文旨在梳理urllib库在Python不同版本间的演进变化,并重点基于Python3.X版本,系统讲解urllib库的实际应用方法。
urllib库版本对照速查表
| Python2.X | Python3.X |
| urllib | urllib.request, urllib.error, urllib.parse |
| urllib2 | urllib.request, urllib.error |
| urllib2.urlopen | urllib.request.urlopen |
| urllib.urlencode | urllib.parse.urlencode |
| urllib.quote | urllib.request.quote |
| urllib2.Request | urllib.request.Request |
| urlparse | urllib.parse |
| urllib.urlretrieve | urllib.request.urlretrieve |
| urllib2.URLError | urllib.error.URLError |
| cookielib.CookieJar | http.CookieJar |
urllib是Python标准库中用于处理URL操作及页面爬取的核心模块,此外还有requests、httplib2等第三方库提供类似功能。
在Python2.X版本中,URL处理功能分散在urllib和urllib2两个模块中;而在Python3.X中,这些功能被统一整合至urllib模块下。通过上述对照表可以清晰看到主要API的变动路径,开发者可据此快速适配不同版本的Python代码。
相较于Python2.X,Python3.X在中文编码支持方面更为友好,因此下文将主要基于Python3.X环境,演示urllib库的常见操作技巧。
发送HTTP请求
import urllib.request r = urllib.request.urlopen(http://www.python.org/)
首先需导入urllib.request模块,调用urlopen()函数向指定URL发送请求,该函数返回一个http.client.HTTPResponse对象,用于后续处理响应数据。
在urlopen()调用中,可通过timeout参数设定等待响应的超时秒数,防止请求挂起。此外,可利用r.info()获取响应头信息,r.getcode()获取HTTP状态码,r.geturl()获取当前实际请求的URL地址。
读取响应内容
import urllib.request url = "http://www.python.org/" with urllib.request.urlopen(url) as r: r.read()
调用r.read()可将响应内容读取至内存,这通常对应网页的源代码(可通过浏览器“查看网页源代码”功能验证)。获取到的字符串数据可能需要通过decode()方法进行解码,以处理特定的字符编码。
传递URL参数
import urllib.request
import urllib.parse
params = urllib.parse.urlencode({'q': 'urllib', 'check_keywords': 'yes', 'area': 'default'})
url = "https://docs.python.org/3/search.html?{}".format(params)
r = urllib.request.urlopen(url)
若需向URL查询字符串传递数据,可将参数字典通过urlencode()函数进行编码处理。
编码后的params变量为字符串格式,字典中的每个键值对之间以'&'符号连接,例如:'q=urllib&check_keywords=yes&area=default'。
最终构建的完整URL示例为:https://docs.python.org/3/search.html?q=urllib&check_keywords=yes&area=default。
需要注意的是,urlopen()也支持直接接收已手动构建好的URL字符串。对于简单的GET请求,开发者可以不使用urlencode(),直接拼接URL后发起请求。不过,使用编码方法能使代码结构更模块化,逻辑也更清晰优雅。
传递中文参数
import urllib.request
searchword = urllib.request.quote(input("请输入要查询的关键字:"))
url = "https://cn.bing.com/images/async?q={}&first=0&mmasync=1".format(searchword)
r = urllib.request.urlopen(url)
以调用Bing图片接口查询关键字q的图片为例,若直接将中文字符串传入URL发起请求,可能会引发编码错误。此时应使用quote()函数对中文字符进行URL编码,必要时也可使用unquote()进行解码还原。
定制请求头
import urllib.request
url = 'https://docs.python.org/3/library/urllib.request.html'
headers = {
'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36',
'Referer': 'https://docs.python.org/3/library/urllib.html'
}
req = urllib.request.Request(url, headers=headers)
r = urllib.request.urlopen(req)
在爬取某些网页时,可能会遇到403 Forbidden错误,即服务器禁止访问。这通常是因为服务器对请求的Headers属性进行身份验证。例如,urllib库默认发送的请求中,User-Agent字段值为“Python-urllib/X.Y”(X为主版本号,Y为副版本号)。为了模拟浏览器行为,需通过urllib.request.Request()构建Request对象,并传入包含Headers属性的字典,以伪装请求来源。
所需的Headers具体信息,可通过浏览器开发者工具中的“检查”功能,在“Network”标签页查看目标网页的请求头获取;也可借助Fiddler、Wireshark等抓包分析软件进行提取。
除了上述方法,还可以利用urllib.request.build_opener()或req.add_header()来定制请求头,具体实现可参考官方示例代码。
在Python2.X环境中,通常需结合使用urllib和urllib2模块:利用urllib.urlencode()对URL参数进行编码,再通过urllib2.Request()构建Request对象以定制请求头,最后统一使用urllib2.urlopen()发送请求。
传递POST请求
import urllib.request
import urllib.parse
url = 'https://passport.cnblogs.com/user/signin?'
post = {
'username': 'xxx',
'password': 'xxxx'
}
postdata = urllib.parse.urlencode(post).encode('utf-8')
req = urllib.request.Request(url, postdata)
r = urllib.request.urlopen(req)
在进行注册、登录等需要提交表单的操作时,通常通过POST方式传递数据。
此时需先分析页面结构,构建表单数据post字典,使用urlencode()进行编码处理并返回字符串。由于POSTdata参数要求为bytes类型或file object,因此需指定'utf-8'编码格式进行转换。最后,通过Request()对象传递postdata,并使用urlopen()发送请求。
下载远程数据到本地
import urllib.request url = "https://www.python.org/static/img/python-logo.png" urllib.request.urlretrieve(url, "python-logo.png")
当需要爬取图片、视频等远程资源并保存至本地时,可使用urlretrieve()函数实现下载。
该函数的第一个参数为待下载的URL地址,第二个参数为下载文件在本地保存的路径。
示例代码演示了将Python官网logo下载至当前目录的过程,函数执行后返回一个元组(filename, headers),包含本地文件名及响应头信息。
设置代理IP
import urllib.request
url = "https://www.cnblogs.com/"
proxy_ip = "180.106.16.132:8118"
proxy = urllib.request.ProxyHandler({'http': proxy_ip})
opener = urllib.request.build_opener(proxy, urllib.request.HTTPHandler)
urllib.request.install_opener(opener)
r = urllib.request.urlopen(url)
若频繁爬取同一网页,可能导致IP被服务器屏蔽。此时可通过配置代理IP来解决访问限制问题。
首先从代理IP网站获取一个可用IP,构建ProxyHandler()对象,将'http'协议及代理IP以字典形式传入,以设置代理服务器信息。接着构建opener对象,传入proxy处理器和HTTPHandler类。最后通过install_opener()将opener设置为全局生效,此后调用urlopen()发送请求时,将自动使用配置的代理信息。
异常处理
import urllib.request
import urllib.error
url = "http://www.balabalabala.org"
try:
r = urllib.request.urlopen(url)
except urllib.error.URLError as e:
if hasattr(e, 'code'):
print(e.code)
if hasattr(e, 'reason'):
print(e.reason)
可使用URLError类来处理与URL相关的异常情况。导入urllib.error模块后,捕获URLError异常。由于仅当发生HTTPError异常(URLError的子类)时,异常对象e才具备状态码属性code,因此需先判断异常对象是否包含code属性,再行处理。
Cookie的使用
import urllib.request import http.cookiejar url = "http://www.balabalabala.org/" cjar = http.cookiejar.CookieJar() opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cjar)) urllib.request.install_opener(opener) r = urllib.request.urlopen(url)
HTTP协议本身是无状态的,Cookie用于维持会话间的状态。例如,某些网站要求登录后才能访问特定内容。首次可通过提交POST表单登录,后续爬取该网站其他页面时,可利用Cookie保持登录状态,避免每次请求都重新提交表单登录。
具体实现时,首先构建CookieJar()对象cjar,再使用HTTPCookieProcessor()处理器处理该CookieJar,并通过build_opener()构建opener对象。将该opener设置为全局后,调用urlopen()发送请求即可自动携带Cookie信息。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













