Python宝典第19章:处理HTML与XML

Python中可以使用html模块处理HTML,获取网页中感兴趣的内容。html模块中的子模块html.parser提供了对HTML标记处理的方法。

使用html.parser模块处理HTML,首先应继承html.parser模块中的HTMLParser类,然后重载相关的处理方法。

  • feed:向HTMLParser传递数据
  • close:强制处理feed方法存在缓冲区的数据
  • reset:重新设置对象实例,进行新一轮的数据处理
  • getpos:获得当前处理的行号和偏移位置
在使用HTMLParser处理HTML过程中,遇到某些标记或数据就会调用相应方法,一般情况下,在脚本中需要重载这些方法。
  • handle_starttag:遇到起始标记
  • handle_startendtag
  • handle_endtag
  • handle_data
  • handle_comment
获取页面图片地址:
一般来说,网页中图片都是以<img>嵌入的。要获取页面图片地址,只要处理该标记即可。
下面脚本分别获得GIF和JPG的相对地址。
因为很多网站使用的HTML并不是标准的语法格式,HTMLParser处理时,并不能获得所有图片。关键是理解该函数,在自动碰到有些tag的时候,调用重载的函数。
<span style="font-size:14px;"><span style="font-size:14px;"># -*- coding:utf-8 -*-
# file: GetImage.py
#

import tkinter
import urllib.request
from html.parser import HTMLParser

class MyHTMLParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.gifs=[]
        self.jpgs=[]
    def handle_starttag(self, tags, attrs):
        if tags=='img':
            for attr in attrs:
                for t in attr:
                    if 'gif' in t:
                        self.gifs.append(t)
                    elif 'jpg' in t:
                        self.jpgs.append(t)
                    else:
                        pass
    def get_gifs(self):
        return self.gifs
    def get_jpgs(self):
        return self.jpgs

class Window:
    def __init__(self, root):
        self.root=root
        self.label=tkinter.Label(root, text="输入URL:")
        self.label.place(x=5, y=15)
        self.entryUrl=tkinter.Entry(root, width=30)
        self.entryUrl.place(x=65, y=15)
        self.get=tkinter.Button(root, text='获取图片',command=self.Get)
        self.get.place(x=280, y=15)
        self.edit=tkinter.Text(root, width=470, height=600)
        self.edit.place(y=50)
    def Get(self):
        url=self.entryUrl.get()
        page=urllib.request.urlopen(url)
        data=page.read()
        parser=MyHTMLParser()
        parser.feed(data.decode())
        self.edit.insert(tkinter.END, '====GIF====\n')
        gifs=parser.get_gifs()
        for gif in gifs:
            self.edit.insert(tkinter.END, gif+'\n')
        self.edit.insert(tkinter.END, '===========\n')
        self.edit.insert(tkinter.END, '====JPG====\n')
        jpgs=parser.get_jpgs()
        for jpg in jpgs:
            self.edit.insert(tkinter.END, jpg+'\n')
        self.edit.insert(tkinter.END, '===========\n')
        page.close()

root=tkinter.Tk()
window=Window(root)
root.minsize(600,480)
root.mainloop()
</span></span>

查看天气预报:

国家气象局提供的天气预报接口

接口地址:

实时天气

http://www.weather.com.cn/data/sk/101010100.html

http://www.weather.com.cn/data/cityinfo/101010100.html

六天的天气情况(含今天):这个接口已经废弃,网上查到说把data换成atad但仍然无效,可能又改了。。。所以下面的脚本只有实时天气和今天天气

http://m.weather.com.cn/data/101010100.html

<span style="font-size:14px;"><span style="font-size:14px;"># -*- coding:utf-8 -*-
# file: GetWeather.py
#

import tkinter
import urllib.request
import json

def getCityWeather_RealTime(cityID):
    url="http://www.weather.com.cn/data/sk/" + str(cityID) + ".html"
    try:
        stdout=urllib.request.urlopen(url)
        weatherInformation=stdout.read().decode('utf-8')
        jsonDatas=json.loads(weatherInformation)
        city=jsonDatas["weatherinfo"]["city"]
        temp=jsonDatas["weatherinfo"]["temp"]
        fx=jsonDatas["weatherinfo"]["WD"]
        fl=jsonDatas["weatherinfo"]["WS"]
        sd=jsonDatas["weatherinfo"]["SD"]
        tm=jsonDatas["weatherinfo"]["time"]
        content="#" + city + "# " + temp +"℃ " + fx + fl + "相对湿度 " +sd \
                 + " 发布时间 " + tm +"\n"
        twitter={'image': "", 'message':content}
    except (SyntaxError) as err:
        print("SyntaxError: "+err.args)
    except:
        print("OtherError: ")
    else:
        return twitter
    finally:
        None

def getCityWeather_AllDay(cityID):
    url="http://www.weather.com.cn/data/cityinfo/" + str(cityID) + ".html"
    try:
        stdout=urllib.request.urlopen(url)
        weatherInformation=stdout.read().decode('utf-8')
        jsonDatas=json.loads(weatherInformation)
        city=jsonDatas["weatherinfo"]["city"]
        temp1=jsonDatas["weatherinfo"]["temp1"]
        temp2=jsonDatas["weatherinfo"]["temp2"]
        weather=jsonDatas["weatherinfo"]["weather"]
        img1=jsonDatas["weatherinfo"]["img1"]
        img2=jsonDatas["weatherinfo"]["img2"]
        ptm=jsonDatas["weatherinfo"]["ptime"]
        content="#" + city + "# " + weather +" 最高气温" + temp1 + " 最低气温"\
                 +temp2 + " 发布时间 " + ptm +"\n\n"
        twitter={'image': "icon\d" + img1, 'message':content}
    except (SyntaxError) as err:
        print("SyntaxError: "+err.args)
    except:
        print("OtherError: ")
    else:
        return twitter
    finally:
        None

