在python中能够进行html和xhtml的库有很多,如HTMLParser、sgmllib、htmllib、BeautifulSoup、mxTidy、uTidylib等,这里介绍一下HTMLParser、BeautifulSoup等模块。

一、利用HTMLParser进行网页解析

具体HTMLParser官方文档可参考http://docs.python.org/library/htmlparser.html#HTMLParser.HTMLParser

1、从一个简单的解析例子开始

例1:
test1.html文件内容如下:

 XHTML 与 HTML 4.01 标准没有太多的不同 i love you 

下面是能够列出title和body的程序示例:

##@小五义:http://www.cnblogs.com/xiaowuyi ##HTMLParser示例 import HTMLParser class TitleParser(HTMLParser.HTMLParser):     def__init__(self):         self.taglevels=[]         self.handledtags=['title','body'] #提出标签         self.processing=None         HTMLParser.HTMLParser.__init__(self)     def handle_starttag(self,tag,attrs):         if tag in self.handledtags:             self.data=''             self.processing=tag     def handle_data(self,data):         if self.processing:             self.data +=data     def handle_endtag(self,tag):         if tag==self.processing:             print str(tag)+':'+str(tp.gettitle())             self.processing=None     def gettitle(self):         return self.data fd=open('test1.html') tp=TitleParser() tp.feed(fd.read())

运行结果如下:

title: XHTML 与 HTML 4.01 标准没有太多的不同
body:
i love you
程序定义了一个TitleParser类,它是HTMLParser类的子孙。HTMLParser的feed方法将接收数据,并通过定义的HTMLParser对象对数据进行相应的解析。其中handle_starttag、handle_endtag判断起始和终止tag,handle_data检查是否取得数据,如果self.processing不为None,那么就取得数据。

2、解决html实体问题

(HTML 中有用的字符实体)
(1)实体名称
当与到HTML中的实体问题时,上面的例子就无法实现,如这里将test1.html的代码改为:
例2:

 XHTML 与" HTML 4.01 "标准没有太多的不同 i love you×

利用上面的例子进行分析,其结果是:

title: XHTML 与 HTML 4.01 标准没有太多的不同
body:
i love you
实体完全消失了。这是因为当出现实体的时候,HTMLParser调用了handle_entityref()方法,因为代码中没有定义这个方法,所以就什么都没有做。经过修改后,如下:

##@小五义:http://www.cnblogs.com/xiaowuyi ##HTMLParser示例:解决实体问题 from htmlentitydefs import entitydefs import HTMLParser class TitleParser(HTMLParser.HTMLParser):     def__init__(self):         self.taglevels=[]         self.handledtags=['title','body']         self.processing=None         HTMLParser.HTMLParser.__init__(self)     def handle_starttag(self,tag,attrs):         if tag in self.handledtags:             self.data=''             self.processing=tag     def handle_data(self,data):         if self.processing:             self.data +=data     def handle_endtag(self,tag):         if tag==self.processing:             print str(tag)+':'+str(tp.gettitle())             self.processing=None     def handle_entityref(self,name):         if entitydefs.has_key(name):             self.handle_data(entitydefs[name])         else:             self.handle_data('&'+name+';')     def gettitle(self):         return self.data fd=open('test1.html') tp=TitleParser() tp.feed(fd.read())

运行结果为:

title: XHTML 与" HTML 4.01 "标准没有太多的不同
body:
i love you×
这里就把所有的实体显示出来了。

(2)实体编码

例3:

 XHTML 与" HTML 4.01 "标准没有太多的不同 i love÷ you×

如果利用例2的代码执行后结果为:

title: XHTML 与" HTML 4.01 "标准没有太多的不同
body:
i love you×
结果中÷ 对应的÷没有显示出来。
添加handle_charref()进行处理,具体代码如下:

