解析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的天下呢?)唉。。。。。。

posted @ 2014-04-02 01:37  中大黑熊  阅读(11135)  评论(2编辑  收藏  举报