python與web編程

source:: http://code.google.com/p/python-tips/source/browse/MP3-Fetch/doc/doc_1 #! /usr/bin/python

一. 代理服務器:
代理服務器(Proxy server),從其名字上不難理解,就是做代理的,其作用與現在各種各樣的代理商差不多。

作爲教育網和169的用戶來講,他們不能直接訪問國外的站點,而且網絡速度也驚人的慢,這樣很多網絡功能就無法使用。最典型的例子就是不能用Icq了,因爲Icq的服務器都在國外,直接連不上。因此在這個時候代理服務器就起了至關重要的作用。

通常我們訪問網站都是直接與目的主機相連,使用了代理服務器,可先與代理服務器進行連接,然後把我們的請求(比如說我們想得到哪個網頁的內容)告訴代理服務器,由代理服務器幫我們取下來。一般代理服務器都有一個很大的Cache,起緩衝的作用,它不斷將新取得數據儲存到它的存儲器上;如果瀏覽器所請求的數據在它本機的存儲器上已經存在,而且是最新的話,那麼它就不重新從Web服務器取數據,而直接將存儲器上的數據傳送給用戶的瀏覽器,這樣就能顯著地提高瀏覽速度和效率了。

代理服務器通常有兩種類型,Http代理和Socks5代理。Http代理是用來瀏覽網頁用的,其端口一般是80和8080,不過也有3128等其它端口的;而socks5代理則可以看成是一種全能的代理,不管是telnet、ftp 還是irc聊天都可以用它,這類代理的端口通常是1080。

----------------------

二. 正向代理與反向代理:
1.正向代理的概念
正向代理 是一個位於客戶端和原始服務器(origin server)之間的服務器,爲了從原始服務器取得內容,客戶端向代理髮送一個請求並指定目標(原始服務器),然後代理向原始服務器轉交請求並將獲得的內容返回給客戶端。客戶端必須要進行一些特別的設置才能使用正向代理。

2.反向代理的概念
反向代理正好相反,對於客戶端而言它就像是原始服務器,並且客戶端不需要進行任何特別的設置。客戶端向反向代理的命名空間(name-space)中的內容發送普通請求,接着反向代理將判斷向何處(原始服務器)轉交請求,並將獲得的內容返回給客戶端,就像這些內容原本就是它自己的一樣。

3. 兩者區別
從用途上來講:
正向代理的典型用途是爲在防火牆內的局域網客戶端提供訪問Internet的途徑。正向代理還可以使用緩衝特性減少網絡使用率。反向代理的典型用途是將防火牆後面的服務器提供給Internet用戶訪問。反向代理還可以爲後端的多臺服務器提供負載平衡,或爲後端較慢的服務器提供緩衝服務。
另外,反向代理還可以啓用高級URL策略和管理技術,從而使處於不同web服務器系統的web頁面同時存在於同一個URL空間下。

從安全性來講:
正向代理允許客戶端通過它訪問任意網站並且隱藏客戶端自身,因此你必須採取安全措施以確保僅爲經過授權的客戶端提供服務。
反向代理對外都是透明的,訪問者並不知道自己訪問的是一個代理。

--------------------------

三. GET與POST區別
1、POST是被設計用來向web服務器上放東西的,而GET是被設計用來從服務器取東西的,GET也能夠向服務器傳送較少的數據,而Get之所以也能傳送數據,只是用來設計告訴服務器,你到底需要什麼樣的數據.POST的信息作爲HTTP 請求的內容,而GET是在HTTP 頭部傳輸的;
2、POST與GET在HTTP 中傳送的方式不同,GET的參數是在HTTP 的頭部傳送的,而Post的數據則是在HTTP 請求的內容裏傳送;
3、POST傳輸數據時,不需要在URL中顯示出來,而GET方法要在URL中顯示;
4、GET方法由於受到URL長度的限制,只能傳遞大約1024字節;POST傳輸的數據量大,可以達到2M

---------------