##@小五义:http://www.cnblogs.com/xiaowuyi ##HTMLParser示例:解决实体问题 from htmlentitydefs import entitydefs import HTMLParser class TitleParser(HTMLParser.HTMLParser):     def__init__(self):         self.taglevels=[]         self.handledtags=['title','body']         self.processing=None         HTMLParser.HTMLParser.__init__(self)     def handle_starttag(self,tag,attrs):         if tag in self.handledtags:             self.data=''             self.processing=tag     def handle_data(self,data):         if self.processing:             self.data +=data     def handle_endtag(self,tag):         if tag==self.processing:             print str(tag)+':'+str(tp.gettitle())             self.processing=None     def handle_entityref(self,name):         if entitydefs.has_key(name):             self.handle_data(entitydefs[name])         else:             self.handle_data('&'+name+';')     def handle_charref(self,name):         try:             charnum=int(name)         except ValueError:             returnif charnum<1 or charnum>255:             return         self.handle_data(chr(charnum))     def gettitle(self):         return self.data fd=open('test1.html') tp=TitleParser() tp.feed(fd.read())

运行结果为:

title: XHTML 与" HTML 4.01 "标准没有太多的不同
body:
i love÷ you×

3、提取链接

例4:

 XHTML 与" HTML 4.01 "标准没有太多的不同i love÷ you×

这里在handle_starttag(self,tag,attrs)中,tag=a时,attrs记录了属性值,因此只需要将attrs中name=href的value提出即可。具体如下:

##@小五义:http://www.cnblogs.com/xiaowuyi ##HTMLParser示例:提取链接 # -*- coding: cp936 -*- from htmlentitydefs import entitydefs import HTMLParser class TitleParser(HTMLParser.HTMLParser):     def__init__(self):         self.taglevels=[]         self.handledtags=['title','body']         self.processing=None         HTMLParser.HTMLParser.__init__(self)            def handle_starttag(self,tag,attrs):         if tag in self.handledtags:             self.data=''             self.processing=tag         if tag =='a':             for name,value in attrs:                 if name=='href':                     print'连接地址:'+value     def handle_data(self,data):         if self.processing:             self.data +=data     def handle_endtag(self,tag):         if tag==self.processing:             print str(tag)+':'+str(tp.gettitle())             self.processing=None     def handle_entityref(self,name):         if entitydefs.has_key(name):             self.handle_data(entitydefs[name])         else:             self.handle_data('&'+name+';')     def handle_charref(self,name):         try:             charnum=int(name)         except ValueError:             returnif charnum<1 or charnum>255:             return         self.handle_data(chr(charnum))     def gettitle(self):         return self.data fd=open('test1.html') tp=TitleParser() tp.feed(fd.read())

运行结果为:

title: XHTML 与" HTML 4.01 "标准没有太多的不同
连接地址:
body:

i love÷ you×

4、提取图片

如果网页中有一个图片文件,将其提取出来,并存为一个单独的文件。
例5:

 XHTML 与" HTML 4.01 "标准没有太多的不同 i love÷ you×我想你

将baidu_sylogo1.gif存取出来,具体代码如下:

##@小五义:http://www.cnblogs.com/xiaowuyi ##HTMLParser示例:提取图片 # -*- coding: cp936 -*- from htmlentitydefs import entitydefs import HTMLParser,urllib def getp_w_picpath(addr):#提取图片并存在当前目录下     u = urllib.urlopen(addr)     data = u.read()     filename=addr.split('/')[-1]     f=open(filename,'wb')     f.write(data)     f.close()     print filename+'已经生成!'class TitleParser(HTMLParser.HTMLParser):     def__init__(self):         self.taglevels=[]         self.handledtags=['title','body']         self.processing=None         HTMLParser.HTMLParser.__init__(self)            def handle_starttag(self,tag,attrs):         if tag in self.handledtags:             self.data=''             self.processing=tag         if tag =='a':             for name,value in attrs:                 if name=='href':                     print'连接地址:'+value         if tag=='img':             for name,value in attrs:                 if name=='src':                     getp_w_picpath(value)     def handle_data(self,data):         if self.processing:             self.data +=data     def handle_endtag(self,tag):         if tag==self.processing:             print str(tag)+':'+str(tp.gettitle())             self.processing=None     def handle_entityref(self,name):         if entitydefs.has_key(name):             self.handle_data(entitydefs[name])         else:             self.handle_data('&'+name+';')     def handle_charref(self,name):         try:             charnum=int(name)         except ValueError:             returnif charnum<1 or charnum>255:             return         self.handle_data(chr(charnum))     def gettitle(self):         return self.data fd=open('test1.html') tp=TitleParser() tp.feed(fd.read())

