(.*?)')text = urlopen('http://python.org/community" />

python之万维网

发布时间:2019-06-24 15:53:34编辑:auto阅读(1250)

    15.1 屏幕抓取

    屏幕抓取是程序下载网页并且提取信息的过程。

    简单的屏幕抓取程序

    from urllib import urlopen

    import re

    p = re.compile('<h3><a .*?><a .*? href="(.*?)">(.*?)</a>')

    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中可能只用一个开始标签(<p>标签)结束一段然后开始下一段,而在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 

    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

    print 1/0

    print 'hello,world'

    可以通过浏览器访问下


     15.2.7 使用cgi模块

    输入时通过HTML表单提供给CGI脚本的键-值对,或称字段。可以使用cgi模块的FieldStorage类从CGI脚本中获取这些字段。当创建FieldStorage实例时,它会从请求中获取输入变量,然后通过类字典接口将它们提供给程序。FieldStorage的值可以通过普通的键查找方式访问,但是因为一些技术原因,FieldStorage的元素并不是真正所要的值。比如知道请求中包括名为name的值,就不应该像下面这么做:

    form = cgi.FieldStorage()

    name = form['name']

    而应该这样做:

    form = cgi.FieldStorage()

    name = form['name'].value

    获取值得简单方式就是用getvalue方法,它类似于字典的get方法,但它会返回项目的value特性的值。

    form = cgi.FieldStorage()

    name = form.getvalue('name','Unknown')

    在上面的代码,我提供了一个默认值unknown。如果不提供的话,就会将None作为默认值使用。

    利用FieldStorage获取一个值得CGI脚本

    #!/usr/bin/env python

    import cgi

    form = cgi.FieldStorage()

    name = from.getvalue('name','world')

    print 'Content-type:text/plain'

    print

    print 'Hello,%s!' % name


     CGI脚本的输入一般都是从已经提交的web表单中获得,但是也可以直接使用参数调用CGI程序。


    15.2.8 简单的表单

    从CGI脚本获取信息的方法有两种:GET方法和POST方法。

    带有HTML表单的问候脚本

    #!/usr/bin/env python

    import cgi

    form = cgi.FieldStorage()

    name = from.getvalue('name','world')

    print ""Content-type:text/html


    <html>

     <head>

      <title>Greeting Page</title>

     </head>

     <body>

      <h1>hello,%s1</h1>

      <form action='simple3.cgi'>

    change name <input type='text' name='name'/>

    <input type='submit'/>

     </form>

     </body>

    </html>

    """ % name

    在脚本的开始处先获取CGI参数name。


    15.3 mod_python

    mod_python是apache的扩展模块。


    15.3.1 安装mod_python

    $./configure --with-apxs=/usr/local/apache/bin/apxs

    $make

    $make install 


    配置apache

    LoadModule python_module libexec/mod_python.so


    在.htaccess文件添加

    <Directory /path/to/your/directory>

    (add the directory here)

    </Directory>



    15.3.2 CGI处理程序

    CGI处理程序在使用CGI的时候会模拟程序运行的环境。所以可以用mod_python运行程序,但是还可以使用gi和gitb模块把它当作CGI脚本来写。


    如果要使用CGI处理程序,要将下面的代码放在CGI脚本所在目录中的.htaccess文件内

    SetHandler mod_python

    PythonHandler mod_python.cgihandler


    需要调试信息的话,增加代码:

    PythonDebug On

    开发完之后,在去掉。

    为了运行CGI脚本,可能需要脚本以.py结尾---尽管访问的时候还是用以.cgi结尾的URL,mod_python在查找满足请求的文件时会将.cgi转换为.py


    15.3.3 PSP

    PSP文档是HTML以及python代码的混合,python代码会包括在具有特殊用途的标签中。任何HTML会被转换为输出函数的调用。

    只要把下面 的代码放在.htaccess文件中即可设置PSP页面:

    AddHandler mod_python .psp

    PythonHandler mod_python .psp


    PSP标签有两类:一类用于语句,另外一类用于表达式。

    带有少量随机数据的PSP例子

    <%

    from random import choice

    adjectives = ['beautiful','cruel']

    %>

    <html>

     <head>

      <title>hello</title>

     </head>

     <body>

     <p>hello, <%=choice(adjectives)%> world. my name is Mr. Gumby.</p>

     </body>

    </html>


    <% - 像这样 -%> 书写注释。


    15.3.4 发布

    要使用发布处理程序,需要下面代码放在.htaccess文件中。

    AddHandler mod_python .py

    PythonHandler mod_python.publisher

    这样可以使用发布处理程序把所有以.py当作python脚本运行。


    下面的函数已经可以发布处理程序了:

    def index(req):

    return "hello,world"

    请求对象访问受到请求中德信息,以及设置自定义HTTP首部等。


    使用mod_python发布处理程序进行验证

    from sha import sha

    __auth_realm__ = "A simple test"

    def __auth__(req,user,pswd):

    return user == "Gumby" and sha(pswd).hexdigest() == \

    '13hj3123012kllkjfl1'

    def __access__(req,user):

    return True

    def index(req,name="world"):

    return "<html>hello,%s!</html>" % name


    15.4 网络应用程序框架


    15.5 web服务:正确分析

    15.5.1 RSS

    15.5.2 使用XML-RPC进行远程过程调用。


关键字