四. Cookies技術
Cookies現在經常被大家提到,那麼到底什麼是Cookies,它有什麼作用 呢?
Cookies是一種能夠讓網站服務器把少量數據儲存到客戶端的硬盤或內存,或是從客戶端的硬盤讀取數據的一種技術。Cookies是當你瀏覽某網站 時,由Web服務器置於你硬盤上的一個非常小的文本文件,它可以記錄你的用戶ID、密碼、瀏覽過的網頁、停留的時間等信息。

當你再次來到該網站時,網站通過讀取Cookies,得知你的相關信息,就可以做出相應的動作,如在頁面顯示歡迎你的標語,或者讓你不用輸入ID、密碼就直接登錄等等。
從本質上講,它可以看作是你的身份證。但Cookies不能作爲代碼執行,也不會傳送病毒,且爲你所專有,並只能由提供它的服務器來讀取。
保存的信息片斷以“名/值”對(name-value pairs)的形式儲存,一個“名/值”對僅僅是一條命名的數據。
一個網站只能取得它放在你的電腦中的信息,它無法從其它的Cookies文件中取得信息,也無法得到你的電腦上的其它任何東西。
Cookies中的內容大多數經過了加密處理,因此一般用戶看來只是一些毫無意義的字母數字組合,只有服務器的CGI處理程序才知道它們真正的含義。

------------------

五. urllib2
HTTP的訪問過程就是一來一回的. python提供的urllib2很方便發起訪問請求:
* urllib2.urlopen(url) url爲完整的URL
* urllib2.urlopen(request) request爲urllib2.Request類實例

1. 請求的header段處理
request = urllib2.Request(url, headers) # headers就是字典實例
retval = urllib2.urlopen(request) # 請求將被發出去

2. post的數據處理
方法1: 
retval = urllib2.urlopen(url=' http://www.google.com' , data=' person=jessinio&gender=male' ) #這樣一個post請求就被發出去了.
方法2:
request = urllib2.Request(url, data=' person=jessinio&gender=male' ) #指定request實例擁有的data字符串
retval = urllib2.urlopen(request) # 請求將被發出去

常常在平時出現這樣的問題: 請求一個html文件, 但返回的不是文本數據. 比如gzip. 那就需要處理一次

-----------------------

五. urllib2的使用
python發送GET/POST可能涉及的lib: urllib, urllib2, cookielib ;
1.最基本的抓站
import urllib2
content = urllib2.urlopen(' http://XXXX' ).read()

2. 代理處理
import urllib2
proxy_support = urllib2.ProxyHandler({' http' :' http://XX.XX.XX.XX:XXXX' })
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
content = urllib2.urlopen(' http://XXXX' ).read()

3. cookie的處理
import urllib2, cookielib
#cj = cookielib.CookieJar() 
cj = cookielib.LWPCookieJar() 
cookie_support = urllib2.HTTPCookieProcessor(cj)
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
content = urllib2.urlopen(' http://XXXX' ).read()
cj.save("cookie.file")

如果想同時用代理和cookie,那就加入proxy_support然後opener改爲
opener = urllib2.build_opener(proxy_support, cookie_support, urllib2.HTTPHandler)

4. GET請求數據: 使用GET在百度搜索引擎上查詢, 在百度的搜索條中隨便輸入一些內容,演示如何生成GET串,並進行請求. 
import urllib, urllib2
#http://www.baidu.com/s?wd=python&rsv_bp=0&inputT=1540
url = "http://www.baidu.com/s"
search = [('wd', 'python' ),('rsv_bp', '0' ),('inputT', '1540' )]
url_String = url + "?" + urllib.urlencode(search)

req = urllib2.Request(url_String)
fd = urllib2.urlopen(req)
print fd.read()

#把查詢的關鍵字與及各種參數, 使用urllib.urlencode()進行組合, 最終作爲一個完整的URL傳遞給urllib2.Request
#GET只是一個請求過程, 向web服務器發送需要請求的參數, 服務器返回結果

5. POST提交form數據:
1.編碼還是使用urlencode
2.不必要使用字符串連接
3.而使用urlopen的data參數

HTML表單(Form)是HTML的一個重要部分,主要用於採集和提交用戶輸入的信息, 如世紀佳緣的登錄表單, 登錄網址是:http://login.jiayuan.com/
<form name="login" id="login" method="post" action="/dologin.php?pre_url=http://www.jiayuan.com/usercp" target="login_run">
<input name="name" id="login_email" type="text">
<input name="password" id="login_password" type="password">
<input type="submit" value="提交">
</form>

1. form 的method是 post
2. form 的action是 /dologin.php?pre_url=http://www.jiayuan.com/usercp
3. form 的選項有: name, password

知道了上面的數據以後, 就可以提交這個form數據了:
import urllib, urllib2, cookielib
url = 'http://login.jiayuan.com/'
action = 'dologin.php?pre_url=http://www.jiayuan.com/usercp'
login_url = url + action

login_Data = {"name":"[email protected]", "password":"xxx"}
post_Data = urllib.urlencode(login_Data)

cj = cookielib.LWPCookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
urllib2.install_opener(opener)

req = urllib2.Request(login_url, post_Data)
urllib2.urlopen(req).read() 或者 urllib2.urlopen("http://www.jiayuan.com/usercp").read()
cj.save('cookie.bak')

-------------------------

1. urllib2 顯然是比 urllib 高級一點的模塊,裏面包括瞭如何使用 Cookies
2. 在 urllib2 中,每個客戶端可以用一個 opener 來抽象,每個 opener 又可以增加多個 handler 來增強其功能。 
3. 在構造 opener 時指定了 HTTPCookieProcessor 做爲 handler,因此這個 handler 支持 Cookie
4. 使用 install_opener 後,調用 urlopen 時會使用這個 opener
5. 如果不需要保存 Cookie,cj 這個參數可以省略, 即不需要使用cj.save("cookie.bak")來保存
6. login_Data 存放的就是登錄所需要的信息,需要使用urllib.urlencode()編碼, 在登錄的時候把這個信息傳遞過去就行了


6. 僞裝成瀏覽器訪問
某些網站反感爬蟲的到訪,於是對爬蟲一律拒絕請求 這時候我們需要僞裝成瀏覽器,這可以通過修改http包中的header來實現: 
postdata=urllib.urlencode({ 'username':' XXXXX', 
'password':' XXXXX', 
'continueURI' :' http://www.verycd.com/', 
'login_submit' :'登錄'})

headers = {'User-Agent':'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
req = urllib2.Request(url = 'http://secure.verycd.com/signin/*/http://www.verycd.com/', data = postdata, headers = headers)


7. 盜鏈
爲什麼會產生盜鏈?
一般瀏覽有一個重要的現象就是一個完整的頁面並不是一次全部傳送到客戶端的。
如果請求的是一個帶有許多圖片和其它信息的頁面,那麼最先的一個Http 請求被傳送回來的是這個頁面的文本,然後通過客戶端的瀏覽器對這段文本的解釋執行,發現其中還有圖片,那麼客戶端的瀏覽器會再發送一條Http請求,當這個請求被處理後那麼這個圖片文件會被傳送到客戶端,然後瀏覽器回將圖片安放到頁面的正確位置,就這樣一個完整的頁面也許要經過發送多條Http請求才能夠被完整的顯示。
基於這樣的機制,就會產生一個問題,那就是盜鏈問題:就是一個網站中如果沒有起頁面中所說的信息,例如圖片信息,那麼它完全可以將這個圖片的連接到別的網站。這樣沒有任何資源的網站利用了別的網站的資源來展示給瀏覽者,提高了自己的訪問量,而大部分瀏覽者又不會很容易地發現,這樣顯然,對於那個被利用了資源的網站是不公平的。一些不良網站爲了不增加成本而擴充自己站點內容,經常盜用其他網站的鏈接。一方面損害了原網站的合法利益,另一方面又加重了服務器的負擔。
網站遇到最多的是兩類盜鏈,一是圖片盜鏈,二是文件盜鏈

反盜鏈的解決方案
其實通過WEB服務器的URL過濾技術,這個傷腦筋的問題會很容易得到解決。
如果WEB服務器用的是APACHE的話,那麼使用APACHE自帶的Url Rewrite功能可以很輕鬆地防止各種盜鏈,其原理是檢查REFER,如果REFER的信息來自其他網站則禁止訪問所需要的資源

反反盜鏈
如上,某些站點有所謂的反盜鏈設置,其實說穿了很簡單,就是檢查你發送請求的header裏面,referer站點是不是他自己,所以我們只需要像瀏覽器僞裝一樣,把headers的referer改成該網站即可,以黑幕著稱地cnbeta爲例:
headers = {'Referer':'http://www.cnbeta.com/articles'}
headers 是一個dict數據結構,你可以放入任何想要的header,來做一些僞裝。例如,有些自作聰明的網站總喜歡窺人隱私,別人通過代理訪問,他偏偏要讀取header中的X-Forwarded-For來看看人家的真實IP,沒話說,那就直接把X-Forwarde-For改了吧,可以改成隨便什麼好玩的東東來欺負欺負他..


8. 編碼
要解決所有編碼問題,要明白幾個事:
1.python內部用的是unicode.
2.不管你當前是神馬編碼,都先使用decode轉換成unicode
3.再轉爲另外的可讀編碼,一般我們是用系統當前編碼爲準

decode的作用是將其他編碼的字符串轉換成unicode編碼,如str1.decode('gb2312'),表示將gb2312編碼的字符串str1轉換成unicode編碼
encode的作用是將unicode編碼轉換成其他編碼的字符串,如str2.encode('gb2312'),表示將unicode編碼的字符串str2轉換成gb2312編碼
因此,轉碼的時候一定要先搞明白,字符串str是什麼編碼,然後decode成unicode,然後再encode成其他編碼

在用Python抓取網頁時,由於不同網站所採用的編碼不同,使用decode時先知道該網頁所採用的編碼,也可以用python來獲得:
req=urllib2.Request("http://www.baidu.com/")
fd=urllib2.urlopen(req)
html = fd.read()

print fd.headers['Content-Type' ] #取得網頁所採用的編碼, 百度的是gbk,其他的一般網站比如google就是utf8的
syscode = sys.getfilesystemencoding() #取得當前系統編碼
print html.decode('gbk').encode(syscode) #第一遍把utf-8decode 成unicode編碼,再encode到系統編碼 顯示出來,如果有特殊需要,可以輸出想要的編碼



s.decode('gbk', 'ignore').encode('utf-8')
因爲decode的函數原型是decode([encoding], [errors=' strict' ]),可以用第二個參數控制錯誤處理的策略,默認的參數就是strict,代表遇到非法字符時拋出異常;
如果設置爲ignore,則會忽略非法字符;
如果設置爲replace,則會用?取代非法字符;
如果設置爲xmlcharrefreplace,則使用XML的字符引用。


----------------------------

六. pycurl使用
Pycurl包是一個libcurl的Python接口,它是由C語言編寫的。與urllib相比,它的速度要快很多
Libcurl 是一個支持FTP, FTPS, HTTP, HTTPS, GOPHER, TELNET, DICT, FILE 和 LDAP的客戶端URL傳輸庫.libcurl也支持HTTPS認證,HTTP POST,HTTP PUT,FTP上傳,代理,Cookies,基本身份驗證,FTP文件斷點繼傳,HTTP代理通道等等。

1. 寫數據到文件
fp = open("tmp.txt", "wb")
curl = pycurl.Curl()
curl.setopt(pycurl.URL, url)
curl.setopt(pycurl.FOLLOWLOCATION, 1)
curl.setopt(pycurl.MAXREDIRS, 5) #最大重定向數
curl.setopt(pycurl.CONNECTTIMEOUT, 30) #設置超時
curl.setopt(pycurl.TIMEOUT, 300)
curl.setopt(pycurl.HEADER, 1) #數據是否包含頭信息
curl.setopt(pycurl.NOSIGNAL, 1) #解決多線程時, pycurl會崩潰
curl.setopt(pycurl.WRITEDATA, fb) #使用pycurl.WRITEDATA

curl.perform()
http_code = curl.getinfo(curl.HTTP_CODE)

2. 寫數據到StringIO
text = StringIO.StringIO()
curl = pycurl.Curl()
curl.setopt(pycurl.URL, url)
curl.setopt(pycurl.FOLLOWLOCATION, 1)
curl.setopt(pycurl.MAXREDIRS, 5)
curl.setopt(pycurl.CONNECTTIMEOUT, 30)
curl.setopt(pycurl.TIMEOUT, 300)
curl.setopt(pycurl.HEADER, 1)
curl.setopt(pycurl.WRITEFUNCTION, text.write) #使用pycurl.WRITEFUNCTION

curl.perform()
html=text.getvalue()

3. pycurl 的一些響應信息:
pycurl.NAMELOOKUP_TIME 域名解析時間
pycurl.CONNECT_TIME 遠程服務器連接時間
pycurl.PRETRANSFER_TIME 連接上後到開始傳輸時的時間
pycurl.STARTTRANSFER_TIME 接收到第一個字節的時間
pycurl.TOTAL_TIME 上一請求總的時間
pycurl.REDIRECT_TIME 如果存在轉向的話,花費的時間

pycurl.EFFECTIVE_URL
pycurl.HTTP_CODE HTTP 響應代碼
pycurl.REDIRECT_COUNT 重定向的次數
pycurl.SIZE_UPLOAD 上傳的數據大小
pycurl.SIZE_DOWNLOAD 下載的數據大小
pycurl.SPEED_UPLOAD 上傳速度
pycurl.HEADER_SIZE 頭部大小
pycurl.REQUEST_SIZE 請求大小
pycurl.CONTENT_LENGTH_DOWNLOAD 下載內容長度
pycurl.CONTENT_LENGTH_UPLOAD 上傳內容長度
pycurl.CONTENT_TYPE 內容的類型
pycurl.RESPONSE_CODE 響應代碼
pycurl.SPEED_DOWNLOAD 下載速度
pycurl.SSL_VERIFYRESULT
pycurl.INFO_FILETIME 文件的時間信息

pycurl.HTTP_CONNECTCODE HTTP 連接代碼
pycurl.HTTPAUTH_AVAIL
pycurl.PROXYAUTH_AVAIL
pycurl.OS_ERRNO
pycurl.NUM_CONNECTS
pycurl.SSL_ENGINES
pycurl.INFO_COOKIELIST
pycurl.LASTSOCKET
pycurl.FTP_ENTRY_PATH 

----------------------------

七. 解析網頁
從網頁上自動獲取大量信息,是非常必要的。比如可以讓一個腳本監視許多頁面數據的更新,同時據此進行數據分析,形成分析報告。
抓取了網頁之後,對HTML的解釋是個大問題,一般我們會用這幾種:
1. SGMLParser
2. HTMLParser
3. BeautifulSoup
4. lxml

當然,還有其它的,但最常用的是前三種, 前兩種,經過對比,覺得SGMLParser更好,一來,在Dive into Python這本入門文檔裏面以它爲例子,二來,HTMLParser有不少BUG,比如對中文支持不好、對HTML格式要求嚴格等。我就是因爲第二個原因,在使用中它不斷拋出異常,終於受不了了才使用的SGMLParser, 例如: 分析一個網頁中特定的表格, 並提取相應的內容:
data = '''
<table class="table-list" cellpadding="0" cellspacing="0" border="0">
<tr class="own">
<td class="first"> <a href="http://www.baidu.com" target="_blank"><em>百度</em></a> </td>
<td class="second"><a href="http://news.baidu.com" target="_blank"><em>新聞</em></a></td>
</tr>
<tr class="own stripe">
<td class="first"> <a href="http://www.sina.com" target="_blank"><em>新浪</em></a> </td>
<td class="second"><a href="http://news.sina.com" target="_blank"><em>新聞</em></a></td>
</tr>
</table
'''
#1. 需要定位到class="table-list" 的這個table
#2. 需要提取這個table的文本數據,以及對應的href 
from sgmllib import SGMLParser

class table_parser(SGMLParser):
is_table_list = 0
is_td_second = 0

def reset(self):
SGMLParser.reset(self)

def start_table(self, attrs):
for id, value in attrs:
if id == "class" and value == "table-list":
self.is_table_list = 1
def end_table(self):
self.is_table_list = 0

def start_td(self, attrs):
for id, value in attrs:
if id == "class" and value == "second":
self.is_td_second = 1
def end_td(self):
self.is_td_second = 0

def handle_data(self, text):
if self.is_table_list == 1 and self.is_td_second == 1:
print text

def start_a(self, attrs):
if self.is_td_second == 1:
for id, value in attrs:
if id == "href":
print value

t_parser = table_parser()
t_parser.feed(data)

1. 如果提取數據較爲複雜, 可自己編寫正則表達式來提取數據, 常用的方法是使用前向匹配(?<=)和後向匹配(?=)來匹配區間數據
2. HTMLParser如果碰到含有中文字符的網頁, 直接報錯, 不能正常解析
3. attrs是一個元組列表list(屬性,值), 如: 
<input type="hidden" name="NXX" id="IDXX" value="VXX" />, 那麼它的attrs列表爲 [('type', 'hidden'), ('name', 'NXX'), ('id', 'IDXX'), ('value', 'VXX')] 
4. reset 由 SGMLParser 的 __init__ 方法來調用,也可以在創建一個分析器實例時手工來調用。所以如果您需要做初始化,在 reset 中去做,而不要在 __init__ 中做。這樣當某人重用一個分析器實例時,可以正確地重新初始化
5. 只要找到一個 <a> 標記,start_a 就會由 SGMLParser 進行調用。這個標記可以包含一個 href 屬性,或者包含其它的屬性,如name或title



通過Python所帶的urlparse模塊,我們能夠輕鬆地把URL分解成元件,之後,還能將這些元件重新組裝成一個URL
URL包括 <scheme>://<netloc>/<path>;<params>?<query>#<fragment>6方面信息
urllib2更流行一些。對於簡單的下載任務,urllib比較好。如果你需要HTTP驗證或cookies,或你想寫一些擴展去處理你自己的協議的話,那麼urllib2是正確的選擇。


>>> data = '麗江'
>>> print data
麗江
>>> data
'\xe4\xb8\xbd\xe6\xb1\x9f'
>>> urllib.quote (data)
'%E4%B8%BD%E6%B1%9F'
那我們想轉回去呢?
>>> urllib.unquote('%E4%B8%BD%E6%B1%9F')
'\xe4\xb8\xbd\xe6\xb1\x9f'
>>> print urllib.unquote ('%E4%B8%BD%E6%B1%9F')
麗江


細心的同學會發現貼吧url中出現的是%C0%F6%BD%AD,而非'%E4%B8%BD%E6%B1%9F',其實是編碼問題。百度的是gbk,其他的一般網站比如google就是utf8的。所以可以用下列語句實現。
>>> import sys,urllib
>>> s = '麗江'
>>> urllib.quote(s.decode(sys.stdin.encoding).encode('gbk'))
'%C0%F6%BD%AD'
>>> urllib.quote(s.decode(sys.stdin.encoding).encode('utf8'))
'%E4%B8%BD%E6%B1%9F'

用python下載有兩種方法,使用urllib,urllib2兩個類
1.使用urllib的urlretrieve方法:
import urllib
filename="http://122.72.25.73/icache/bai-show.com/fileupload/music/634107480100781250.mp3"
urllib.urlretrieve(filename,r"urllib.mp3")

2.使用urllib2
import urllib2
url="http://122.72.25.73/icache/bai-show.com/fileupload/music/634107480100781250.mp3"
res=urllib2.urlopen(url)
data=res.read()
open(r"urllib2.mp3","wb").write(data)
發佈了6 篇原創文章 · 獲贊 31 · 訪問量 45萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章