python中,有三个库可以解析html文本,HTMLParser,sgmllib,htmllib。他们的实现方法不通,但功能差不多。这三个库中 提供解析html的类都是基类,本身并不做具体的工作。他们在发现的元件后(如标签、注释、声名等),会调用相应的函数,这些函数必须重载,因为基类中不 作处理。

比如:

"""<html><head><title>Advice</title></head><body>
<p>The <a href="http://ietf.org">IETF admonishes:
<i>Be strict in what you <b>send</b>.</i></a></p>
<form>
<input type=submit >  <input type=text name=start size=4></form>
</body></html>
"""

如果对这个数据做处理,当检测到<html>标签时,对于HTMLParser,会调用handle_starttag函数。

下面具体介绍下几个库

1、HTMLParser

  1. #------------------ HTMLParser_stack.py ------------------#
  2. #-- coding: GBK --
  3. import HTMLParser,sys,os,string
  4. html = """<html><head><title>Advice</title></head><body>
  5. <p>The <a href="http://ietf.org" mce_href="http://ietf.org">IETF admonishes:
  6. <i>Be strict in what you <b>send</b>.</i></a></p>
  7. <form>
  8. <input type=submit >  <input type=text name=start size=4></form>
  9. </body></html>
  10. """
  11. tagstack = []
  12. class ShowStructure(HTMLParser.HTMLParser):
  13. def handle_starttag(self, tag, attrs): tagstack.append(tag)
  14. def handle_endtag(self, tag): tagstack.pop()
  15. def handle_data(self, data):
  16. if data.strip():
  17. for tag in tagstack: sys.stdout.write('/'+tag)
  18. sys.stdout.write(' >> %s/n' % data[:40].strip())
  19. ShowStructure().feed(html)

此函数的输出:

/html/body/p >> The
/html/body/p/a >> IETF admonishes:
/html/body/p/a/i >> Be strict in what you
/html/body/p/a/i/b >> send
/html/body/p/a/i >> .

对于一些网页,可能并没有严格的开始结束标签对,这时,我们可以去忽略一些标签。可以自己写个堆栈来处理这些标签。

  1. #*--------------- TagStack class example -----------------#
  2. class TagStack:
  3. def __init__(self, lst=[]): self.lst = lst
  4. def __getitem__(self, pos): return self.lst[pos]
  5. def append(self, tag):
  6. # Remove every paragraph-level tag if this is one
  7. if tag.lower() in ('p','blockquote'):
  8. self.lst = [t for t in self.lst
  9. if t not in ('p','blockquote')]
  10. self.lst.append(tag)
  11. def pop(self, tag):
  12. # "Pop" by tag from nearest pos, not only last item
  13. self.lst.reverse()
  14. try:
  15. pos = self.lst.index(tag)
  16. except ValueError:
  17. raise HTMLParser.HTMLParseError, "Tag not on stack"
  18. del self.lst[pos]
  19. self.lst.reverse()
  20. tagstack = TagStack()

HTMLParser有个bug,就是不能处理中文属性,比如说,如果网页里有这么一段:

<input type=submit value=跳转到>

那么解析到这一行时就会出错。

错误原因还是正则表达式惹的祸。
 
