# 8.3. 从 HTML 文档中提取数据
为了从 HTML 文档中提取数据,将 `SGMLParser` 类进行子类化,然后对想要捕捉的标记或实体定义方法。
从 HTML 文档中提取数据的第一步是得到某个 HTML 文件。如果在您的硬盘里存放着 HTML 文件,您可以使用[处理文件的函数](../file_handling/file_objects.html "6.2. 与文件对象共事")将它读出来,但是真正有意思的是从实际的网页得到 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 for experienced programmers</td></tr>
[...略...]
```
| | |
| --- | --- |
| \[1\] | `urllib` 模块是标准 Python 库的一部分。它包含了一些函数,可以从基于互联网的 URL (主要指网页) 来获取信息并且真正取回数据。 |
| \[2\] | `urllib` 模块最简单的使用是提取用 `urlopen` 函数取回的网页的整个文本。打开一个 URL 同[打开一个文件](../file_handling/file_objects.html "6.2. 与文件对象共事")相似。`urlopen` 的返回值是像文件一样的对象,它具有一个文件对象一样的方法。 |
| \[3\] | 使用由 `urlopen` 所返回的类文件对象所能做的最简单的事情就是 `read`,它可以将网页的整个 HTML 读到一个字符串中。这个对象也支持 `readlines` 方法,这个方法可以将文本按行放入一个列表中。 |
| \[4\] | 当用完这个对象,要确保将它 `close`,就如同一个普通的文件对象。 |
| \[5\] | 现在我们将 `http://diveintopython.org/` 主页的完整的 HTML 保存在一个字符串中了,接着我们将分析它。 |
## 例 8.6. `urllister.py` 介绍
如果您还没有下载本书附带的样例程序, 可以 [下载本程序和其他样例程序](http://www.woodpecker.org.cn/diveintopython/download/diveintopython-exampleszh-cn-5.4b.zip "Download example scripts")。
```
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)
```
| | |
| --- | --- |
| \[1\] | `reset` 由 `SGMLParser` 的 `__init__` 方法来调用,也可以在创建一个分析器实例时手工来调用。所以如果您需要做初始化,在 `reset` 中去做,而不要在 `__init__` 中做。这样当某人重用一个分析器实例时,可以正确地重新初始化。 |
| \[2\] | 只要找到一个 `<a>` 标记,`start_a` 就会由 `SGMLParser` 进行调用。这个标记可以包含一个 `href` 属性,或者包含其它的属性,如 `name` 或 `title`。`attrs` 参数是一个 tuple 的 list,`[(_attribute_, _value_), (_attribute_, _value_), ...]`。或者它可以只是一个有效的 HTML 标记 `<a>` (尽管无用),这时 `attrs` 将是个空 list。 |
| \[3\] | 我们可以通过一个简单的[多变量](../native_data_types/declaring_variables.html#odbchelper.multiassign "3.4.2. 一次赋多值") [list 映射](../native_data_types/mapping_lists.html "3.6. 映射 list")来查找这个 `<a>` 标记是否拥有一个 `href` 属性。 |
| \[4\] | 像 `k=='href'` 的字符串比较是区分大小写的,但是这里是安全的。因为 `SGMLParser` 会在创建 `attrs` 时将属性名转化为小写。 |
## 例 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
...略...
```
| | |
| --- | --- |
| \[1\] | 调用定义在 `SGMLParser` 中的 `feed` 方法,将 HTML 内容放入分析器中。 \[4\] 这个方法接收一个字符串,这个字符串就是 `usock.read()` 所返回的。 |
| \[2\] | 像处理文件一样,一旦处理完毕,您应该 `close` 您的 URL 对象。 |
| \[3\] | 您也应该 `close` 您的分析器对象,但出于不同的原因。`feed` 方法不保证对传给它的全部 HTML 进行处理,它可能会对其进行缓冲处理,等待接收更多的内容。只要没有更多的内容,就应调用 `close` 来刷新缓冲区,并且强制所有内容被完全处理。 |
| \[4\] | 一旦分析器被 `close`,分析过程也就结束了。`parser.urls` 中包含了在 HTML 文档中所有的链接 URL。(如果当您读到此处发现输出结果不一样,那是因为下载了本书的更新版本。) |
## Footnotes
\[4\] 像 `SGMLParser` 这样的分析器,技术术语叫做_消费者 (consumer)_。它消费 HTML,并且拆分它。也许因此就选择了 `feed` 这个名字,以便同_消费者_ 这个主题相适应。就个人来说,它让我想象在动物园看展览。里面有一个黑漆漆的兽穴,没有树,没有植物,没有任何生命的迹象。但只要您非常安静地站着,尽可能靠近着瞧,您会看到在远处的角落里有两只明眸在盯着您。但是您会安慰自已那不过是心理作用。唯一知道兽穴里并不是空无一物的方法,就是在栅栏上有一个不明显的标记,上面写着 “禁止给分析器喂食”。但也许只有我这么想,不管怎么样,这种心理想象很有意思。
- 版权信息
- 第 1 章 安装 Python
- 1.1. 哪一种 Python 适合您?
- 1.2. Windows 上的 Python
- 1.3. Mac OS X 上的 Python
- 1.4. Mac OS 9 上的 Python
- 1.5. RedHat Linux 上的 Python
- 1.6. Debian GNU/Linux 上的 Python
- 1.7. 从源代码安装 Python
- 1.8. 使用 Python 的交互 Shell
- 1.9. 小结
- 第 2 章 第一个 Python 程序
- 2.1. 概览
- 2.2. 函数声明
- 2.3. 文档化函数
- 2.4. 万物皆对象
- 2.5. 代码缩进
- 2.6. 测试模块
- 第 3 章 内置数据类型
- 3.1. Dictionary 介绍
- 3.2. List 介绍
- 3.3. Tuple 介绍
- 3.4. 变量声明
- 3.5. 格式化字符串
- 3.6. 映射 list
- 3.7. 连接 list 与分割字符串
- 3.8. 小结
- 第 4 章 自省的威力
- 4.1. 概览
- 4.2. 使用可选参数和命名参数
- 4.3. 使用 type、str、dir 和其它内置函数
- 4.4. 通过 getattr 获取对象引用
- 4.5. 过滤列表
- 4.6. and 和 or 的特殊性质
- 4.7. 使用 lambda 函数
- 4.8. 全部放在一起
- 4.9. 小结
- 第 5 章 对象和面向对象
- 5.1. 概览
- 5.2. 使用 from _module_ import 导入模块
- 5.3. 类的定义
- 5.4. 类的实例化
- 5.5. 探索 UserDict:一个封装类
- 5.6. 专用类方法
- 5.7. 高级专用类方法
- 5.8. 类属性介绍
- 5.9. 私有函数
- 5.10. 小结
- 第 6 章 异常和文件处理
- 6.1. 异常处理
- 6.2. 与文件对象共事
- 6.3. for 循环
- 6.4. 使用 `sys.modules`
- 6.5. 与目录共事
- 6.6. 全部放在一起
- 6.7. 小结
- 第 7 章 正则表达式
- 7.1. 概览
- 7.2. 个案研究:街道地址
- 7.3. 个案研究:罗马字母
- 7.4. 使用 {n,m} 语法
- 7.5. 松散正则表达式
- 7.6. 个案研究:解析电话号码
- 7.7. 小结
- 第 8 章 HTML 处理
- 8.1. 概览
- 8.2. sgmllib.py 介绍
- 8.3. 从 HTML 文档中提取数据
- 8.4. BaseHTMLProcessor.py 介绍
- 8.5. locals 和 globals
- 8.6. 基于 dictionary 的字符串格式化
- 8.7. 给属性值加引号
- 8.8. dialect.py 介绍
- 8.9. 全部放在一起
- 8.10. 小结
- 第 9 章 XML 处理
- 9.1. 概览
- 9.2. 包
- 9.3. XML 解析
- 9.4. Unicode
- 9.5. 搜索元素
- 9.6. 访问元素属性
- 9.7. Segue [9]
- 第 10 章 脚本和流
- 10.1. 抽象输入源
- 10.2. 标准输入、输出和错误
- 10.3. 查询缓冲节点
- 10.4. 查找节点的直接子节点
- 10.5. 根据节点类型创建不同的处理器
- 10.6. 处理命令行参数
- 10.7. 全部放在一起
- 10.8. 小结
- 第 11 章 HTTP Web 服务
- 11.1. 概览
- 11.2. 避免通过 HTTP 重复地获取数据
- 11.3. HTTP 的特性
- 11.4. 调试 HTTP web 服务
- 11.5. 设置 User-Agent
- 11.6. 处理 Last-Modified 和 ETag
- 11.7. 处理重定向
- 11.8. 处理压缩数据
- 11.9. 全部放在一起
- 11.10. 小结
- 第 12 章 SOAP Web 服务
- 12.1. 概览
- 12.2. 安装 SOAP 库
- 12.3. 步入 SOAP
- 12.4. SOAP 网络服务查错
- 12.5. WSDL 介绍
- 12.6. 以 WSDL 进行 SOAP 内省
- 12.7. 搜索 Google
- 12.8. SOAP 网络服务故障排除
- 12.9. 小结
- 第 13 章 单元测试
- 13.1. 罗马数字程序介绍 II
- 13.2. 深入
- 13.3. romantest.py 介绍
- 13.4. 正面测试 (Testing for success)
- 13.5. 负面测试 (Testing for failure)
- 13.6. 完备性检测 (Testing for sanity)
- 第 14 章 测试优先编程
- 14.1. roman.py, 第 1 阶段
- 14.2. roman.py, 第 2 阶段
- 14.3. roman.py, 第 3 阶段
- 14.4. roman.py, 第 4 阶段
- 14.5. roman.py, 第 5 阶段
- 第 15 章 重构
- 15.1. 处理 bugs
- 15.2. 应对需求变化
- 15.3. 重构
- 15.4. 后记
- 15.5. 小结
- 第 16 章 函数编程
- 16.1. 概览
- 16.2. 找到路径
- 16.3. 重识列表过滤
- 16.4. 重识列表映射
- 16.5. 数据中心思想编程
- 16.6. 动态导入模块
- 16.7. 全部放在一起
- 16.8. 小结
- 第 17 章 动态函数
- 17.1. 概览
- 17.2. plural.py, 第 1 阶段
- 17.3. plural.py, 第 2 阶段
- 17.4. plural.py, 第 3 阶段
- 17.5. plural.py, 第 4 阶段
- 17.6. plural.py, 第 5 阶段
- 17.7. plural.py, 第 6 阶段
- 17.8. 小结
- 第 18 章 性能优化
- 18.1. 概览
- 18.2. 使用 timeit 模块
- 18.3. 优化正则表达式
- 18.4. 优化字典查找
- 18.5. 优化列表操作
- 18.6. 优化字符串操作
- 18.7. 小结
- 附录 A. 进一步阅读
- 附录 B. 五分钟回顾
- 附录 C. 技巧和窍门
- 附录 D. 示例清单
- 附录 E. 修订历史
- 附录 F. 关于本书
- 附录 G. GNU Free Documentation License
- G.0. Preamble
- G.1. Applicability and definitions
- G.2. Verbatim copying
- G.3. Copying in quantity
- G.4. Modifications
- G.5. Combining documents
- G.6. Collections of documents
- G.7. Aggregation with independent works
- G.8. Translation
- G.9. Termination
- G.10. Future revisions of this license
- G.11. How to use this License for your documents
- 附录 H. GNU 自由文档协议
- H.0. 序
- H.1. 适用范围和定义
- H.2. 原样复制
- H.3. 大量复制
- H.4. 修改
- H.5. 合并文档
- H.6. 文档合集
- H.7. 独立著作聚集
- H.8. 翻译
- H.9. 终止协议
- H.10. 协议将来的修订
- H.11. 如何为你的文档使用本协议
- 附录 I. Python license
- I.A. History of the software
- I.B. Terms and conditions for accessing or otherwise using Python
- 附录 J. Python 协议
- J.0. 关于译文的声明
- J.A. 软件的历史
- J.B. 使用 Python 的条款和条件