15.1屏幕抓取屏幕抓取是程序下载网页并且提取信息的过程。简单的屏幕抓取程序fromurllibimporturlopenimportrep=re.compile(h3a.*?a.*?href=(.*?)(.*?)/a)text=u
15.1 屏幕抓取
屏幕抓取是程序下载网页并且提取信息的过程。
简单的屏幕抓取程序
from urllib import urlopen
import re
p = re.compile('
(.*?)')
text = urlopen('http://python.org/community/jobs').read()
for url,name in p.findall(text):
print '%s (%s)' % (name,url)
上述这个已经可以用了,但是至少有3个缺点
1.正则表达式并不是完全可读的。对于更复杂的HTML代码和查询来说,表达式会变得乱七八糟并且不可维护。
2.程序对CDATA部分和字符实体之类的HTML特性是无法处理的。如果碰到了这类特性,程序很有可能会失败。
3.正则表达式被HTML源代码约束,而不是取决于更抽象的结构。这就意味着网页结构中很小的改变就会导致程序中断。
15.1.1 Tidy和XHTML解析
1.Tidy是什么
Tidy是用来修复不规范且随意的HTML的工具。它能以相当智能的方法修复一般的错误,做那些你不愿意做的事情。它也是可设置的,也可以打开或关闭各种修改选项。
Tidy不能修复HTML文件的所有问题,但是它会确保文件的格式是正确的,这样一来解析的时候就轻松多了。
2.获取Tidy库
可以从网上下载
3.在Python中使用命令行Tidy
如果正在使用UNIX或Linux系统的话,就不信要安装任何库,因为系统可能已经包括Tidy的命令行版本。
获得二进制版本后,可以使用subprocess模块运行Tidy程序。假设有个叫做messy.html的混乱的HTML文件,那么下面的程序会对该文件运行Tidy,然后打印结果:
from subprocess import Popen,PIPE
text = open('messy.html').read()
tidy = Popen('tidy',stdin=PIPE,stdout=PIPE,stderr=PIPE)
tidy.stdin.write(text)
tidy.stdin.close()
print tidy.stdout.read()
4.但为什么用XHTML
XHTML和旧版本的HTML之间的最主要区别是XHTML对于显式关闭所有元素要求更加严格。所以HTML中可能只用一个开始标签(
标签)结束一段然后开始下一段,,而在XHTML中首先需要显示地关闭当前段落。这种行为让XHTML更容易解析,因为可以直接告诉程序什么时候进入或者离开各种元素。XHTML的另外一个好处是它是XML的一种,所以可以对它使用XML的工具,例如Xpath。
解析这类从Tidy中获得的表现良好的XHTML的方法是使用标准库模块HTMLParser。
5.使用HTMLParser
使用HTMLParser的意思是继承它,并且对handle_starttage或handle_data等事件处理方法进行覆盖。
如果要进行屏幕抓取,一般不需要实现所有的解析器回调,也可能不用创造整个文档的抽象表示法来查找自己需要的内容。如果只需要记录所需信息的最小部分,那么就足够了。
使用HTMLParser模块的屏幕抓取程序
from urllib import urlopen
from HTMLParser import HTMLPaeer
class Scraper(HTMLParser):
in_h3 = False
in_link = False
def handle_starttag(self,tag,attrs):
attrs = dict(attrs)
if tag == 'h3':
self.in_h3 = True
if tag == 'a' and 'href' in attrs:
self.in_link = True
self.chunks = []
self.url = attrs['href']
def handle_data(self,data):
if self.in_link:
self.chunks.append(data)
def handle_endtag(self,tag):
if tag == 'h3':
self.in_h3 = False
if tag == 'a':
if self.in_h3 and self.in_link:
print '%s (%s)' % (''.join(self.chunks),self.url)
self.in_link = False
text = urlopen('http://python.org/community/jobs').read()
parser = Scraper()
parser.feed(text)
parser.close()
首先,没有使用Tidy,因为网页中HTML已经足够规范了。使用了一些布尔状态变量以追踪是否已经位于h3元素和链接内。在事件处理程序中检查并且更新这些变量。handle_starttag的attrs参数是由(键,值)元组组成的列表,所以使用dict函数将它们转化为字典。
handle_data方法可能还得解释一下。它使用了在处理HTML和XML这类结构化标记的基于事件的解析工作时非常常见的技术。我没有假定只掉用handle_data就能获得所有需要的文本,而是假定会通过多次调用函数获得多个文本块。这样做的原因有几个:忽略了缓冲、字符实体和标记等----只需确保获得所有文本。然后在准备输出结果时,只是将所有的文本联结在一起。可以让文本调用feed方法以运行这个解析器,然后再调用close方法。
15.1.2 Beautiful Soup
Beautiful Soup是个小模块,用来解析和经常在网上看到的那些乱七八糟而且不规则的HTML。
下载和安装beautiful Soup:下载BeautifulSoup.py文件,然后将它放置在python路径中。如果需要的话,还能下载带有安装脚本和测试的tar档案文件。
使用beautiful Soup的屏幕抓取程序
from urllib import urlopen
from BeautifulSoup import BeautifulSoup
text = urlopen('http://python.org/community/jobs').read()
soup = BeautifulSoup(text)
jobs = set()
for header in soup('h3'):
links = header('a','reference')
if not links:continue
link = links[0]
jobs.add('%s (%s)' % (link.string,link['href']))
print '\n'.join(sorted(jobs,key=lambda s: s.lower()))
用HTML文本实例化BeautifulSoup类,然后使用各种方法提取处理后的解析树的各个部分。
15.2 使用CGI创建动态网页
CGI(通用网关接口)。CGI是网络服务器可以将查询传递到专门的程序中并且在网页上显示结果的标准机制。它是创建万维网应用程序而不用编写特殊用途的应用服务器的简单方法。
Python CGI程序设计的关键工具是cgi模块。
15.2.1 第一步:准备网络服务器
15.2.2 第二步:加入Pound Bang行
当把脚本放在正确位置后,需要在脚本的开始处增加pound bang行。
#!/usr/bin/env python
15.2.3 设置文件许可
设置权限
15.2.5 简单的CGI脚本
简单的CGI脚本
#!/usr/bin/env python
print 'Content-type:text/plain'
print 'hello,world'
text.plain 说明是普通文本,如果页面是HTML,这一行就是text/html
15.2.6 使用cgitb调试
调用回溯的CGI脚本
#!/usr/bin/env python
import cgitb;cgitb.enable()
print 'Content-type: text/html'
print 1/0
print 'hello,world'
可以通过浏览器访问下
15.2.7 使用cgi模块