可爱的 Python: 使用 mechanize 和 Beautiful Soup 轻松收集 Web 数据
2010-01-20 00:00:00 来源:WEB开发网对感兴趣的站点进行交互式研究后,我发现我希望执行的查询含有一些固定的元素和一些变化的元素。我仅仅是将这些元素连接成一个大的 GET 请求并查看 “results” 页面。而结果列表包含了我实际需要的资源的链接。因此,我访问这些链接(当此过程出现某些错误时,会抛出 try/except 块)并保存在这些内容页面上找到的任何内容。
很简单,是不是?Mechanize 可以做的不止这些,但是这个简单的例子向您展示了 Mechanize 的大致功能。
处理结果
现在,我们已经完成了对 mechanize 的操作;剩下的工作是理解在 fetch() 循环期间保存的大量 HTML 文件。批量处理特性让我能够在一个不同的程序中将这些文件整齐、明显地分离开来,fetch() 和 process() 可能交互得更密切。Beautiful Soup 使得后期处理比初次获取更加简单。
对于这个批处理任务,我们希望从获取的各种 Web 页面的零散内容中生成表式的以逗号分隔的值(CSV)数据。
清单 2. 使用 Beautiful Soup 从无序的内容中生成整齐的数据from glob import glob
from BeautifulSoup import BeautifulSoup
def process():
print "!MOVIE,DIRECTOR,KEY_GRIP,THE_MOOSE"
for fname in glob('result_*'):
# Put that sloppy HTML into the soup
soup = BeautifulSoup(open(fname))
# Try to find the fields we want, but default to unknown values
try:
movie = soup.findAll('span', {'class':'movie_title'})[1].contents[0]
except IndexError:
fname = "UNKNOWN"
try:
director = soup.findAll('div', {'class':'director'})[1].contents[0]
except IndexError:
lname = "UNKNOWN"
try:
# Maybe multiple grips listed, key one should be in there
grips = soup.findAll('p', {'id':'grip'})[0]
grips = " ".join(grips.split()) # Normalize extra spaces
except IndexError:
title = "UNKNOWN"
try:
# Hide some stuff in the HTML <meta> tags
moose = soup.findAll('meta', {'name':'shibboleth'})[0]['content']
except IndexError:
moose = "UNKNOWN"
print '"%s","%s","%s","%s"' % (movie, director, grips, moose)
第一次查看 Beautiful Soup,process() 中的代码令人印象深刻。读者应当阅读有关文档来获得关于这个模块的更多细节,但是这个代码片段很好地体现了它的整体风格。大多数 soup 代码包含一些对只含有格式良好的 HTML 的页面的 .findAll() 调用。这里是一些类似 DOM 的 .parent、nextSibling 和 previousSibling 属性。它们类似于 Web 浏览器的 “quirks” 模式。我们在 soup 中找到的内容并不完全 是一个解析树。
结束语
诸如我之类的守旧者,甚至于一些更年轻的读者,都会记住使用 TCL Expect(或使用用 Python 和其他许多语言编写的类似内容)编写脚本带来的愉悦。自动化与 shell 的交互,包括 telnet、ftp、ssh 等等远程 shell,变得非常的直观,因为会话中的所有内容都被显示出来。Web 交互变得更加细致,因为信息被分为头部和内容体,并且各种相关的资源常常通过 href 链接、框架、Ajax 等被绑定在一起。然而,总的来说,您可以 使用 wget 之类的工具来检索 Web 服务器提供的所有字节,然后像使用其他连接协议一样运行与 Expect 风格完全相同的脚本。
在实践中,几乎没有编程人员过分执着于过去的老方法,比如我建议的 wget + Expect 方法。Mechanize 保留了许多与出色的 Expect 脚本相同的东西,令人感觉熟悉和亲切,并且和 Expect 一样易于编写(如果不是更简单的话)。Browser() 对象命令,比如 .select_form()、.submit() 和 .follow_link(),真的是实现 “查找并发送” 操作的最简单、最明显的方法,同时绑定了我们希望在 Web 自动化框架中具备的复杂状态和会话处理的所有优点。
更多精彩
赞助商链接