attrfind = re.compile(
    r'/s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(/s*=/s*'
    r'(/'[^/']*/'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$/(/)_#=~@]*))?') 
attrfind 没有匹配中文字符。

可以更改这个匹配已修正这个错误。sgmllib则不存在这种错误。

2、sgmllib

html格式为sgml格式的一个子集,所以sgml可以处理跟多的东西,下面通过一段代码来示例sgmllib的用法。

  1. #------------------ HTMLParser_stack.py ------------------#
  2. #-- coding: GBK --
  3. import sgmllib,sys,os,string
  4. html = """<lala><head><title>Advice</title></head><body>
  5. <p>The <a href="http://ietf.org" mce_href="http://ietf.org">IETF admonishes:
  6. <i>Be strict in what you <b>send</b>.</i></a></p>
  7. <form>
  8. <input type=submit name='我'> 我 <input type=text name=start size=4></form>
  9. </body></lala>
  10. """
  11. os.chdir('d://python')
  12. f=file('testboard.txt','r')
  13. contest=f.read()
  14. tagstack = []
  15. class ShowStructure(sgmllib.SGMLParser):
  16. def handle_starttag(self, tag, method,attrs): tagstack.append(tag)
  17. def handle_endtag(self, tag): tagstack.pop()
  18. def handle_data(self, data):
  19. if data.strip():
  20. for tag in tagstack: sys.stdout.write('/'+tag)
  21. sys.stdout.write(' >> %s/n' % data[:40].strip())
  22. def unknown_starttag(self,tag,attrs):
  23. print 'start tag:<'+tag+'>'
  24. def unknown_endtag(self,tag):
  25. print 'end tag:</'+tag+'>'
  26. def start_lala(self,attr):
  27. print 'lala tag found'
  28. ShowStructure().feed(html)

输出:

start tag:<head>
start tag:<title>
/lala >> Advice
end tag:</title>
end tag:</head>
start tag:<body>
start tag:<p>
/lala >> The
start tag:<a>
/lala >> IETF admonishes:
start tag:<i>
/lala >> Be strict in what you
start tag:<b>
/lala >> send
end tag:</b>
/lala >> .
end tag:</i>
end tag:</a>
end tag:</p>
start tag:<form>
start tag:<input>
/lala >> ϒ
start tag:<input>
end tag:</form>
end tag:</body>
end tag:</lala>

和HTMLParser一样,如果要用sgmllib解析html,则要继承sgmllib.SGMLParser类,此类里的函数都是空的,用户需要重载它。这个类提供的功能是在特定情况下调用相应的函数。

比如当发现<html>标签时,如果并没有定义 start_html(self,attr)函数,则会调用unknown_starttag函数,具体怎么处理则更具用户。

sgml的标签是可以自定义的,比如自己定义了一个start_lala函数,则就会处理<lala>标签。

有 个地方要说明下,如果定义了start_tagname函数,有定义了handle_starttag函数,则函数只会运行 handle_starttag函数,start_tagname为空函数都没有问题,如果没有定义handle_starttag函数,则遇 到<tagname>标签时,会运行start_tagname函数。如果没有定义tagname的start函数,则此标签为未知标签,调 用unknown_starttag函数

最新文章

  1. 【Python】range和xrange区别
  2. css -- 映像 ,分页(上一页下一页)
  3. linux 知识汇总
  4. javascript中字符串常用操作总结、JS字符串操作大全
  5. MySQL中REGEXP正则表达式使用大全
  6. 咦,为DJANGO的ORM的QUERYSET增加数据列的样码,很好用哟
  7. 洛谷1373 小a和uim之大逃离
  8. 经典递归算法研究:hanoi塔的理解与实现
  9. mysql出现Waiting for table metadata lock的原因及解决方案
  10. Python - 缩写(capwords) 和 创建转换表(maketrans) 详细说明
  11. xsrftoken--源码笔记
  12. animate()写无限循环
  13. ios证书生成
  14. Vue创建头部组件示例
  15. Android内核栈溢出与ROP(CVE-2013-2597)
  16. CSS——【元素内边距padding、元素外边距margin、元素边框border-width、元素大小width/height】与【元素显示大小】的关系
  17. jquery-easyui:如何设置组件属性
  18. Revit API封装一个通用函数“过名称找元素”
  19. UVA 10479 The Hendrie Sequence
  20. redux VS mobx (装饰器配合使用)

热门文章

  1. Mysql5.6.24 zip解压缩版配置及修改默认编码方法
  2. vs linq to db template
  3. Android JNI开发提高篇
  4. Linq to sql介绍及增、删、改、查
  5. 查询sql 语句的好坏
  6. UIWebvView 解决onClick 延迟相应问题
  7. linux命令行后台运行与调回
  8. Python学习之collections module-defaultdict()
  9. poj 1905 Expanding Rods 二分
  10. 无法更新 EntitySet“GuigeInfo”,因为它有一个 DefiningQuery,而 &lt;ModificationFunctionMapping&gt; 元素中没有支持当前操作的 &lt;InsertFunction&gt; 元素。