zoukankan      html  css  js  c++  java
  • 解析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的天下呢?)唉。。。。。。

  • 相关阅读:
    Putty远程登录VMware虚拟机Linux(Ubuntu12.04)
    boost库在工作(39)网络UDP异步服务端之九
    UVA 1401 Remember the Word
    Windbg调试命令详解(1)
    数学之路(3)-机器学习(3)-机器学习算法-余弦相似度(1)
    2012-2013年度总结
    重建二叉树---根据前序和中序遍历结果重建二叉树
    Windbg调试命令详解(2)
    时间操作(JavaScript版)—最简单比較两个时间格式数据的大小
    WO+开放平台:API调用开发手记(话费计费接口2.0)
  • 原文地址:https://www.cnblogs.com/sysu-blackbear/p/3639600.html
Copyright © 2011-2022 走看看