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 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):
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
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 BeautifulSoup import BeautifulSoup
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腳本
print 'Content-type:text/plain'
print 'hello,world'
text.plain 說明是普通文本,如果頁面是HTML,這一行就是text/html
15.2.6 使用cgitb調試
調用回溯的CGI腳本
import cgitb;cgitb.enable()
print 'Content-type: text/html'
print 1/0
可以通過浏覽器通路下
15.2.7 使用cgi子產品
輸入時通過HTML表單提供給CGI腳本的鍵-值對,或稱字段。可以使用cgi子產品的FieldStorage類從CGI腳本中擷取這些字段。當建立FieldStorage執行個體時,它會從請求中擷取輸入變量,然後通過類字典接口将它們提供給程式。FieldStorage的值可以通過普通的鍵查找方式通路,但是因為一些技術原因,FieldStorage的元素并不是真正所要的值。比如知道請求中包括名為name的值,就不應該像下面這麼做:
form = cgi.FieldStorage()
name = form['name']
而應該這樣做:
name = form['name'].value
擷取值得簡單方式就是用getvalue方法,它類似于字典的get方法,但它會傳回項目的value特性的值。
name = form.getvalue('name','Unknown')
在上面的代碼,我提供了一個預設值unknown。如果不提供的話,就會将None作為預設值使用。
利用FieldStorage擷取一個值得CGI腳本
import cgi
name = from.getvalue('name','world')
print 'Hello,%s!' % name
CGI腳本的輸入一般都是從已經送出的web表單中獲得,但是也可以直接使用參數調用CGI程式。
15.2.8 簡單的表單
從CGI腳本擷取資訊的方法有兩種:GET方法和POST方法。
帶有HTML表單的問候腳本
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']
%>
<title>hello</title>
<p>hello, <%=choice(adjectives)%> world. my name is Mr. Gumby.</p>
<% - 像這樣 -%> 書寫注釋。
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進行遠端過程調用。
本文轉自潘闊 51CTO部落格,原文連結:http://blog.51cto.com/pankuo/1661449,如需轉載請自行聯系原作者