楼主: lastwinner

[参考文档] Python 研究(Dive Into Python)

[复制链接]
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
131#
 楼主| 发表于 2006-7-15 19:53 | 只看该作者
例 8.3. dialect.py 的输出结果
运行这个脚本会将 第 3.2 节 “List 介绍” 转换成模仿瑞典厨师用语 (mock Swedish Chef-speak) (来自 The Muppets), 模仿埃尔默唠叨者用语 (mock Elmer Fudd-speak) (来自 Bugs Bunny 卡通画) 和模仿中世纪英语 (mock Middle English) (零散地来源于乔叟的《坎特伯雷故事集》)。如果您查看输出页面的 HTML 源代码,您会发现所有的 HTML 标记和属性没有改动,但是在标记之间的文本被转换成模仿语言了。如果您观查得更仔细些,您会发现,实际上,仅有标题和段落被转换了;代码列表和屏幕例子没有改动。

<div class="abstract">
<p>Lists awe <span class="application">Pydon</span>'s wowkhowse datatype.
If youw onwy expewience wif wists is awways in
<span class="application">Visuaw Basic</span> ow (God fowbid) de datastowe
in <span class="application">Powewbuiwdew</span>, bwace youwsewf fow
<span class="application">Pydon</span> wists.</p>
</div>

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
132#
 楼主| 发表于 2006-7-15 19:55 | 只看该作者
8.2. sgmllib.py 介绍
HTML 处理分成三步: 将 HTML 分解成它的组成片段,对片段进行加工,接着将片段再重新合成 HTML。第一步是通过 sgmllib.py 来完成的,它是标准 Python 库的一部分。

理解本章的关键是要知道 HTML 不只是文本,更是结构化文本。这种结构来源于开始与结束标记的或多或少分级序列。通常您并不以这种方式处理 HTML ,而是以 文本方式 在一个文本编辑中对其进行处理,或以 可视的方式 在一个浏览器中进行浏览或页面编辑工具中进行编辑。sgmllib.py 表现出了 HTML 的结构。

sgmllib.py 包含一个重要的类: SGMLParser。SGMLParser 将 HTML 分解成有用的片段,比如开始标记和结束标记。一旦它成功地分解出某个数据为一个有用的片段,它会根据所发现的数据,调用一个自身内部的方法。为了使用这个分析器,您需要子类化 SGMLParser 类,并且覆盖这些方法。这就是当我说它表示了 HTML 结构的意思: HTML 的结构决定了方法调用的次序和传给每个方法的参数。

SGMLParser 将 HTML 分析成 8 类数据,然后对每一类调用单独的方法:

开始标记 (Start tag)
是一个开始一个块的 HTML 标记,象 <html>,<head>,<body> 或 <pre> 等,或是一个独一的标记,象 <br> 或 <img> 等。当它找到一个开始标记 tagname,SGMLParser 将查找名为 start_tagname 或 do_tagname 的方法。例如,当它找到一个 <pre> 标记,它将查找一个 start_pre 或 do_pre 的方法。如果找到了,SGMLParser 会使用这个标记的属性列表来调用这个方法;否则,它用这个标记的名字和属性列表来调用 unknown_starttag 方法。
结束标记 (End tag)
是结束一个块的 HTML 标记,象 </html>,</head>,</body> 或 </pre> 等。当找到一个结束标记时,SGMLParser 将查找名为 end_tagname 的方法。如果找到,SGMLParser 调用这个方法,否则它使用标记的名字来调用 unknown_endtag 。
字符引用 (Character reference)
用字符的十进制或等同的十六进制来表示的转义字符,象  。当找到,SGMLParser 使用十进制或等同的十六进制字符文本来调用 handle_charref 。
实体引用 (Entity reference)
HTML 实体,象 &copy;。当找到,SGMLParser 使用 HTML 实体的名字来调用 handle_entityref 。
注释 (Comment)
HTML 注释, 包括在 <!-- ... -->之间。当找到,SGMLParser 用注释内容来调用 handle_comment。
处理指令 (Processing instruction)
HTML 处理指令,包括在 <? ... > 之间。当找到,SGMLParser 用处理指令内容来调用 handle_pi。
声明 (Declaration)
HTML 声明,如 DOCTYPE,包括在 <! ... >之间。当找到,SGMLParser 用声明内容来调用 handle_decl。
文本数据 (Text data)
文本块。不满足其它 7 种类别的任何东西。当找到,SGMLParser 用文本来调用 handle_data。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
133#
 楼主| 发表于 2006-7-15 19:55 | 只看该作者
Python 2.0 存在一个 bug,即 SGMLParser 完全不能识别声明(handle_decl 永远不会调用),这就意味着 DOCTYPE 被静静地忽略掉了。在这错误在 Python 2.1 中改正了。