运动结果为:

title: XHTML 与" HTML 4.01 "标准没有太多的不同
连接地址:
baidu_sylogo1.gif已经生成!
body:
i love÷ you×
?ò????

5、实际例子:

例6、获取人人网首页上的各各链接地址,代码如下:

##@小五义:http://www.cnblogs.com/xiaowuyi ##HTMLParser示例:获取人人网首页上的各各链接地址 #coding: utf-8 from htmlentitydefs import entitydefs import HTMLParser,urllib def getp_w_picpath(addr):     u = urllib.urlopen(addr)     data = u.read()     filename=addr.split('/')[-1]     f=open(filename,'wb')     f.write(data)     f.close()     print filename+'已经生成!'class TitleParser(HTMLParser.HTMLParser):     def__init__(self):         self.taglevels=[]         self.handledtags=['a']         self.processing=None         self.linkstring=''         self.linkaddr=''         HTMLParser.HTMLParser.__init__(self)            def handle_starttag(self,tag,attrs):         if tag in self.handledtags:             for name,value in attrs:                 if name=='href':                     self.linkaddr=value             self.processing=tag     def handle_data(self,data):         if self.processing:             self.linkstring +=data             #print data.decode('utf-8')+':'+self.linkaddr def handle_endtag(self,tag):         if tag==self.processing:             print self.linkstring.decode('utf-8')+':'+self.linkaddr             self.processing=None             self.linkstring=''def handle_entityref(self,name):         if entitydefs.has_key(name):             self.handle_data(entitydefs[name])         else:             self.handle_data('&'+name+';')     def handle_charref(self,name):         try:             charnum=int(name)         except ValueError:             returnif charnum<1 or charnum>255:             return         self.handle_data(chr(charnum))     def gettitle(self):         return self.linkaddr tp=TitleParser() tp.feed(urllib.urlopen('http://www.renren.com/').read())

运行结果:

分享:
应用程序:
公共主页:
人人生活:
人人小组:
同名同姓:
人人中学:
大学百科:
人人热点:
人人小站:
人人逛街:
人人校招:
:
注册:
登录:
帮助:
给我们提建议:
更多:#
:javascript:closeError();
打开邮箱查收确认信:#
重新输入:javascript:closeError();
:javascript:closeStop();
客服:
:javascript:closeLock();
立即解锁:
忘记密码?:
忘记密码?:
换一张:javascript:refreshCode_login();
MSN:#
360:
天翼:
为什么要填写我的生日?:#birthday
看不清换一张?:javascript:refreshCode();
想了解更多人人网功能?点击此处:javascript:;
:javascript:;
:javascript:;
立刻注册:
关于:
开放平台:
人人游戏:
公共主页:
手机人人:
团购:
皆喜网:
营销服务:
招聘:
客服帮助:
隐私:
京ICP证090254号:
互联网药品信息服务资格证:

二、利用BeautifulSoup进行网页解析

1、BeautifulSoup下载和安装
下载地址:
中文文档地址:
安装方法:将下载的文件解压缩后,文件夹下有个setup.py文件,然后在cmd下,运行python setup.py install进行安装,注意setup.py的路径问题。安装成功后,在python中就可以直接import BeautifulSoup了。
2、从一个简单的解析例子开始
例7:

 XHTML 与" HTML 4.01 "标准没有太多的不同 i love÷ you×我想你

获取title的代码:

