轉載請註明出處http://blog.csdn.net/evankaka
html
摘要:本文將使用Python3.4爬網頁、爬圖片、本身主動登陸。並對HTTP協議作了一個簡單的介紹。在進行爬蟲以前,先簡單來進行一個HTTP協議的解說。這樣如下再來進行爬蟲就是理解更加清楚。java
HTTP是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫。python
它的發展是萬維網協會(World Wide Web Consortium)和Internet工做小組IETF(Internet Engineering Task Force)合做的結果,(他們)終於公佈了一系列的RFC。RFC 1945定義了HTTP/1.0版本號。當中最著名的就是RFC 2616。RFC 2616定義了今天廣泛使用的一個版本號——HTTP 1.1。web
HTTP協議(HyperText Transfer Protocol。超文本傳輸協議)是用於從WWWserver傳輸超文本到本地瀏覽器的傳送協議。它可以使瀏覽器更加高效,使網絡傳輸下降。編程
它不只保證計算機正確高速地傳輸超文本文檔。還肯定傳輸文檔中的哪一部分。以及哪部份內容首先顯示(如文本先於圖形)等。
瀏覽器
HTTP的請求響應模型cookie
HTTP協議永遠都是client發起請求,server回送響應。見下圖:網絡
這樣就限制了使用HTTP協議,沒法實現在client沒有發起請求的時候。server將消息推送給client。
HTTP協議是一個無狀態的協議。同一個client的此次請求和上次請求是沒有相應關係。併發
工做流程app
一次HTTP操做稱爲一個事務。其工做過程可分爲四步:
1)首先客戶機與server需要創建鏈接。僅僅要單擊某個超級連接,HTTP的工做開始。
2)創建鏈接後。客戶機發送一個請求給server。請求方式的格式爲:統一資源標識符(URL)、協議版本號號。後邊是MIME信息包括請求修飾符、客戶機信息和可能的內容。
3)server接到請求後,給予相應的響應信息,其格式爲一個狀態行,包括信息的協議版本號號、一個成功或錯誤的代碼,後邊是MIME信息包括server信息、實體信息和可能的內容。
4)client接收server所返回的信息經過瀏覽器顯示在用戶的顯示屏上,而後客戶機與server斷開鏈接。
假設在以上過程當中的某一步出現錯誤,那麼產生錯誤的信息將返回到client,有顯示屏輸出。
對於用戶來講。這些過程是由HTTP本身完畢的,用戶僅僅要用鼠標點擊,等待信息顯示就可以了
請求報頭
請求報頭贊成client向server端傳遞請求的附加信息以及client自身的信息。
常用的請求報頭
Accept
Accept請求報頭域用於指定client接受哪些類型的信息。eg:Accept:image/gif。代表client但願接受GIF圖象格式的資源。Accept:text/html,代表client但願接受html文本。
Accept-Charset
Accept-Charset請求報頭域用於指定client接受的字符集。eg:Accept-Charset:iso-8859-1,gb2312.假設在請求消息中沒有設置這個域,缺省是不論什麼字符集都可以接受。
Accept-Encoding
Accept-Encoding請求報頭域類似於Accept,但是它是用於指定可接受的內容編碼。eg:Accept-Encoding:gzip.deflate.假設請求消息中沒有設置這個域server假定client對各類內容編碼都可以接受。
Accept-Language
Accept-Language請求報頭域類似於Accept,但是它是用於指定一種天然語言。eg:Accept-Language:zh-cn.假設請求消息中沒有設置這個報頭域,server假定client對各類語言都可以接受。
Authorization
Authorization請求報頭域主要用於證實client有權查看某個資源。當瀏覽器訪問一個頁面時,假設收到server的響應代碼爲401(未受權),可以發送一個包括Authorization請求報頭域的請求,要求server對其進行驗證。
Host(發送請求時,該報頭域是必需的)
Host請求報頭域主要用於指定被請求資源的Internet主機和端口號。它一般從HTTP URL中提取出來的,eg:
咱們在瀏覽器中輸入:http://www.guet.edu.cn/index.html
瀏覽器發送的請求消息中,就會包括Host請求報頭域。例如如下:
Host:www.guet.edu.cn
此處使用缺省端口號80,若指定了端口號,則變成:Host:www.guet.edu.cn:指定端口號
User-Agent
咱們上網登錄論壇的時候,每每會看到一些歡迎信息。當中列出了你的操做系統的名稱和版本號,你所使用的瀏覽器的名稱和版本號,這每每讓很是多人感到很是奇妙,實際上,server應用程序就是從User-Agent這個請求報頭域中獲取到這些信息。User-Agent請求報頭域贊成client將它的操做系統、瀏覽器和其餘屬性告訴server。只是。這個報頭域不必的。假設咱們本身編寫一個瀏覽器。不使用User-Agent請求報頭域。那麼server端就沒法得知咱們的信息了。
請求報頭舉例:
GET /form.html HTTP/1.1 (CRLF)
Accept:image/gif,image/x-xbitmap,image/jpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/* (CRLF)
Accept-Language:zh-cn (CRLF)
Accept-Encoding:gzip,deflate (CRLF)
If-Modified-Since:Wed,05 Jan 2007 11:21:25 GMT (CRLF)
If-None-Match:W/"80b1a4c018f3c41:8317" (CRLF)
User-Agent:Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0) (CRLF)
Host:www.guet.edu.cn (CRLF)
Connection:Keep-Alive (CRLF)
(CRLF)
GET /form.html HTTP/1.1 (CRLF)Accept:image/gif,image/x-xbitmap,image/jpeg,application/x-shockwave-flash,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/* (CRLF)Accept-Language:zh-cn (CRLF)Accept-Encoding:gzip,deflate (CRLF)If-Modified-Since:Wed,05 Jan 2007 11:21:25 GMT (CRLF)If-None-Match:W/"80b1a4c018f3c41:8317" (CRLF)User-Agent:Mozilla/4.0(compatible;MSIE6.0;Windows NT 5.0) (CRLF)Host:www.guet.edu.cn (CRLF)Connection:Keep-Alive (CRLF)(CRLF)
響應報頭
響應報頭贊成server傳遞不能放在狀態行中的附加響應信息。以及關於server的信息和對Request-URI所標識的資源進行下一步訪問的信息。
常用的響應報頭
Location
Location響應報頭域用於重定向接受者到一個新的位置。Location響應報頭域常用在更換域名的時候。
Server
Server響應報頭域包括了server用來處理請求的軟件信息。
與User-Agent請求報頭域是相相應的。如下是
Server響應報頭域的一個樣例:
Server:Apache-Coyote/1.1
WWW-Authenticate
WWW-Authenticate響應報頭域必須被包括在401(未受權的)響應消息中,client收到401響應消息時候,併發送Authorization報頭域請求server對其進行驗證時,服務端響應報頭就包括該報頭域。
eg:WWW-Authenticate:Basic realm="Basic Auth Test!" //可以看出server對請求資源採用的是基本驗證機制。
一、第一個演示樣例,咱們要來進行簡單的爬蟲來爬別人的網頁
#python3.4 爬蟲教程 #一個簡單的演示樣例爬蟲 #林炳文Evankaka(博客:http://blog.csdn.net/evankaka/) import urllib.request url = "http://www.douban.com/" webPage=urllib.request.urlopen(url) data = webPage.read() data = data.decode('UTF-8') print(data) print(type(webPage)) print(webPage.geturl()) print(webPage.info()) print(webPage.getcode())這是爬回來的網頁輸出:
這中間究竟發生了什麼事呢?讓咱們打開Fiddler來看看吧:
左邊標紅的就表示咱們本次訪問成功,爲http 200
右邊上方這是python生成 的請求報頭。不清楚看如下:
很是easy的一個報頭。而後再來看看響應回來的html
這裏響應回來的就是咱們上面在python的idle中打印出來的網頁了!
二、假裝成瀏覽器來爬網頁
有些網頁,比方登陸的。假設你不是從瀏覽器發起的起求,這就不會給你響應,這時咱們就需要本身來寫報頭。而後再發給網頁的server,這時它就覺得你就是一個正常的瀏覽器。從而就可以爬了!
#python3.4 爬蟲教程 #一個簡單的演示樣例爬蟲 #林炳文Evankaka(博客:http://blog.csdn.net/evankaka/) import urllib.request weburl = "http://www.douban.com/" webheader = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'} req = urllib.request.Request(url=weburl, headers=webheader) webPage=urllib.request.urlopen(req) data = webPage.read() data = data.decode('UTF-8') print(data) print(type(webPage)) print(webPage.geturl()) print(webPage.info()) print(webPage.getcode())來看看請求報頭,就是和咱們設置的一個樣。
返回的是同樣的:
再來一個複雜一點的請求報頭:
#python3.4 爬蟲教程 #一個簡單的演示樣例爬蟲 #林炳文Evankaka(博客:http://blog.csdn.net/evankaka/) import urllib.request weburl = "http://www.douban.com/" webheader1 = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'} webheader2 = { 'Connection': 'Keep-Alive', 'Accept': 'text/html, application/xhtml+xml, */*', 'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko', #'Accept-Encoding': 'gzip, deflate', 'Host': 'www.douban.com', 'DNT': '1' } req = urllib.request.Request(url=weburl, headers=webheader2) webPage=urllib.request.urlopen(req) data = webPage.read() data = data.decode('UTF-8') print(data) print(type(webPage)) print(webPage.geturl()) print(webPage.info()) print(webPage.getcode())
看看生成 的結果:
返回仍是:
三、爬取站點上的圖片
前面咱們可以爬網頁了,下一步咱們就可以批量的本身主動下載該網頁上的各類數據了~,比方。這裏我要下載該網頁上的所有圖片
#python3.4 爬蟲教程 #爬取站點上的圖片 #林炳文Evankaka(博客:http://blog.csdn.net/evankaka/) import urllib.request import socket import re import sys import os targetDir = r"D:\PythonWorkPlace\load" #文件保存路徑 def destFile(path): if not os.path.isdir(targetDir): os.mkdir(targetDir) pos = path.rindex('/') t = os.path.join(targetDir, path[pos+1:]) return t if __name__ == "__main__": #程序執行入口 weburl = "http://www.douban.com/" webheaders = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'} req = urllib.request.Request(url=weburl, headers=webheaders) #構造請求報頭 webpage = urllib.request.urlopen(req) #發送請求報頭 contentBytes = webpage.read() for link, t in set(re.findall(r'(http:[^\s]*?這是正在執行的過程:(jpg|png|gif))', str(contentBytes))): #正則表達式查找所有的圖片 print(link) try: urllib.request.urlretrieve(link, destFile(link)) #下載圖片 except: print('失敗') #異常拋出
打開電腦上相應的目錄,而後來看看圖片。這裏僅僅是一部分哦!!
。。
真實的網頁上的圖片
四、保存爬取回來的報文
def saveFile(data): save_path = 'D:\\temp.out' f_obj = open(save_path, 'wb') # wb 表示打開方式 f_obj.write(data) f_obj.close() # 這裏省略爬蟲代碼 # ... # 爬到的數據放到 dat 變量裏 # 將 dat 變量保存到 D 盤下 saveFile(dat)
比方:
#python3.4 爬蟲教程 #一個簡單的演示樣例爬蟲 #林炳文Evankaka(博客:http://blog.csdn.net/evankaka/) import urllib.request def saveFile(data): save_path = 'D:\\temp.out' f_obj = open(save_path, 'wb') # wb 表示打開方式 f_obj.write(data) f_obj.close() weburl = "http://www.douban.com/" webheader1 = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'} webheader2 = { 'Connection': 'Keep-Alive', 'Accept': 'text/html, application/xhtml+xml, */*', 'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko', #'Accept-Encoding': 'gzip, deflate', 'Host': 'www.douban.com', 'DNT': '1' } req = urllib.request.Request(url=weburl, headers=webheader2) webPage=urllib.request.urlopen(req) data = webPage.read() saveFile(data)# 將data變量保存到 D 盤下 data = data.decode('UTF-8') print(data) print(type(webPage)) print(webPage.geturl()) print(webPage.info()) print(webPage.getcode())而後看看D盤:
用NotePad打開:
是對的。網頁已經被爬下來了。
通常狀況下咱們輸入郵箱和密碼後,登陸。
來看看。
這就是提交表單的內容
python3.4代碼編寫:
import gzip import re import http.cookiejar import urllib.request import urllib.parse #解壓函數 def ungzip(data): try: # 嘗試解壓 print('正在解壓.....') data = gzip.decompress(data) print('解壓完畢!') except: print('未經壓縮, 無需解壓') return data #獲取_xsrf def getXSRF(data): cer = re.compile('name=\"_xsrf\" value=\"(.*)\"', flags = 0) strlist = cer.findall(data) return strlist[0] #構造文件頭 def getOpener(head): #設置一個cookie處理器,它負責從server下載cookie到本地。並且在發送請求時帶上本地的cookie cj = http.cookiejar.CookieJar() pro = urllib.request.HTTPCookieProcessor(cj) opener = urllib.request.build_opener(pro) header = [] for key, value in head.items(): elem = (key, value) header.append(elem) opener.addheaders = header return opener #構造header,通常header至少要包括一下兩項。這兩項是從抓到的包裏分析得出的。 header = { 'Connection': 'Keep-Alive', 'Accept': 'text/html, application/xhtml+xml, */*', 'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko', 'Accept-Encoding': 'gzip, deflate', 'Host': 'www.zhihu.com', 'DNT': '1' } url = 'http://www.zhihu.com/' opener = getOpener(header) op = opener.open(url) data = op.read() data = ungzip(data) # 解壓 _xsrf = getXSRF(data.decode()) #post數據接收和處理的頁面(咱們要向這個頁面發送咱們構造的Post數據) url += 'login/email' id = '這裏寫本身的郵箱' password = '這裏寫本身的密碼' #構造Post數據,他也是從抓大的包裏分析得出的。 postDict = { '_xsrf':_xsrf, #特有數據。不一樣站點可能不一樣 'email': id, 'password': password, 'rememberme': 'y' } #需要給Post數據編碼 postData = urllib.parse.urlencode(postDict).encode() op = opener.open(url, postData) data = op.read() data = ungzip(data) print(data.decode())
這時執行返回的
發送出去的請求頭
接收回來 的報頭
返回的數據是什麼意思呢:
很是easy, 咱們轉碼下: