第十五章 Python和Web
本章討論Python Web編程的一些方面。
三個重要的主題:屏幕抓取、CGI和mod_python。
屏幕抓取
屏幕抓取是通過程序下載網頁并從中提取信息的過程。
下載數據并對其進行分析。
從Python Job Board(http://python.org/jobs)提取招聘單位的名稱和網站。
from urllib.request import urlopen
import rep = re.compile('<a href="(/jobs/\\d+)/">(.*?)</a>')
text = urlopen('http://python.org/jobs').read().decode()
for url,name in p.findall(text):print('{}({})'.format(name,url))#結果為:
'''
PhD Position in Computer Simulation & Machine Learning(/jobs/6173)
Data Engineering Senior Lead(/jobs/6172)
Python Systems / Infrastructure Engineer(/jobs/6171)
Django Backend Engineer(/jobs/6170)
Senior Full Stack Engineer(/jobs/6169)
Head of Software Engineering - Python (Python Stack/ Django / FinTech / Google Cloud) – Johannesburg(/jobs/6168)
Senior Software Engineer (Remote)(/jobs/6166)
(Senior) Software Engineer (80-100%, f::m::d)(/jobs/6164)
Senior Backend Developer (Python)(/jobs/6163)
Python/GoLang Developer (Web Scraping)(/jobs/6161)
Scientific Software Developer(/jobs/6160)
Sr. Developer for Python, Django(/jobs/6159)
Data Scientist(/jobs/6156)
Data Scientist (Delivery)(/jobs/6155)
Backend Software Engineer(/jobs/6152)
Senior Python Developer (remote)(/jobs/6151)
REMOTE PYTHON/REACT JOBS(/jobs/6150)
Remote Python Developer(/jobs/6149)
Senior Python Developer(/jobs/6148)
Data Engineer(/jobs/6147)
Distinguished Machine Learning Engineer(/jobs/6146)
Senior Python Engineer(/jobs/6145)
Full Stack Software Engineer(/jobs/6144)
Open Source Engineering Manager(/jobs/6143)
Senior Python Engineer(/jobs/6142)
'''
Tidy和XHTML解析
1,Tidy是什么?
Tidy是用于對格式不正確且不嚴謹的HTML進行修復的工具。
Tidy并不能修復HTML文件存在的所有問題,但確實能夠確保文件是格式良好的(即所有元素都嵌套正確)
2,獲取Tidy
找出可供使用的包裝器: pip search tidy
安裝PyTidyLib:pip install pytidylib
3,為何使用XHTML
XHTML和舊式HTML的主要區別在于,XHTML非常嚴格,要求顯式地結束所有的元素。
在HTML中,可通過(使用標簽<p>
)開始另一個段落來結束當前段落,但在XHTML中,必須先(使用標簽</p>
)顯式地結束當前段落。
XHTML是一種XML方言,可使用各種出色的工具(如XPath)來處理。
要對Tidy生成的格式良好的XHTML進行解析,一種非常簡單的方式是使用標準庫模塊html.parser中的HTMLParser類。
4,使用HTMLParser
使用HTMLParser意味著繼承它,并重寫各種事件處理方法。
HTMLParser中的回調方法
回調方法 | 何時被調用 |
---|---|
handle_starttag(tag, attrs) | 遇到開始標簽時調用。attrs是一個由形如(name, value)的元組組成的序列 |
handle_startendtag(tag, attrs) | 遇到空標簽時調用。默認分別處理開始標簽和結束標簽 |
handle_endtag(tag) | 遇到結束標簽時調用 |
handle_data(data) | 遇到文本數據時調用 |
handle_charref(ref) | 遇到形如&#ref;的字符引用時調用 |
handle_entityref(name) | 遇到形如&name;的實體引用時調用 |
handle_comment(data) | 遇到注釋時;只對注釋內容調用 |
handle_decl(decl) | 遇到形如<!..>的聲明時調用 |
handle_pi(data) | 用于處理指令 |
unknown_decl(data) | 遇到未知聲明時調用 |
使用模塊HTMLParser的屏幕抓取程序
from urllib.request import urlopen
from html.parser import HTMLParserdef isjob(url):try:a, b, c, d = url.split('/')except ValueError:return Falsereturn a == d == '' and b == 'jobs' and c.isdigit()class Scraper(HTMLParser):in_link = False #使用了一個布爾狀態變量(屬性)來跟蹤是否位于相關的鏈接中def handle_starttag(self, tag, attrs): #handle_starttag的參數是一個由形如(key, value)的元組組成的列表attrs = dict(attrs) #因此使用dict將它們轉換為字典,以便管理url = attrs.get('href', '')if tag == 'a' and isjob(url):self.url = urlself.in_link = Trueself.chunks = []def handle_data(self, data):if self.in_link:self.chunks.append(data)def handle_endtag(self, tag):if tag == 'a' and self.in_link:print('{} ({})'.format(''.join(self.chunks), self.url)) #為了(在方法handle_endtag中)輸出結果,將所有的文本塊合并在一起。self.in_link = Falsetext = urlopen('http://python.org/jobs').read().decode()
parser = Scraper()
parser.feed(text) #為運行這個解析器,調用其方法feed將并text作為參數
parser.close() #然后調用其方法close。'''
PhD Position in Computer Simulation & Machine Learning (/jobs/6173/)
Data Engineering Senior Lead (/jobs/6172/)
Python Systems / Infrastructure Engineer (/jobs/6171/)
Django Backend Engineer (/jobs/6170/)
Senior Full Stack Engineer (/jobs/6169/)
Head of Software Engineering - Python (Python Stack/ Django / FinTech / Google Cloud) – Johannesburg (/jobs/6168/)
Senior Software Engineer (Remote) (/jobs/6166/)
(Senior) Software Engineer (80-100%, f::m::d) (/jobs/6164/)
Senior Backend Developer (Python) (/jobs/6163/)
Python/GoLang Developer (Web Scraping) (/jobs/6161/)
Scientific Software Developer (/jobs/6160/)
Sr. Developer for Python, Django (/jobs/6159/)
Data Scientist (/jobs/6156/)
Data Scientist (Delivery) (/jobs/6155/)
Backend Software Engineer (/jobs/6152/)
Senior Python Developer (remote) (/jobs/6151/)
REMOTE PYTHON/REACT JOBS (/jobs/6150/)
Remote Python Developer (/jobs/6149/)
Senior Python Developer (/jobs/6148/)
Data Engineer (/jobs/6147/)
Distinguished Machine Learning Engineer (/jobs/6146/)
Senior Python Engineer (/jobs/6145/)
Full Stack Software Engineer (/jobs/6144/)
Open Source Engineering Manager (/jobs/6143/)
Senior Python Engineer (/jobs/6142/)
'''
Beautiful Soup
Beautiful Soup是一個小巧而出色的模塊,用于解析你在Web上可能遇到的不嚴謹且格式糟糕的HTML。
下載并安裝Beautiful Soup:pip install beautifulsoup4
使用Beautiful Soup的屏幕抓取程序
from urllib.request import urlopen
from bs4 import BeautifulSoup
text = urlopen('http://python.org/jobs').read()
soup = BeautifulSoup(text, 'html.parser')
jobs = set()
for job in soup.body.section('h2'): #使用soup.body來獲取文檔體,再訪問其中的第一個section。 使用參數'h2'調用返回的對象。jobs.add('{} ({})'.format(job.a.string, job.a['href'])) #屬性string是鏈接的文本內容,而a['href']為屬性href。print('\n'.join(sorted(jobs, key=str.lower)))
'''
(Senior) Software Engineer (80-100%, f::m::d) (/jobs/6164/)
Backend Software Engineer (/jobs/6152/)
Data Engineer (/jobs/6147/)
Data Engineering Senior Lead (/jobs/6172/)
Data Scientist (/jobs/6156/)
Data Scientist (Delivery) (/jobs/6155/)
Distinguished Machine Learning Engineer (/jobs/6146/)
Django Backend Engineer (/jobs/6170/)
Full Stack Software Engineer (/jobs/6144/)
Head of Software Engineering - Python (Python Stack/ Django / FinTech / Google Cloud) – Johannesburg (/jobs/6168/)
Open Source Engineering Manager (/jobs/6143/)
PhD Position in Computer Simulation & Machine Learning (/jobs/6173/)
Python Systems / Infrastructure Engineer (/jobs/6171/)
Python/GoLang Developer (Web Scraping) (/jobs/6161/)
Remote Python Developer (/jobs/6149/)
REMOTE PYTHON/REACT JOBS (/jobs/6150/)
Scientific Software Developer (/jobs/6160/)
Senior Backend Developer (Python) (/jobs/6163/)
Senior Full Stack Engineer (/jobs/6169/)
Senior Python Developer (/jobs/6148/)
Senior Python Developer (remote) (/jobs/6151/)
Senior Python Engineer (/jobs/6142/)
Senior Python Engineer (/jobs/6145/)
Senior Software Engineer (Remote) (/jobs/6166/)
Sr. Developer for Python, Django (/jobs/6159/)
'''
使用CGI創建動態網頁
通用網關接口(CGI)
CGI是一種標準機制,Web服務器可通過它將(通常是通過Web表達提供的)查詢交給專用程序,并以網頁的方式顯示查詢結果。
要讓CGI腳本能夠通過Web進行訪問(和運行),必須將其放在Web服務器能夠訪問的地方、添加!#行并設置合適的文件權限。
對于重要的Web應用,大多數人都不會直接為其編寫CGI腳本,而是選擇使用Web框架,因為它會替你完成很多繁重的工作。
Python Web應用框架
名稱 | 網站 |
---|---|
Django | https://djangoproject.com |
TurboGears | http://turbogears.org |
web2py | http://web2py.com |
Grok | https://pypi.python.org/pypi/grok |
Zope2 | https://pypi.python.org/pypi/Zope2 |
Pyramid | https://trypyramid.com |
Flask | http://flask.pocoo.org |
Web服務:更高級的抓取
鑒于實現Web服務的方式眾多(且涉及大量的協議),同時每個Web服務系統都可能提供多種服務,因此有時必須以客戶端能夠自動解讀的方式描述服務,這被稱為元服務
。
有關這種描述的標準是Web服務描述語言(WSDL)。
WSDL是一種XML格式,描述了通過服務可使用哪些方法以及這些方法的參數和返回值等方面。
除支持SOAP等服務協議外,很多乃至大部分Web服務工具包都支持WSDL。
RSS和相關內容
RSS指的是富網站摘要(Rich Site Summary)、RDF網站摘要(RDF Site Summary)或簡易信息聚合(Really Simple Syndication),具體指哪個取決于版本。
在最簡單的情況下,RSS是一種以XML方式列出新聞的格式。
使用XML—RPC進行遠程過程調用
除簡單的RSS下載和解析機制外,還有遠程過程調用。遠程過程調用是對基本網絡交互的抽象:客戶端程序請求服務器程序執行計算并返回結果,但這個過程被偽裝成簡單的過程(函數或方法)調用。
在客戶端代碼中,遠程過程調用看起來就像普通方法調用,但用來調用方法的對象實際上位于另一臺計算機中。
XML-RPC可能是最簡單的遠程過程調用機制,它使用HTTP和XML來實現網絡通信。
SOAP
SOAP也是一種將XML和HTTP用作底層技術的消息交換協議。
與XML-RPC一樣,SOAP也支持遠程過程調用,但SOAP規范比XML-RPC規范復雜得多。
SOAP是異步的,支持有關路由的元請求,而且類型系統非常復雜(而XML-RPC使用簡單而固定的類型集)。
小結
概念 | 解釋 |
---|---|
屏幕抓取 | 指的是自動下載網頁并從中提取信息。程序Tidy及其庫版本是很有用的工具,可用來修復格式糟糕的HTML,然后使用HTTML解析器進行解析。另一種抓取方式是使用Beautiful Soup,即便面對混亂的輸入,它也可以處理。 |
CGI | 通用網關接口是一種創建動態網頁的方式,這是通過讓Web服務器運行、與客戶端程序通信并顯示結果而實現的。模塊cgi和cgitb可用于編寫CGI腳本。CGI腳本通常是在HTML表單中調用的。 |
Flask | 一個簡單的Web框架,讓你能夠將代碼作為Web應用發布,同時不用過多操心Web部分。 |
Web應用框架 | 要使用Python開發復雜的大型Web應用,Web應用框架必不可少。對簡單的項目來說,Flask是不錯的選擇;但對于較大的項目,你可能應考慮使用Django或TurboGears。 |
Web服務 | Web服務之于程序猶如網頁之于用戶。可以認為,Web服務讓你能夠以更抽象的方式進行網絡編程。常用的Web服務標準包括RSS(以及與之類似的RDF和Atom)、XML-RPC和SOAP。 |
本章介紹的新函數
函數 | 描述 |
---|---|
cgitb.enable() | 在CGI腳本中啟用棧跟蹤 |