##@小五义:http://www.cnblogs.com/xiaowuyi ##BeautifulSoup示例:title #coding: utf8 import BeautifulSoup a=open('test1.html','r') htmlline=a.read() soup=BeautifulSoup.BeautifulSoup(htmlline.decode('gb2312')) #print soup.prettify()#规范化html文件 titleTag=soup.html.head.title print titleTag.string

运行结果:

XHTML 与&quot; HTML 4.01 &quot;标准没有太多的不同
从代码和结果来看,应注意两点:
第一,在BeautifulSoup.BeautifulSoup(htmlline.decode('gb2312'))初始化过程中,应注意字符编码格式,从网上搜索了一下,开始用utf-8的编码显示不正常,换为gb2312后显示正常。其实可以用soup.originalEncoding方法来查看原文件的编码格式。
第二,结果中未对字符实体进行处理,在BeautifulSoup中文文档中,有专门对实体转换的解释,这里将上面的代码改为以下代码后,结果将正常显示:

##@小五义:http://www.cnblogs.com/xiaowuyi ##BeautifulSoup示例:title #coding: utf8 import BeautifulSoup a=open('test1.html','r') htmlline=a.read() soup=BeautifulSoup.BeautifulStoneSoup(htmlline.decode('gb2312'),convertEntities=BeautifulSoup.BeautifulStoneSoup.ALL_ENTITIES) #print soup.prettify()#规范化html文件 titleTag=soup.html.head.title print titleTag.string

这里convertEntities=BeautifulSoup.BeautifulStoneSoup.ALL_ENTITIES中的ALL_ENTITIES定义了XML和HTML两者的实体代码。当然,也可以直接用XML_ENTITIES或者HTML_ENTITIES。运行结果如下:

XHTML 与" HTML 4.01 "标准没有太多的不同
3、提取链接
还有用上面的例子,这里代码变为:

##@小五义:http://www.cnblogs.com/xiaowuyi ##BeautifulSoup示例:提取链接 #coding: utf8 import BeautifulSoup a=open('test1.html','r') htmlline=a.read() a.close() soup=BeautifulSoup.BeautifulStoneSoup(htmlline.decode('gb2312'),convertEntities=BeautifulSoup.BeautifulStoneSoup.ALL_ENTITIES) name=soup.find('a').string links=soup.find('a')['href'] print name+':'+links

运行结果为:

我想你:
4、提取图片
依然是用上面的例子,把baidu图片提取出来。
代码为:

##@小五义:http://www.cnblogs.com/xiaowuyi#coding: utf8 import BeautifulSoup,urllib def getp_w_picpath(addr):#提取图片并存在当前目录下     u = urllib.urlopen(addr)     data = u.read()     filename=addr.split('/')[-1]     f=open(filename,'wb')     f.write(data)     f.close()     print filename+' finished!' a=open('test1.html','r') htmlline=a.read() soup=BeautifulSoup.BeautifulStoneSoup(htmlline.decode('gb2312'),convertEntities=BeautifulSoup.BeautifulStoneSoup.ALL_ENTITIES) links=soup.find('img')['src'] getp_w_picpath(links)

提取链接和提取图片两部分主要都是用了find方法,具体方法为:

find(name, attrs, recursive, text, **kwargs)
findAll是列出全部符合条件的,find只列出第一条。这里注意的是findAll返回的是个list。
5、实际例子:
例8、获取人人网首页上的各各链接地址,代码如下:

##@小五义:http://www.cnblogs.com/xiaowuyi ##BeautifulSoup示例:获取人人网首页上的各各链接地址 #coding: utf8 import BeautifulSoup,urllib linkname='' htmlline=urllib.urlopen('http://www.renren.com/').read() soup=BeautifulSoup.BeautifulStoneSoup(htmlline.decode('utf-8')) links=soup.findAll('a') for i in links:     ##判断tag是a的里面,href是否存在。 if'href'in str(i):         linkname=i.string         linkaddr=i['href']         if'NoneType'in str(type(linkname)):#当i无内容是linkname为Nonetype类型。 print linkaddr         else:             print linkname+':'+linkaddr