class Window:
    def __init__(self, root):
        self.citys=self.getCitys('city.txt')
        self.root=root
        self.label=tkinter.Label(root, text="输入城市:")
        self.label.place(x=5, y=15)
        self.entryCity=tkinter.Entry(root, width=30)
        self.entryCity.place(x=65, y=15)
        self.entryCity.insert(tkinter.END, '上海')
        self.get=tkinter.Button(root, text='获取天气',command=self.Get)
        self.get.place(x=230, y=15)
        self.edit=tkinter.Text(root, width=300, height=350)
        self.edit.place(y=50)
    def getCitys(self, file):     
        file=open(file,encoding='utf-8')
        #print(file.read())
        city={}
        for c in file.read().split('|'):
            cn,cc=c.split(',')
            city.update({cn:cc})
        #print(city)
        return city    
    def Get(self):
        city=self.entryCity.get()
        #print(city)
        #print(self.citys)
        for k in self.citys.keys():            
            if k.endswith(city):
                #print(city)
                #print(k)
                CityCode=self.citys[k]
                #print(CityCode)
                break
        title_small="【实时天气】\n"
        twitter=getCityWeather_RealTime(CityCode)
        self.edit.insert(tkinter.END, title_small+twitter['message']+'\n')
        title_small="【今日天气】\n"
        twitter=getCityWeather_AllDay(CityCode)
        self.edit.insert(tkinter.END, title_small+twitter['message']+'\n')
if __name__=='__main__':
    root=tkinter.Tk()
    window=Window(root)
    root.minsize(400,280)
    root.mainloop()
</span></span>

iter函数迭代器的介绍:http://luozhaoyu.iteye.com/blog/1513198
http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html


处理XML:
一般来说,XML文档包含以下几部分内容:
  • XML声明:version, encoding, standlone
  • 根元素
  • 元素和属性
  • 字符数据:处于元素标记间的数据
  • CDATA块
  • 注释
  • 处理指令
DTD,文档类型定义,用于描述XML文档包含的内容和XML文档的布局结构。使用DTD可以验证XML文档结构的正确性。

使用Python处理XML:
有Expat分析器的xml.parsers.expat模块,SAX分析器的xml.sax模块和使用DOM的xml.dom模块。
其中xml.parser.expat和xml.sax模块与html.parser模块中的HTMLParser类相似,都是基于事件对XML文档进行分析。

xml.parsers.expat:
  • ParserCreate
  • Parse    ParseFile
  • XmlDeclHandler
  • StartDoctypeDeclHandler    EndDoctypeDeclHandler
  • ...
xml.sax将分析器和处理器分离。
Python提供的xml.dom模块的DOM接口可以将xml文档转为树结构。Python提供了基本的minidom和复制的DOM分析系统pulldom模块。前者使用小文档,因为一次性读到内存;后者适用于较大XML文档,不会一次性读到内存。

简单的RSS阅读器:
http://legacy.python.org/channews.rdf
<span style="font-size:14px;"># -*- coding:utf-8 -*-
# file: GetRSS.py
#

import tkinter
import urllib.request
import xml.parsers.expat

class MyXML:
    def __init__(self,edit):
        self.parser=xml.parsers.expat.ParserCreate()
        self.parser.StartElementHandler=self.start
        self.parser.EndElementHandler=self.end
        self.parser.CharacterDataHandler=self.data
        self.title=False
        self.date=False
        self.edit=edit
    def start(self, name, attrs): #有问题
        if name=='title':
            self.title=True
        elif name=='pubDate':
            self.date=True
        else:
            pass
    def end(self, name):
        if name=='title':
            self.title=False
        elif name=='pubDate':
            self.date=False
        else:
            pass
    def data(self, data):
        if self.title:
            self.edit.insert(tkinter.END, '***************************\n')
            self.edit.insert(tkinter.END, 'Title: ')
            self.edit.insert(tkinter.END, data+'\n')
        elif self.date:
            self.edit.insert(tkinter.END, 'Date: ')
            self.edit.insert(tkinter.END, data+'\n')
        else:
            pass
    def feed(self, data):
        self.parser.Parse(data,0)#有问题

class Window:
    def __init__(self, root):
        self.root=root
        self.get=tkinter.Button(root, text="获取RSS", command=self.Get)
        self.get.place(x=280, y=15)
        self.frame=tkinter.Frame(root, bd=2)#bd是边框宽度
        self.scrollbar=tkinter.Scrollbar(self.frame)
        self.edit=tkinter.Text(self.frame, yscrollcommand=self.scrollbar.set,\
                               width=96, height=32)#以下都是绑定滚动条到文本框
        self.scrollbar.config(command=self.edit.yview)
        self.edit.pack(side=tkinter.LEFT)
        self.scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
        self.frame.place(y=50)
    def Get(self):
        url='http://legacy.python.org/channews.rdf'
        page=urllib.request.urlopen(url)
        data=page.read()
        parser=MyXML(self.edit)
        parser.feed(data)

if __name__=='__main__':
    root=tkinter.Tk()
    window=Window(root)
    root.minsize(600,480)
    root.maxsize(600,480)
    root.mainloop()
</span>



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值