Python 3 中的 urllib 库有四个模块,分别是urllib.request
,urllib.error
,urllib.parse
,urllib.robotparser。接下来我们对这四个模块做详细介绍 参考:
https://docs.python.org/3/library/
一,
urllib.request
1.1 urllib.request.urlopen
request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
参数含义:
url: 打开一个url,该url可以是一个字符串或者一个 Request 对象
data: 参数必须是一个字节对象 ,该对象指明发送到服务器的附加数据。如果不需要发送数据,可以是None]
timeout: 可选的参数 timeout 参数在秒的级别规定了一个连接尝试的阻塞等待时间(如果没有指定该参数,
全局的默认的超时时间将被启用),这个参数实际上只对http,https,ftp链接有效
cafile和capath: 可选的 cafile 和 capath 参数用来为https请求指明一套可信的CA证书。cafile 必须是包含了
一套证书的单独的文件,capath则应该指定这些证书文件的目录。
ssl.SSLContext.load_verify_locations()函数中可以找到更多信息
context: 如果 context 参数被指定,它必须是一个带有各样SLL选项的ssl.SSLContext实例
cadefault: 参数已经被弃用,可以不用管了。
接下来让我看看怎么应用
我们使用 urllib.request.urlopen() 去请求百度贴吧,并获取到它页面的源代码。
import urllib.request
url = "http://tieba.baidu.com"
response = urllib.request.urlopen(url)
html = response.read() # 获取到页面的源代码
print(html.decode('utf-8')) # 转化为 utf-8 编码
设置请求超时,有些请求可能因为网络原因无法得到响应。因此,我们可以手动设置超时时间。
当请求超时,我们可以采取进一步措施,例如选择直接丢弃该请求或者再请求一次。
import urllib.request
url = "http://tieba.baidu.com"
response = urllib.request.urlopen(url, timeout=1)
print(response.read().decode('utf-8'))
使用 data 参数提交数据,在请求某些网页时需要携带一些数据,我们就需要使用到 data 参数params 需要被转码成字节流。而 params 是一个字典。我们需要使用 urllib.parse.urlencode() 将字典转化为字符串。再使用 bytes() 转为字节流。最后使用 urlopen() 发起请求,请求是模拟用 POST 方式提交表单数据。
import urllib.parse
import urllib.request
url = "http://xx.xx.xx.xx/chitchat"
params = { "session":"1111","question":"你好" }
data = bytes(urllib.parse.urlencode(params), encoding='utf8')
response = urllib.request.urlopen(url, data=data)
print(response.read().decode('utf-8'))
1.2 urllib.request.Request
由上我们知道利用 urlopen() 方法可以发起简单的请求。但这几个简单的参数并不足以构建一个完整的请求,如果请求中需要加入headers(请求头)、指定请求方式等信息,我们就可以利用更强大的Request类来构建一个请求。
按照国际惯例,先看下 Request 的构造方法:
urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
url: 参数
是请求链接,这个是必传参数,其他的都是可选参数。
data: 参数
跟 urlopen() 中的 data 参数用法相同。
headers: 参数
是指定发起的 HTTP 请求的头部信息。headers 是一个字典。它除了在 Request 中添加,还可以
通过调用 Request实例的 add_header() 方法来添加请求头。
origin_req_host: 参数
指的是请求方的 host 名称或者 IP 地址。
unverifiable: 参数
表示这个请求是否是无法验证的,默认值是False。意思就是说用户没有足够权限来选择接收
这个请求的结果。例如我们请求一个HTML文档中的图片,但是我们没有自动抓取图像的权限,
我们就要将 unverifiable 的值设置成 True。
method: 参数
指的是发起的 HTTP 请求的方式,有 GET、POST、DELETE、PUT等
接下来看一个demo吧:
import urllib.parse
import urllib.request
url = 'https://fanyi.baidu.com/'
headers = {
'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
}
values = {
'from': 'zh',
'to':'en',
'query':'肥猪',
'transtype':'translang',
'simple_means_flag':'3'
}
data = urllib.parse.urlencode(values).encode("utf-8")
request = urllib.request.Request(url,data,headers)
response = urllib.request.urlopen(request).read().decode("utf-8")
print(response)
1.3 urllib.request.install_opener(opener)
urllib.request.build_opener
([handler, ...])
urllib.request.
ProxyHandler
(proxies=None)
在抓取一个网站的信息时,如果我们进行频繁的访问,就很有可能被网站检测到而被屏蔽,解决这个问题的方法就是使用ip代理 。在我们接入因特网进行上网时,我们的电脑都会被分配一个全球唯一地ip地址供我们使用,而当我们频繁访问一个网站时,网站也正是因为发现同一个ip地址访问多次而进行屏蔽的,所以这时候如果我们使用多个ip地址进行随机地轮流访问,这样被网站检测的概率就很小了,这时候如果我们再使用多个不同的headers,这时候就有多个ip+主机的组合,访问时被发现率又进一步减小了
步骤:
1、ProxyHandler类可以使用ip代理访问网页
proxy_support = urllib.request.ProxyHandler({}),其中参数是一个字典{‘类型’:'代理ip:端口号'}
2、定制、创建一个opener
opener = urllib.request.build_opener(proxy_support)
3、安装opener
urllib.request.install_opener(opener)
调用默认的opener
opener.open(url)
对于没有设置反爬虫机制的网站,我们只需要直接像上面那样引入ProxyHandler类进行处理,不需要考虑模仿浏览器
接下来看段例子:
import urllib.request
url="https://www.baidu.com"
for i in range(0,10000):
html = urllib.request.urlopen(url)
print(html.info())
print(i)
上面程序行351行就出错了这是由于我们在访问的时候,网站会记下我们的ip,当我们的ip访问量在一段时间内超过网站设定的上限值的时候,这个请求就会被拒绝了
改进后代码:
#coding:utf-8
from urllib.request import Request
from urllib.request import urlopen
import urllib
import random
def gethtml(url,proxies):
proxy = random.choice(proxies)
proxy_support = urllib.request.ProxyHandler({"http":proxy})
opener = urllib.request.build_opener(proxy_support)
urllib.request.install_opener(opener)
html = urlopen(url)
return html
url = "https://www.baidu.com"
proxies=["101.53.101.172:9999","171.117.93.229:8118","119.251.60.37:21387","58.246.194.70:8080"]
for i in range(100):
try:
html = gethtml(url,proxies)
print(html.info())
print(i)
except:
print("故障")
1.4 urllib.request.pathname2url
(path)
urllib.request.url2pathname
(path)
暂还未研究透
1.5 urllib.request.getproxies
()
这个helper函数返回一个日程表dictionary 去代理服务器的URL映射。扫描指定的环境变量 _proxy大小写不敏感的方法,对所有的操作系统,当它不能找到它,从Mac OS X的Mac OSX系统配置和Windows系统注册表中寻找代理信息。如果两个大写和小写环境变量存在(或不一样),小写优先。
请注意,如果环境变量 REQUEST_METHOD已被设置,这通常表明你在CGI脚本运行环境,此时环境变量 HTTP_PROXY(大写 _PROXY)将被忽略。这是因为该变量可以被客户端使用注射“代理:”HTTP头。如果你需要使用一个HTTP代理在CGI环境中,要么使用 ProxyHandler明确,或者确保变量名小写(或至少是 _proxy后缀)。
1.6 urllib.request.OpenerDirector
OpenerDirector类打开url并通过 BaseHandler连接在一起。它管理处理程序的连接,和恢复错误。
1.7 urllib.request.BaseHandler
这是对于所有已注册的处理程序的基类
1.8 urllib.request.HTTPRedirectHandler
一个类来处理重定向
1.9 urllib.request.HTTPCookieProcessor(cookiejar=None)
一个类来处理HTTP cookie。
1.10 urllib.request.HTTPPasswordMgr
保持一个数据库 (realm, uri) -> (user, password)映射。
1.11 urllib.request.HTTPPasswordMgrWithDefaultRealm
保持一个数据库 (realm, uri) -> (user, password)映射。一个领域 None被认为是一个全方位领域,如果没有其他搜索领域
1.12 urllib.request.HTTPPasswordMgrWithPriorAuth
一个变体 HTTPPasswordMgrWithDefaultRealm还有一个数据库 uri -> is_authenticated的映射。可以使用BasicAuth处理程序来确定当发送身份验证凭证立即而不是等待 401响应。
1.13 urllib.request.AbstractBasicAuthHandler(password_mgr=None)
这是mixin类,帮助与HTTP身份验证,远程主机和代理。果有password_mgr,应该是兼容 HTTPPasswordMgr的。请参阅部分 HTTPPasswordMgr对象必须支持的接口信息。如果passwd_mgr还提供了 is_authenticated和 update_authenticated方法(见 HTTPPasswordMgrWithPriorAuth对象),然后处理程序将使用 is_authenticated结果对于一个给定的URI来决定是否发送请求的身份验证凭证。如果 is_authenticated返回 TrueURI,凭证发送。如果 is_authenticated是 False凭证不发送,然后如果 401收到响应请求发送身份验证凭证。如果身份验证成功, update_authenticated被称为设置 is_authenticated TrueURI,这样后续请求的URI或任何super-URIs将自动包括身份验证凭证。
在新的3.5版本:添加 is_authenticated支持。
1.14 urllib.request.HTTPBasicAuthHandler(password_mgr=None)
与远程主机处理身份验证。如果有password_mgr,应该是兼容HTTPPasswordMgr的。请参阅部分 HTTPPasswordMgr对象必须支持的接口信息。HTTPBasicAuthHandler将提高 ValueError当面对一个错误的身份验证方案。
1.15 urllib.request.ProxyBasicAuthHandler(password_mgr=None)
处理与代理身份的验证。如果有password_mgr,应该是兼容 HTTPPasswordMgr的。请参阅部分 HTTPPasswordMgr对象必须支持的接口信息。
1.16 urllib.request.AbstractDigestAuthHandler(password_mgr=None)
这是mixin类,帮助与HTTP身份验证,远程主机和代理。password_mgr,如果有,应该是兼容的 HTTPPasswordMgr;请参阅部分 HTTPPasswordMgr对象必须支持的接口信息
1.17 urllib.request.HTTPDigestAuthHandler(password_mgr=None)
与远程主机处理身份验证。如果有password_mgr,应该是兼容 HTTPPasswordMgr的;请参阅部分 HTTPPasswordMgr对象必须支持的接口信息。摘要式身份验证处理程序和基本身份验证处理器都是补充说,摘要式身份验证总是尝试第一次。如果主机返回一个40 x再次回应,它发送到基本身份验证处理程序来处理。这个处理程序方法将提高 ValueError当面对除了消化或基本身份验证方案。
3.3版本的变化:提高 ValueError不支持的身份验证方案。
1.18 urllib.request.ProxyDigestAuthHandler(password_mgr=None)
处理与代理身份验证。如果有password_mgr,应该是兼容 HTTPPasswordMgr的;请参阅部分 HTTPPasswordMgr对象必须支持的接口信息
1.19 urllib.request.HTTPHandler
一个类来处理HTTP url
1.20 urllib.request.HTTPSHandler(debuglevel=0, context=None, check_hostname=None)
一个类来处理开放的HTTPS url。在context 文和check_hostname有相同的意义 http.client.HTTPSConnection.
3.2版本的变化:context and check_hostname被补充。
1.21 urllib.request.FileHandler
打开本地文件
1.22 urllib.request.DataHandler
开放数据的url
1.23 urllib.request.FTPHandler
开放的FTP url
1.24 urllib.request.CacheFTPHandler
打开FTP url,保持打开的FTP连接缓存来减少延迟
1.25 urllib.request.UnknownHandler
全方位类处理未知的url。
1.26 urllib.request.HTTPErrorProcessor
HTTP错误响应过程。