您的位置:首页 > 编程语言 > Python开发

Python进阶 - HTML获取与解析

2015-09-28 20:00 603 查看

1 URL的处理

1.1 URL介绍

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


1.2 URL的解析

python中的urllib.urlparse用于对url进行解析。主要方法有urlparse、urljoin、urlsplit、urlunsplit等。

urlparse将URL分为六元组:

scheme://netloc/path;parameters?query#fragment


注意这里并没有将服务器地址和端口地址进行区分。

在解析URL的时候所有的
%
转移符都不会被处理。另外除了第一个起始斜线外,分隔符都会被去掉。

urlparse有两个可选参数:

- default_scheme:为不包含协议的url指定协议

- allow_fragments:指示是否可以对地址进行分片。默认为True

1.3 URL拼合

from urllib.parse import *

webURL = "http://alice:secret@www.hostname.com: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)


1.4 URL分解

有效的格式化,特殊字符得到转换:

r = urlunsplit(urlsplit("http://www.python.org/faq?"))


1.5 URL的编码与解码

URL中使用的是ASCII字符集,当使用不在字符集中的字符时,就需要进行编码。即使是ASCII字符集中的字符,有些也不能直接使用,常见的情况是不能在URL中使用空格字符。有些字符被称为保留字符,不能在URL中出现,例如斜线
/
等。ASCII字符集中的编码规则是:在百分号后面加上两个十六进制数字,与其在ASCII字符表中的数值对应。

大部分的标点符号都需要编码,特别是那些保留字符。一般的,对于不在ASCII字符集中的字符,如果不知道是否应该编码,那么最好进行编码。注意当字符有特殊含义的时候不应进行编码

urllib中的编码解码方法如下:

quote
对URL进行编码

quote_plus
同quote编码,进一步将空格变为
+
符号

unquote
解码

unquote_plus
解码,将
+
变为空格

1.6 中文的编码与解码

from urllib.parse import quote
r = quote("URL编码")
unquote(r)


1.7 参数的编码

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)


2 获取HTML资源

2.1 使用urlopen和urlretrieve获取HTTP资源

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")


2.2 自定义资源获取方式

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
建议访问其他URL

307
资源临时性删除

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")


2.3 使用httplib获取资源

The httplib module has been renamed to http.client in Python 3.

httplib实现了HTTP和HTTPS协议的客户端部分,一般情况下这个模块并不直接使用,而是作为urllib的基础模块。但实际上,此模块还是比较适用于在访问HTTP资源的时候使用,包括GE和POST方法等等。

3 HTML文档解析

获取到资源之后,结下来便是对HTML文档进行处理了。Python提供了HTMLParser模块来解析HTML文档。另外,由于HTML是属于SGML家族的一员,所以亦可以使用sgmllib模块来处理HTML文档。htmpllib是建立在sgmllib模块上的HTTP文档高级处理模块,可以对HTML进行更细的处理。

3.1 使用HTMLParser模块

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
处理

3.2 sgmllib的HTML文档处理

Deprecated since version 2.6: The sgmllib module has been removed in Python 3.

3.3 使用htmllib处理HTML文档

Deprecated since version 2.6: The htmllib module has been removed in Python 3.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: