解析html与xhtml的神器——HTMLParser与SGMLParser

        有时候你要把抓回来的数据进行提取,过大篇幅的html标签,你若使用正则表达式进行匹配的话,显然是低效的,这时使用python的HTMLParser模块会显得非常方便。据说还有个比较好用的解析器叫:Beautiful Soup,这个以后有机会再说吧,现在本渣连实习都找不到,再搞这个东西估计没法生活了。。。。。。

事先说明:我们要解析的html和xhtml的语法是规范的那一种,如果遇到不规范的就gg了,得自己手写正则提取。还有,对于那些转义字符没转义就先不考虑了。。。。。。。

关于HTMLParser与SGMLParser:

网上看很多大牛说HTMLParser对中文字符的提取很不好,推荐使用SGMLParser,但是python的官方文档的Demo是用HTMLParser写的。那就学HTMLParser,反正据说两者是继承关系。

先上文档的Demo:

 1 #!/usr/bin/env python

 2 #-*-coding:utf-8-*-

 3 

 4 from HTMLParser import HTMLParser

 5 from htmlentitydefs import name2codepoint

 6 

 7 class MyHTMLParser(HTMLParser):

 8     #检索开头标签

 9     def handle_starttag(self,tag,attrs):

10         print "Start tag:",tag

11         #匹配里面的项

12         for attr in attrs:

13             print "    attr:",attr

14     #匹配结束标签

15     def handle_endtag(self,tag):

16         print "End tag  :",tag

17     #处理数据

18     def handle_data(self,data):

19         print "Data     :",data

20     #检索注释内容

21     def handle_comment(self,data):

22         print "Comment  :",data

23     #处理转义字符

24     def handle_entityref(self,name):

25         c = unichr(name2codepoint[name])

26         print "Named ent:",c

27     #处理转义的数字字符(ACSII)

28     def handle_charref(self,name):

29         if name.startswith('x'):

30             c = unichr(int(name[1:],16))    #十六进制

31         else:

32             c = unichr(int(name))

33         print "Num ent  :",c

34     #匹配HTML头

35     def handle_decl(self,data):

36         print "Decl     :",data

37 

38 parser = MyHTMLParser()

39 

40 parser.feed('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML4.01//EN"''"http://www.w3.org/TR/html4/strict.dtd">')

41 #Decl     : DOCTYPE HTML PUBLIC "-//W3C//DTD HTML4.01//EN""http://www.w3.org/TR/html4/strict.dtd"

42 

43 parser.feed('<img src="python-logo.png" alt="The Python logo">')

44 #Start tag: img

45 #    attr: ('src', 'python-logo.png')

46 #    attr: ('alt', 'The Python logo')

47 

48 parser.feed('<style type="text/css">#python { color: green }</style>')

49 #Start tag: style

50 #    attr: ('type', 'text/css')

51 #Data     : #python { color: green }

52 #End tag  : style

53 

54 parser.feed('<script type="text/javascript"> alert("<strong>hello!</strong>");</script>')

55 #Start tag: script

56 #    attr: ('type', 'text/javascript')

57 #Data     :  alert("<strong>hello!</strong>");

58 #End tag  : script

59 

60 parser.feed('<!-- a comment --><!--[if IE 9]>IE-specific content<![endif]-->')

61 #Comment  :  a comment 

62 #Comment  : [if IE 9]>IE-specific content<![endif]

63 

64 parser.feed('&gt;&#62;&#x3E;')

65 #Named ent: >

66 #Num ent  : >

67 #Num ent  : >

68 

69 parser.feed('<p><a class=link href=#main>tag soup</p ></a>')

70 #Start tag: p

71 #Start tag: a

72 #    attr: ('class', 'link')

73 #    attr: ('href', '#main')

74 #Data     : tag soup

75 #End tag  : p

76 #End tag  : a

 

一般来说要提取HTML文件中的信息只有3个主要的用途:

  • 提取标题和段落;
  • 提取img的图片,另存为文件;
  • 提取href中的链接

 

1.提取标题和段落:

 1 #!/usr/bin/env python

 2 #-*-coding:utf-8-*-

 3 

 4 from htmlentitydefs import entitydefs

 5 from HTMLParser import HTMLParser

 6 

 7 class TitleParser(HTMLParser):

 8     

 9     def __init__(self):

10         #定义要搜寻的标签

11         self.handledtags = ['title','p']  #提出标签,理论上可以提取所有标签的内容

12         self.processing = None

13         HTMLParser.__init__(self)  #继承父类的构造函数

14 

15     def handle_starttag(self,tag,attrs):

16         #判断是否在要搜寻的标签内

17         if tag in self.handledtags:

18             self.data = ''

19             self.processing = tag

20 

21     def handle_data(self,data):

22         if self.processing:

23             self.data += data

24 

25     def handle_endtag(self,tag):

26         if tag == self.processing:

27             print str(tag)+' : '+str(self.data)

28             self.processing = None

29 

30     #下面两个函数都是对html实体做的转码,没有深究

31     def handle_entityref(self,name): 

32         if entitydefs.has_key(name): 

33             self.handle_data(entitydefs[name]) 

34         else: 

35             self.handle_data('&'+name+';') 

36             

37     def handle_charref(self,name): 

38         try: 

39             charnum=int(name) 

40         except ValueError: 

41             return 

42         if charnum<1 or charnum>255: 

43             return 

44         self.handle_data(chr(charnum)) 

45     

46 parser = TitleParser()

47 html1 = """

48 <html> 

49 <head> 

50 <title> XHTML 与 HTML 4.01 标准没有太多的不同</title> 

51 </head> 

52 <body> 

53 <p>i love you</p> 

54 </body> 

55 </html> 

56 """

57 

58 html2 = """

59 <html> 

60 <head> 

61 <title> XHTML 与&quot; HTML 4.01 &quot;标准没有太多的不同</title> 

62 </head> 

63 <body> 

64 <p>i love&#247; you&times;</p> 

65 </body> 

66 </html> 

67 """

68 parser.feed(html2)

 

2.提取img的图片,另存为文件

 1 #!/usr/bin/env python

 2 #-*-coding:utf-8-*-

 3 

 4 from htmlentitydefs import entitydefs

 5 from HTMLParser import HTMLParser

 6 import urllib

 7 import time

 8 

 9 class ImgParser(HTMLParser):

10     

11     num = 1

12 

13     def __init__(self):

14         #定义要搜寻的标签

15         self.processing = None

16         HTMLParser.__init__(self)  #继承父类的构造函数

17         self.addr=''

18     

19     def handle_starttag(self,tag,attrs):

20         #判断是否在要搜寻的标签内

21         if tag == 'img':

22             print 'pic'+str(self.num) + " : " + tag

23             self.num += 1

24             for key,value in attrs:

25                 if key == 'src':

26                     self.addr = value

27                     #在类的成员函数中,使用类中的另一个成员函数,前面必须要指定类名

28                     ImgParser.getImage(self)   #合法

29                     print key + " : " + value

30                 if key == 'alt':

31                     print key + " : " + value

32 

33     def getImage(self):

34         u = urllib.urlopen(self.addr)

35         data = u.read()

36         filename = self.addr.split('/')[-1]

37         timestr = time.strftime('%Y%m%d%S',time.localtime(time.time()))

38         f = open('/home/dzhwen/python文件/Homework/urllib/pic/'+timestr+filename,'wb')

39         f.write(data)

40         f.close()

41 

42 parser = ImgParser()

43 f = urllib.urlopen('http://www.sina.com.cn/')  #抓取新浪网上以img标签开头的图片

44 parser.feed(f.read())

 

3.提取href中的链接

 1 #!/usr/bin/env python

 2 #-*-coding:utf-8-*-

 3 

 4 from htmlentitydefs import entitydefs

 5 from HTMLParser import HTMLParser

 6 import urllib

 7 

 8 class LinkParser(HTMLParser):

 9     

10     def __init__(self):

11         #定义要搜寻的标签

12         self.handledtags = ['a']  #提出标签,理论上可以提取所有标签的内容

13         self.processing = None

14         self.linkstr = ''   #定义链接的标题

15         self.linkaddr = ''  #定义链接的地址

16         HTMLParser.__init__(self)  #继承父类的构造函数

17 

18     def handle_starttag(self,tag,attrs):

19         #判断是否在要搜寻的标签内

20         if tag in self.handledtags:

21             for name,value in attrs:

22                 if name == 'href':

23                     self.linkaddr = value

24             self.processing = tag

25             self.linkstr = ''

26 

27     def handle_data(self,data):

28         if self.processing:

29             self.linkstr += data

30 

31     def handle_endtag(self,tag):

32         if tag == self.processing:

33             print self.linkstr.decode('utf-8') + ' : ' + self.linkaddr.decode('utf-8')

34             self.processing = None

35 

36     #下面两个函数都是对html实体做的转码,没有深究

37     def handle_entityref(self,name): 

38         if entitydefs.has_key(name): 

39             self.handle_data(entitydefs[name]) 

40         else: 

41             self.handle_data('&'+name+';') 

42             

43     def handle_charref(self,name): 

44         try: 

45             charnum=int(name) 

46         except ValueError: 

47             return 

48         if charnum<1 or charnum>255: 

49             return 

50         self.handle_data(chr(charnum)) 

51     

52 parser = LinkParser()

53 f = urllib.urlopen('http://www.csdn.net/')   #解析csdn主页的链接

54 parser.feed(f.read())

 

不过很多网站的数据都用js来包装,这样就不能单纯用HTMLParser来解析了,需要用到别的工具,还是回去好好练级吧。。。。

搞到这里,基本的爬虫能掌握思路了,解析来就剩下Beautiful Soup ,Scrapy 和 异步编程还没学(用来进行大幅度的下载和抓取)。。。。。。迫于生活压力,估计没那么快更了,被迫进军java后台了(谁叫外面的世界都是java的天下呢?)唉。。。。。。

你可能感兴趣的:(HtmlParser)