2020-12-3 21:18:35

HTMLParser

如果我们要编写一个搜索引擎,第一步是用爬虫把目标网站的页面抓下来,第二步就是解析该HTML页面,看看里面的内容到底是新闻、图片还是视频。

假设第一步已经完成了,第二步应该如何解析HTML呢?

HTML本质上是XML的子集,但是HTML的语法没有XML那么严格,所以不能用标准的DOM或SAX来解析HTML。

好在Python提供了HTMLParser来非常方便地解析HTML,只需简单几行代码:(伪代码)

from HTMLParser import HTMLParser
from htmlentitydefs import name2codepoint

class MyHTMLParser(HTMLParser):
    
    def handle_starttag(self, tag, attrs):
        print('<%s>' % tag)

    def handle_endtag(self, tag):
        print('</%s>' % tag)
        
    def handle_startendtag(self, tag, attrs):
        print('<%s/>' % tag)
        
    def handle_data(self, data):
        print('data')
    
    def handle_comment(self, data):
        print('<!-- -->')
        
    def handle_entityref(self, name):
        print('&%s;' % name)
        
    def handle_charref(self, name):
        print('&#%s;' % name)
        
parser = MyHTMLParser()
parser.feed('<html><head></head><body><p>Some <a href=\"#\">html</a> tutorial...<br>END</p></body></html>')

feed() 方法可以多次调用,也就是不一定一次把整个HTML字符串都塞进去,可以一部分一部分塞进去。

特殊字符有两种,一种是英文表示的 &nbsp; ,一种是数字表示的 &#1234; ,这两种字符都可以通过Parser解析出来。

找一个网页,例如https://www.python.org/events/python­events/,用浏览器查看源码并复制,然后尝试解析一下HTML,
输出Python官网发布的会议时间、名称和地点。
# _*_ coding: gbk _*_
from HTMLParser import HTMLParser
from htmlentitydefs import name2codepoint
import os,string,urllib2

import ssl

# '''
# HTMLParser的成员函数: 
#  
#     handle_startendtag  处理开始标签和结束标签 
#     handle_starttag     处理开始标签,比如<xx> 
#     handle_endtag       处理结束标签,比如</xx> 
#     handle_charref      处理特殊字符串,就是以&#开头的,一般是内码表示的字符 
#     handle_entityref    处理一些特殊字符,以&开头的,比如   
#     handle_data         处理数据,就是<xx>data</xx>中间的那些数据 
#     handle_comment      处理注释 
#     handle_decl         处理<!开头的,比如<!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN” 
#     handle_pi           处理形如<?instruction>的东西 
#  
# '''
class MyHTMLParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.flag=None

    def handle_starttag(self, tag, attrs):
        if tag == 'h3' and attrs.__contains__(('class', 'event-title')):
            print '\n\n会议主题:',
            self.flag=True    #在需要打印的块中设置标识
        elif tag == 'time':
            print '\n会议时间:',
            self.flag=True
        elif tag == 'span' and attrs.__contains__(('class', 'event-location')):
            print '\n会议地址:',
            self.flag=True

    def handle_endtag(self, tag):
        if tag in('h3','time','span'):
            self.flag=None
            #print('</%s>' % tag)

    def handle_startendtag(self, tag, attrs):
        #print('<%s/>' % tag)
        pass

    def handle_data(self, data):
        if self.flag:    #判断是需要的值才打印
            print('%s' % data),    #末尾加逗号打印不换行

    def handle_comment(self, data):
        #print('<!-- -->')
        pass

    def handle_entityref(self, name):
        if name == 'ndash':
            print '至',
        else:
            pass

    def handle_charref(self, name):
        #print('&#%s;' % name)
        pass

        
#f=open('python.html','r++')
#data=f.read()
#f.close()
ssl._create_default_https_context = ssl._create_unverified_context
pyhtml=urllib2.urlopen('https://www.python.org/events/python-events/').read()
parser = MyHTMLParser()
parser.feed(pyhtml)
C:\Users\Administrator\Desktop>python html_parser.py


会议主题: PyDay Chile 2020
会议时间: 05 Dec.  2020
会议地址: Online (Chile)

会议主题: Pyjamas Conf 2020
会议时间: 05 Dec.  至  06 Dec.   2020
会议地址: Online

会议主题: PyCode Conference 2020
会议时间: 11 Dec.  至  12 Dec.   2020
会议地址: Online

会议主题: PyCon Tanzania 2020
会议时间: 14 Dec.  至  15 Dec.   2020
会议地址: Dar es Salaam, Tanzania

会议主题: BelPy 2021
会议时间: 30 Jan.  至  31 Jan.   2021
会议地址: Online

会议主题: PyCascades 2021
会议时间: 19 Feb.  至  21 Feb.   2021
会议地址: Portland, OR, USA

会议主题: enterPy (cancelled)
会议时间: 23 Nov.  至  24 Nov.   2020
会议地址: Heidelberg, Germany

会议主题: Online Python Web Global Summit 20
会议时间: 19 Nov.  2020
会议地址: Online

C:\Users\Administrator\Desktop>

作者 wanglei

发表评论