HTML使用同一资源定位符(Universal Resource Locator:URL)来定位Internet上的HTML文档信息。URL语法定义如下:
protocol://auth/path?query
常用协议有:http、https、ftp、mailto、file、telnet
一种包含授权的URL详细语法如下:
protocol://username@passwd:netloc:port/path/filename?param = value#tag
具体示例:
http://www.w3.org/2015/10/Process-20150914/activities.html
ftp://ftp.test.com/pub/index.txt
../images/logo.jpg
first.html
python中的urllib.urlparse用于对url进行解析。主要方法有urlparse、urljoin、urlsplit、urlunsplit等。
urlparse将URL分为六元组:
scheme://netloc/path;parameters?query#fragment
注意这里并没有将服务器地址和端口地址进行区分。
在解析URL的时候所有的%
转移符都不会被处理。另外除了第一个起始斜线外,分隔符都会被去掉。
urlparse有两个可选参数:
- default_scheme:为不包含协议的url指定协议
- allow_fragments:指示是否可以对地址进行分片。默认为True
from urllib.parse import *
webURL = "http://alice:[email protected]:80/%7Ealice/python.cgi\
?query = text#sample"
r = urlparse(webURL)
print(r)
# 第一个参数是绝对地址,第二个是相对地址
join1 = urljoin("http://www.zeroc.com", "ice.html")
print(join1)
# 都含有绝对地址,有限采用相对地址中的协议
join2 = urljoin("http://www.python.org", "ftp:www.python.org/fag")
print(join2)
# 当相对url中不含协议时,会将所有字符当做一个路径信息
join3 = urljoin("http://www.python.org", "www.python.org/faq")
print(join3)
# 优先使用相对url地址的服务器地址和路径
join4 = urljoin("http://www.python.org", "http://www.python.com/fag")
print(join4)
有效的格式化,特殊字符得到转换:
r = urlunsplit(urlsplit("http://www.python.org/faq?"))
URL中使用的是ASCII字符集,当使用不在字符集中的字符时,就需要进行编码。即使是ASCII字符集中的字符,有些也不能直接使用,常见的情况是不能在URL中使用空格字符。有些字符被称为保留字符,不能在URL中出现,例如斜线/
等。ASCII字符集中的编码规则是:在百分号后面加上两个十六进制数字,与其在ASCII字符表中的数值对应。
大部分的标点符号都需要编码,特别是那些保留字符。一般的,对于不在ASCII字符集中的字符,如果不知道是否应该编码,那么最好进行编码。注意当字符有特殊含义的时候不应进行编码
urllib中的编码解码方法如下:
quote
对URL进行编码quote_plus
同quote编码,进一步将空格变为+
符号unquote
解码unquote_plus
解码,将+
变为空格from urllib.parse import quote
r = quote("URL编码")
unquote(r)
urlencode用于将查询参数加工成url所需的格式
urlencode([("keyword1", "value1"), ("keyword2", "value2"), ("keyword3", "keyword3")]) #列表中的元素是有序的
urlencode({"key1":"val1", "key2":"val2", "key3":"val3"}) #集合中的元素是无序的
urlencode还有一个可选的参数,用于对查询参数中的数据进行控制。默认为False,即当查询参数的value为列表的时候,将其整个用quote_plus进行编码,并作为查询的参数。当其为True时,不会编码。
urlencode([("keyword", ("val1", "val2", "val3"))])
urlencode([("keyword", ("val1", "val2", "val3"))], True)
urlopen:
可以读取URL资源,并不能对数据进行seek操作。返回值中有一个可以读的handler,从而可以实现对数据的读取。
from urllib.request import *
fp = urlopen("http://www.python.org")
print(fp.read())
op = open("python.html", "wb") # 从网络获取的数据最好使用二进制方式
n = 0
while True:
s = fp.read(1024)
if not s: # 遇到 EOF 时跳出循环
break
op.write(s)
n = n + len(s)
fp.close()
op.close()
print("retrieved", n, " bytes from", fp.url)
使用代理:
proxies = {"http":"http://www.proxy.com:2137"}
urlopen(url, proxies = proxies)
urlretrieve:
直接存储到本地文件。
关于参数 reporthook,用于报告下载进度的一个函数,有三个参数,分别为已获取的文件块的个数、文件块的大小、文件的大小。当文件大小为 -1 时,表明无法获得整个文件的大小,特别是对于ftp流数据而言。
from urllib.request import *
def download(url, filename = ""):
def reporthook(block_count, block_size, file_size):
if file_size == -1:
print("Cann't determine the file size, now retrieved",
block_count * block_size)
else:
percentage = int((block_count * block_size * 100.0) / file_size)
if percentage > 100:
print(" 100% ")
else:
print(" % d% % " % (percentage))
filehandler, m = urlretrieve(url, filename, reporthook = reporthook)
print("Done!")
return filehandler
download("http://www.python.org", "D:/index.html")
urllib中还有URLopener及其继承类FancyURLopener,它们也可以完成URL资源的读取。实际上urlopen方法就是FacyURLopener的一个实例,并通过调用其实例的open方法来实现的。一般来说,使用FancyURLopener就够了,URLopener类主要针对除http、ftp、file以外的协议。
访问需要简单认证的URL资源
FancyURLopener类中有prompt_user_passwd方法来处理用户名和密码,当访问的资源需要使用简单认证进行访问的情况下,将会调用此方法得到用户名和密码。默认情况下会从控制台读取用户名和密码。我们需要对这个函数进行重载,直接在代码中调用我们事先设定的参数即可。
from urllib.request import *
class myURLopener(FancyURLopener):
def setAuth(self, user, passwd):
self.user = user
self.passwd = passwd
def prompt_user_passwd(self, host, realm):
return self.user, self.passwd
myurlopener = myURLopener()
myurlopener.setAuth(" user", " passwd")
op = myurlopener.open(" http://www.secret.com")
构造文件头元信息
有效避开某些URL资源对于访问的限制
from urllib.request import *
opener = FancyURLopener()
opener.addheader("User-Agent", "Mozilla/4.0 (compatible;MSIE 6.0; \
windows NT 5.1)")
opener.addheader("Accept", "text/html")
opener.addheader("Connection", "close")
opener.open("http://www.baidu.com")
访问出错的处理方法
HTTP状态码:
301
数据已被删除302
资源临时重定向303
建议访问其他URL307
资源临时性删除 401
错误的请求404
访问资源不存在默认情况下对303错误的处理方法:
def http_error_302(self, url, fp, errcode, errmsg, headers, data = None):
delf.tries += 1
if self.maxtries and self.tries >= self.maxtries:
if hasattr(self, "http_error_500"):
meth = self.http_error_500
else:
meth = self.http_error_default
self.tries = 0
return meth(url, fp, 500, "Internal Server Error: Redirect Recursion",
headers)
result = self.redirect_internal(url, fp, errcode, errmsg, headers, data)
self.tries = 0
return result
自定义处理方法:
from urllib.request import *
class myURLopener(FancyURLopener):
def setAuth(self, user, passwd):
self.user = user
self.passwd = passwd
def prompt_user_passwd(self, host, realm):
return self.user, self.passwd
def http_error_302(self, url, fp, errcode, errmsg, headers, data = None):
if "location" in headers:
newurl = headers["location"]
elif "uri" in headers:
newurl = headers["uri"]
else:
return
print(url, "==>", newurl)
return FancyURLopener.http_error_302(self, url, fp, errcode, errmsg,
headers, data)
myurlopener = myURLopener()
myurlopener.setAuth(" user", " passwd")
op = myurlopener.open(" http://www.secret.com")
The httplib module has been renamed to http.client in Python 3.
httplib实现了HTTP和HTTPS协议的客户端部分,一般情况下这个模块并不直接使用,而是作为urllib的基础模块。但实际上,此模块还是比较适用于在访问HTTP资源的时候使用,包括GE和POST方法等等。
获取到资源之后,结下来便是对HTML文档进行处理了。Python提供了HTMLParser模块来解析HTML文档。另外,由于HTML是属于SGML家族的一员,所以亦可以使用sgmllib模块来处理HTML文档。htmpllib是建立在sgmllib模块上的HTTP文档高级处理模块,可以对HTML进行更细的处理。
HTMLParser小巧、快速、使用简便,利用它可以分析HTML文档中的标签和数据等。HTMLParser采用了一种事件驱动的方式,是的模块在找到了一个特定的对象的时候,可以调用用户定义的函数来进行处理。
处理函数都是以handle_开头的,是HTMLParser的成员函数。具体使用使,先继承HTMLParser类,然后重载这些函数即可。
HTMLParser中的handle_函数如下:
handle_startendtag
处理开始标签和结束标签,比如handle_starttag
处理开始标签,比如handle_endtag
处理结束标签,比如handle_charref
处理特殊字符串,就是以开头的,一般是内码表示的字符handle_entityref
处理一些特殊字符,以&开头的,比如 handle_data
处理数据,就是data中间的那些数据handle_comment
处理注释handle_decl
处理Deprecated since version 2.6: The sgmllib module has been removed in Python 3.
Deprecated since version 2.6: The htmllib module has been removed in Python 3.