標籤:python 原始碼 import 運算式 全球資訊網
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.Regex並不是完全可讀的。對於更複雜的HTML代碼和查詢來說,運算式會變得亂七八糟並且不可維護。
2.程式對CDATA部分和字元實體之類的HTML特性是無法處理的。如果碰到了這類特性,程式很有可能會失敗。
3.Regex被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進行遠端程序呼叫。
本文出自 “linux_oracle” 部落格,請務必保留此出處http://pankuo.blog.51cto.com/8651697/1661449
python之全球資訊網