sgmllib.py 所附带的一个测试套件举例说明了这一点。您可以运行 sgmllib.py,在命令行下传入一个 HTML 文件的名字,然后它会在分析标记和其它元素的同时将它们打印出来。它的实现是通过子类化 SGMLParser 类,然后定义 unknown_starttag,unknown_endtag,handle_data 和其它方法来实现的。这些方法简单地打印出它们的参数。


在 Windows 下的 ActivePython IDE 中,您可以在 “Run script” 对话框中指定命令行参数。用空格将多个参数分开。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
134#
 楼主| 发表于 2006-7-15 19:55 | 只看该作者
例 8.4. sgmllib.py 的样例测试
下面是一个片段,来自本书的 HTML 版本的目录,toc.html。 当然,您的存储路径可能与我的有所不同。 (如果您还没有下载本书的 HTML 版本, 可以从 http://diveintopython.org/ 下载。

c:\python23\lib> type "c:\downloads\diveintopython\html\toc\index.html"

<!DOCTYPE html
  PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
   
      <title>Dive Into Python</title>
      <link rel="stylesheet" href="diveintopython.css" type="text/css">

... 略 ...
通过 sgmllib.py 的测试套件来运行它,会得到如下的输出结果:

c:\python23\lib> python sgmllib.py "c:\downloads\diveintopython\html\toc\index.html"
data: '\n\n'
start tag: <html lang="en" >
data: '\n   '
start tag: <head>
data: '\n      '
start tag: <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" >
data: '\n   \n      '
start tag: <title>
data: 'Dive Into Python'
end tag: </title>
data: '\n      '
start tag: <link rel="stylesheet" href="diveintopython.css" type="text/css" >
data: '\n      '

... 略 ...

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
135#
 楼主| 发表于 2006-7-15 19:56 | 只看该作者
下面是本章其它部分的路标:
  • 子类化 SGMLParser 来创建从 HTML 文档中抽取感兴趣的数据的类。
  • 子类化 SGMLParser 来创建 BaseHTMLProcessor,它覆盖了所有8个处理方法,然后使用它们从片段中重建原始的 HTML。
  • 子类化 BaseHTMLProcessor 来创建 Dialectizer,它增加了一些方法,专门用来处理指定的 HTML 标记,然后覆盖了 handle_data 方法,提供了用来处理 HTML 标记之间文本块的框架。
  • 子类化 Dialectizer 来创建定义了文本处理规则的类。这些规则被 Dialectizer.handle_data 使用。
  • 编写一个测试套件,它可以从 http://diveintopython.org/ 处抓取一个真正的 web 页面,然后处理它。

继续阅读本章, 您还可以学习到有关 locals, globals 和基于 dictionary 的字符串格式化的内容。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
136#
 楼主| 发表于 2006-7-15 19:57 | 只看该作者
8.3. 从 HTML 文档中提取数据
为了从 HTML 文档中提取数据,将 SGMLParser 类进行子类化,然后对想要捕捉的标记或实体定义方法。

从 HTML 文档中提取数据的第一步是得到某个 HTML 文件。如果在您的硬盘里存放着 HTML 文件,您可以使用 file 函数 将它读出来,但是真正有意思的是从实际的网页得到 HTML。

例 8.5. urllib 介绍
>>> import urllib                                       
>>> sock = urllib.urlopen("http://diveintopython.org/"
>>> htmlSource = sock.read()                           
>>> sock.close()                                       
>>> print htmlSource                                    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head>
      <meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1'>
   <title>Dive Into Python</title>
<link rel='stylesheet' href='diveintopython.css' type='text/css'>
<link rev='made' href='mailto:mark@diveintopython.org'>
<meta name='keywords' content='Python, Dive Into Python, tutorial, object-oriented, programming, documentation, book, free'>
<meta name='description' content='a free Python tutorial for experienced programmers'>
</head>
<body bgcolor='white' text='black' link='#0000FF' vlink='#840084' alink='#0000FF'>
<table cellpadding='0' cellspacing='0' border='0' width='100%'>
<tr><td class='header' width='1%' valign='top'>diveintopython.org</td>
<td width='99%' align='right'><hr size='1' noshade></td></tr>
<tr><td class='tagline' colspan='2'>Python&nbsp;for&nbsp;experienced&nbsp;programmers</td></tr>

[...略...]  urllib 模块是标准 Python 库的一部分。它包含了一些函数,可以从基于互联网的 URL (主要指网页) 来获取信息并且真正取回数据。
  urllib 模块最简单的使用是提取用 urlopen 函数取回的网页的整个文本。打开一个 URL 同 打开一个文件相似。urlopen 的返回值是象文件一样的对象,它具有一个文件对象一样的方法。
  使用由 urlopen 所返回的类文件对象所能做的最简单的事情就是 read,它可以将网页的整个 HTML 读到一个字符串中。这个对象也支持 readlines 方法,这个方法可以将文本按行放入一个列表中。
  当用完这个对象,要确保将它 close,就如同一个普通的文件对象。
  现在我们将 http://diveintopython.org/ 主页的完整的 HTML 保存在一个字符串中了,接着我们将分析它。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
137#
 楼主| 发表于 2006-7-15 19:57 | 只看该作者
例 8.6. urllister.py 介绍
如果您还没有下载本书附带的例子程序, 可以 下载本程序和其他例子程序。


from sgmllib import SGMLParser

class URLLister(SGMLParser):
    def reset(self):                              
        SGMLParser.reset(self)
        self.urls = []

    def start_a(self, attrs):                     
        href = [v for k, v in attrs if k=='href']  
        if href:
            self.urls.extend(href)  reset 由 SGMLParser 的 __init__ 方法来调用,也可以在创建一个分析器实例时手工来调用。所以如果您需要做初始化,在 reset 中去做,而不要在 __init__ 中做。这样当某人重用一个分析器实例时,会正确地重新初始化。
  只要找到一个 <a> 标记,start_a 就会由 SGMLParser 进行调用。这个标记可以包含一个 href 属性,或者包含其它的属性,如 name 或 title。attrs 参数是一个 tuple 的 list,[(attribute, value), (attribute, value), ...]。或者它可以只是一个有效的 HTML 标记 <a> (尽管无用),这时 attrs 将是个空 list。
  我们可以通过一个简单的 多变量 list 映射来查找是否这个 <a> 标记拥有一个 href 属性。
  象 k=='href' 的字符串比较是区分大小写的,但是这里是安全的。因为 SGMLParser 会在创建 attrs 时将属性名转化为小写。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
138#
 楼主| 发表于 2006-7-15 19:57 | 只看该作者
例 8.7. 使用 urllister.py
>>> import urllib, urllister
>>> usock = urllib.urlopen("http://diveintopython.org/"
>>> parser = urllister.URLLister()
>>> parser.feed(usock.read())         
>>> usock.close()                     
>>> parser.close()                    
>>> for url in parser.urls: print url
toc/index.html
#download
#languages
toc/index.html
appendix/history.html
download/diveintopython-html-5.0.zip
download/diveintopython-pdf-5.0.zip
download/diveintopython-word-5.0.zip
download/diveintopython-text-5.0.zip
download/diveintopython-html-flat-5.0.zip
download/diveintopython-xml-5.0.zip
download/diveintopython-common-5.0.zip


...略...  调用定义在 SGMLParser 中的 feed 方法,将 HTML 内容放入分析器中。 [1] 这个方法接收一个字符串,这个字符串就是 usock.read() 所返回的。
  象处理文件一样,一旦处理完毕,您应该 close 您的 URL 对象。
  您也应该 close 您的分析器对象,但出于不同的原因。feed 方法不保证对传给它的全部 HTML 进行处理,它可能会对其进行缓冲处理,等待接收更多的内容。一旦没有更多的内容,应调用 close 来刷新缓冲区,并且强制所有内容被完全处理。
  一旦分析器被 close,分析过程也就结束了。parser.urls 中包含了在 HTML 文档中所有的链接 URL。 (当您读到此处发现输出结果不一样,那是因为下载了本书的更新版本。)

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
139#
 楼主| 发表于 2006-7-15 19:58 | 只看该作者
Footnotes
[1] 象 SGMLParser 这样的分析器,技术术语叫做 消费者 (consumer)。它消费 HTML,并且拆分它。也许因为这就选择了 feed 这个名字,以便同 消费者 这个主题相适应。就个人来说,它让我想象在动物园看展览。里面有一个黑漆漆的兽穴,没有树,没有植物,没有任何生命的迹象。但只要您非常安静地站着,尽可能靠近着瞧,您会看到在远处的角落里有两只明眸在盯着您。但是您会安慰自已那不过是心理作用。唯一知道兽穴里并不是空无一物的方法,就是在栅栏上有一个不明显的标记,上面写着 “禁止给分析器喂食”。但也许只有我这么想,不管怎么样,这种心理想象很有意思。

使用道具 举报

回复
论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
140#
 楼主| 发表于 2006-7-15 20:05 | 只看该作者
8.4. BaseHTMLProcessor.py 介绍
SGMLParser 自身不会产生任何结果。它只是分析,分析,再分析,对于它找到的有趣的东西会调用相应的一个方法,但是这些方法什么都不做。SGMLParser 是一个 HTML 消费者 (consumer): 它接收 HTML,将其分解成小的、结构化的小块。正如您所看到的,在 前一节 中,您可以通过将 SGMLParser 子类化来定义一个类,它可以捕捉特别标记和生成有用东西,如一个网页中所有链接的一个列表。现在我们将沿着这条路更深一步。我们要定义一个可以捕捉 SGMLParser 所丢出来的所有东西的一个类,接着重建整个 HTML 文档。用技术术语来说,这个类将是一个 HTML 生产者 (producer)。

SGMLParser 子类化 BaseHTMLProcessor ,并且提供了全部的 8 个处理方法: unknown_starttag, unknown_endtag, handle_charref, handle_entityref, handle_comment, handle_pi, handle_decl 和handle_data。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表