概述
urllib
是 Python 标准库中用于处理 URL(统一资源定位符)相关操作的模块,它提供了多个子模块,用于执行网络请求、解析 URL、处理错误以及解析 robots.txt 文件等。以下是 urllib
的子模块:
子模块
urllib.request
:提供打开和读取 URL 的功能。支持多种网络协议,如 HTTP、FTP 等。urllib.error
:包含与网络请求相关的异常类,用于处理错误和异常情况。urllib.parse
:用于解析和构建 URL,提供各种操作,如分割、组合、编码和解码。urllib.robotparser
:用于解析网站的robots.txt
文件,确定哪些页面可以被爬取。
优点
- 内置模块:作为 Python 标准库的一部分,无需单独安装。
- 全面功能:支持多种网络协议和操作,适用于多种网络操作需求。
- 高度可定制:用于处理 URL 的多个方面,如打开、读取、解析等。
缺点
- 较低层次的 API:与一些第三方库相比(如
requests
),urllib
的 API 较为底层,可能需要编写更多的代码。 - 繁琐的错误处理:错误处理需要额外的代码,相比使用像
requests
这样的库可能更复杂。
同类产品对比
产品 | 优点 | 缺点 | 适用背景 | 社区支持 |
---|---|---|---|---|
urllib | 标准库,全面 | API 较底层 | 网络请求,URL 操作 | Python 社区 |
requests | API 简单 | 需要单独安装 | HTTP 请求 | Python 社区 |
httplib2 | 功能丰富 | 使用复杂 | HTTP 请求 | Python 社区 |
urllib.request
方法 | 功能描述 | 示例 |
---|---|---|
urlopen() | 打开并读取一个 URL 的内容 | urllib.request.urlopen(url) |
urlretrieve() | 将 URL 指向的文件下载到本地 | urllib.request.urlretrieve(url, filename) |
build_opener() | 构建一个可自定义的 Opener 对象 | opener = urllib.request.build_opener() |
install_opener() | 安装全局的 Opener | urllib.request.install_opener(opener) |
HTTPBasicAuthHandler() | HTTP 基础认证处理程序 | handler = urllib.request.HTTPBasicAuthHandler() |
HTTPCookieProcessor() | 用于处理 HTTP cookies | handler = urllib.request.HTTPCookieProcessor() |
ProxyHandler() | 设置代理 | proxy = urllib.request.ProxyHandler({'http': 'http://www.example.com:8080'}) |
Request() | 创建一个请求对象,用于定制 HTTP 头等 | req = urllib.request.Request(url, headers={...}) |
urlopen()
打开 URL
import urllib.request
# 打开一个网页
response = urllib.request.urlopen('http://www.example.com')
# 读取网页内容
data = response.read()
# 输出网页内容
print(data)
urlretrieve()
下载文件
import urllib.request
# 从指定 URL 下载文件,并保存到本地
urllib.request.urlretrieve('http://www.example.com/file.txt', 'local_file.txt')
build_opener()
和 install_opener()
build_opener()
传递一系列处理程序(handlers),这些处理程序用于定义如何处理各种 HTTP 功能,比如重定向、基础认证、cookies 等。一旦你使用 build_opener()
创建了一个 Opener
对象,你可以使用 install_opener()
来设置它作为默认的 Opener
。
import urllib.request
# 创建基础认证处理程序
auth_handler = urllib.request.HTTPBasicAuthHandler()
auth_handler.add_password('realm', 'host', 'username', 'password')
# 创建代理处理程序
proxy_handler = urllib.request.ProxyHandler({'http': 'http://www.proxy.com:8080'})
# 创建 Opener
opener = urllib.request.build_opener(auth_handler, proxy_handler)
# 安装 Opener
urllib.request.install_opener(opener)
# 使用 urlopen() 方法,这样会应用我们之前设置的所有处理程序
response = urllib.request.urlopen('http://www.example.com')
HTTP 基础认证 (HTTPBasicAuthHandler
)
import urllib.request
# 创建一个 HTTPBasicAuthHandler 对象
auth_handler = urllib.request.HTTPBasicAuthHandler()
# 添加认证信息
auth_handler.add_password('realm', 'host', 'username', 'password')
# 创建并安装 opener
opener = urllib.request.build_opener(auth_handler)
urllib.request.install_opener(opener)
HTTPCookieProcessor
处理 Cookies
import urllib.request
import http.cookiejar
# 创建一个 CookieJar 对象
cookie_jar = http.cookiejar.CookieJar()
# 创建一个 HTTPCookieProcessor 对象
cookie_handler = urllib.request.HTTPCookieProcessor(cookie_jar)
# 构建和安装 opener
opener = urllib.request.build_opener(cookie_handler)
ProxyHandler
设置代理
import urllib.request
# 创建一个 ProxyHandler 对象
proxy_handler = urllib.request.ProxyHandler({'http': 'http://www.proxy.com:8080'})
# 构建并安装 opener
opener = urllib.request.build_opener(proxy_handler)
Request()
自定义请求
import urllib.request
# 创建一个 Request 对象
req = urllib.request.Request(url='http://www.example.com', headers={'User-Agent': 'MyApp/1.0'})
# 使用 urlopen 打开自定义的请求
response = urllib.request.urlopen(req)
urllib.error
方法 | 功能描述 |
---|---|
URLError | 所有 urllib 产生的异常的基类 |
HTTPError | 处理 HTTP 错误状态,继承自 URLError |
ContentTooShortError | 在下载过程中,数据不足时抛出的异常 |
URLError
当使用 urllib.request
打开一个 URL 失败时,通常会抛出 URLError
异常。
import urllib.request
import urllib.error
try:
response = urllib.request.urlopen('http://www.nonexistentwebsite.com')
except urllib.error.URLError as e:
print(e.reason)
HTTPError
当服务器返回 HTTP 错误状态码(如 404、500 等)时,会抛出 HTTPError
。
import urllib.request
import urllib.error
try:
response = urllib.request.urlopen('http://www.example.com/404')
except urllib.error.HTTPError as e:
print(f'HTTP Error Code: {e.code}')
print(f'Reason: {e.reason}')
ContentTooShortError
如果使用 urlretrieve()
函数,但获取的数据长度与 Content-Length
头中声明的长度不匹配时,会抛出 ContentTooShortError
。
import urllib.request
import urllib.error
try:
urllib.request.urlretrieve('http://www.example.com/file', 'local_file.txt')
except urllib.error.ContentTooShortError as e:
print('The downloaded data is less than expected.')
urllib.parse
方法 | 功能描述 | 示例 |
---|---|---|
urlparse() | 解析 URL,返回一个 ParseResult 对象 | urllib.parse.urlparse(url) |
urlunparse() | 将 ParseResult 对象转回 URL | urllib.parse.urlunparse(parse_result) |
urlsplit() | 类似于 urlparse() ,但不分割 params | urllib.parse.urlsplit(url) |
urlunsplit() | 将由 urlsplit() 返回的对象转回 URL | urllib.parse.urlunsplit(split_result) |
urljoin() | 合并两个 URL | urllib.parse.urljoin(base, url) |
urlencode() | 将字典或序列转换为 URL 查询字符串 | urllib.parse.urlencode(query_dict) |
quote() | 将字符串进行 URL 编码 | urllib.parse.quote(string) |
unquote() | 对 URL 编码的字符串进行解码 | urllib.parse.unquote(encoded_string) |
解析和构建 URL
from urllib.parse import urlparse, urlunparse, urlsplit, urlunsplit, urljoin
# 解析URL并返回ParseResult对象
parsed_url = urlparse('http://www.example.com/path?query=arg')
# 将ParseResult对象转换回URL
new_url = urlunparse(parsed_url)
# 类似于urlparse(),但不分割params
split_result = urlsplit('http://www.example.com/path?query=arg')
# 将由urlsplit()返回的对象转换回URL
original_url = urlunsplit(split_result)
# 合并两个URL
new_url = urljoin('http://www.example.com/path/', '/anotherpath.html')
转换查询字符串
from urllib.parse import urlencode
# 将字典或序列转换为URL查询字符串
query_dict = {'key1': 'value1', 'key2': 'value2'}
query_string = urlencode(query_dict)
URL 编码和解码
from urllib.parse import quote, unquote
# 将字符串进行URL编码
encoded = quote('a string with / and ?')
# 对URL编码的字符串进行解码
decoded = unquote(encoded)
urllib.robotparser
通过使用 urllib.robotparser
,你可以确保你的网络爬虫尊重网站的抓取策略,这是一种负责任的爬虫行为。
方法 | 功能描述 | 示例 |
---|---|---|
RobotFileParser() | 创建一个 RobotFileParser 对象 | rp = urllib.robotparser.RobotFileParser() |
set_url() | 设置 robots.txt 文件的 URL | rp.set_url('http://www.example.com/robots.txt') |
read() | 从设置的 URL 读取 robots.txt 文件 | rp.read() |
parse() | 用于手动解析 robots.txt 文件的行 | rp.parse(robots_txt_body.split("\n")) |
can_fetch() | 检查指定的 User-Agent 是否可以访问某个路径 | rp.can_fetch('*', 'http://www.example.com/page') |
mtime() | 获取最后一次获取 robots.txt 文件的时间(Unix 时间戳) | rp.mtime() |
modified() | 设置最后一次获取 robots.txt 文件的时间 | rp.modified() |
创建和设置 RobotFileParser
首先,你需要创建一个 RobotFileParser
对象,并设置要解析的 robots.txt
文件的 URL。
import urllib.robotparser
# 创建 RobotFileParser 对象
rp = urllib.robotparser.RobotFileParser()
# 设置 robots.txt 文件的 URL
rp.set_url('http://www.example.com/robots.txt')
# 从 URL 读取 robots.txt 文件
rp.read()
检查爬虫是否可以访问特定页面
使用 can_fetch()
方法,您可以检查指定的 User-Agent 是否被允许抓取特定的网页路径。
# 检查 '*'(所有 User-Agents)是否允许访问 '/page'
allowed = rp.can_fetch('*', 'http://www.example.com/page')
if allowed:
print("I can crawl this page.")
else:
print("I cannot crawl this page.")
手动解析 robots.txt
如果你需要手动解析 robots.txt
文件的内容,可以使用 parse()
方法。
# 假设 robots_txt_body 包含了 robots.txt 的文本内容
robots_txt_body = '''
User-agent: *
Disallow: /private/
'''
# 手动解析这些规则
rp.parse(robots_txt_body.split("\n"))