摘要:本文將使用Python3.4爬網頁、爬圖片、自動登陸。並對HTTP協議作了一個簡單的介紹。在進行爬蟲以前,先簡單來進行一個HTTP協議的講解,這樣下面再來進行爬蟲就是理解更加清楚。html
HTTP是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫。它的發展是萬維網協會(World Wide Web Consortium)和Internet工做小組IETF(Internet Engineering Task Force)合做的結果,(他們)最終發佈了一系列的RFC,RFC 1945定義了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC 2616定義了今天廣泛使用的一個版本——HTTP 1.1。
HTTP協議(HyperText Transfer Protocol,超文本傳輸協議)是用於從WWW服務器傳輸超文本到本地瀏覽器的傳送協議。它可使瀏覽器更加高效,使網絡傳輸減小。它不只保證計算機正確快速地傳輸超文本文檔,還肯定傳輸文檔中的哪一部分,以及哪部份內容首先顯示(如文本先於圖形)等。java
HTTP的請求響應模型python
HTTP協議永遠都是客戶端發起請求,服務器回送響應。見下圖:web
這樣就限制了使用HTTP協議,沒法實如今客戶端沒有發起請求的時候,服務器將消息推送給客戶端。正則表達式
HTTP協議是一個無狀態的協議,同一個客戶端的此次請求和上次請求是沒有對應關係。編程
工做流程瀏覽器
一次HTTP操做稱爲一個事務,其工做過程可分爲四步:服務器
1)首先客戶機與服務器須要創建鏈接。只要單擊某個超級連接,HTTP的工做開始。cookie
2)創建鏈接後,客戶機發送一個請求給服務器,請求方式的格式爲:統一資源標識符(URL)、協議版本號,後邊是MIME信息包括請求修飾符、客戶機信息和可能的內容。網絡
3)服務器接到請求後,給予相應的響應信息,其格式爲一個狀態行,包括信息的協議版本號、一個成功或錯誤的代碼,後邊是MIME信息包括服務器信息、實體信息和可能的內容。
4)客戶端接收服務器所返回的信息經過瀏覽器顯示在用戶的顯示屏上,而後客戶機與服務器斷開鏈接。
若是在以上過程當中的某一步出現錯誤,那麼產生錯誤的信息將返回到客戶端,有顯示屏輸出。對於用戶來講,這些過程是由HTTP本身完成的,用戶只要用鼠標點擊,等待信息顯示就能夠了
請求報頭
請求報頭容許客戶端向服務器端傳遞請求的附加信息以及客戶端自身的信息。
經常使用的請求報頭
Accept
Accept請求報頭域用於指定客戶端接受哪些類型的信息。eg:Accept:image/gif,代表客戶端但願接受GIF圖象格式的資源;Accept:text/html,代表客戶端但願接受html文本。
Accept-Charset
Accept-Charset請求報頭域用於指定客戶端接受的字符集。eg:Accept-Charset:iso-8859-1,gb2312.若是在請求消息中沒有設置這個域,缺省是任何字符集均可以接受。
Accept-Encoding
Accept-Encoding請求報頭域相似於Accept,可是它是用於指定可接受的內容編碼。eg:Accept-Encoding:gzip.deflate.若是請求消息中沒有設置這個域服務器假定客戶端對各類內容編碼均可以接受。
Accept-Language
Accept-Language請求報頭域相似於Accept,可是它是用於指定一種天然語言。eg:Accept-Language:zh-cn.若是請求消息中沒有設置這個報頭域,服務器假定客戶端對各類語言均可以接受。
Authorization
Authorization請求報頭域主要用於證實客戶端有權查看某個資源。當瀏覽器訪問一個頁面時,若是收到服務器的響應代碼爲401(未受權),能夠發送一個包含Authorization請求報頭域的請求,要求服務器對其進行驗證。
Host(發送請求時,該報頭域是必需的)
Host請求報頭域主要用於指定被請求資源的Internet主機和端口號,它一般從HTTP URL中提取出來的,eg:
咱們在瀏覽器中輸入:https://www.guet.edu.cn/index.html
瀏覽器發送的請求消息中,就會包含Host請求報頭域,以下:
Host:www.guet.edu.cn
此處使用缺省端口號80,若指定了端口號,則變成:Host:www.guet.edu.cn:指定端口號
User-Agent
咱們上網登錄論壇的時候,每每會看到一些歡迎信息,其中列出了你的操做系統的名稱和版本,你所使用的瀏覽器的名稱和版本,這每每讓不少人感到很神奇,實際上,服務器應用程序就是從User-Agent這個請求報頭域中獲取到這些信息。User-Agent請求報頭域容許客戶端將它的操做系統、瀏覽器和其它屬性告訴服務器。不過,這個報頭域不是必需的,若是咱們本身編寫一個瀏覽器,不使用User-Agent請求報頭域,那麼服務器端就沒法得知咱們的信息了。
請求報頭舉例:
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)
1
|
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)
|
響應報頭
響應報頭容許服務器傳遞不能放在狀態行中的附加響應信息,以及關於服務器的信息和對Request-URI所標識的資源進行下一步訪問的信息。
經常使用的響應報頭
Location
Location響應報頭域用於重定向接受者到一個新的位置。Location響應報頭域經常使用在更換域名的時候。
Server
Server響應報頭域包含了服務器用來處理請求的軟件信息。與User-Agent請求報頭域是相對應的。下面是
Server響應報頭域的一個例子:
Server:Apache-Coyote/1.1
WWW-Authenticate
WWW-Authenticate響應報頭域必須被包含在401(未受權的)響應消息中,客戶端收到401響應消息時候,併發送Authorization報頭域請求服務器對其進行驗證時,服務端響應報頭就包含該報頭域。
eg:WWW-Authenticate:Basic realm=Basic Auth Test! //能夠看出服務器對請求資源採用的是基本驗證機制。
一、第一個示例,咱們要來進行簡單的爬蟲來爬別人的網頁
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#python3.
4
爬蟲教程
#一個簡單的示例爬蟲
#林炳文Evankaka(博客:https:
//blog.csdn.net/evankaka/)
import
urllib.request
url = https:
//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生成 的請求報頭,不清楚看下面:
很簡單的一個報頭,而後再來看看響應回來的html
這裏響應回來的就是咱們上面在python的idle中打印出來的網頁了!
二、假裝成瀏覽器來爬網頁
有些網頁,好比登陸的。若是你不是從瀏覽器發起的起求,這就不會給你響應,這時咱們就須要本身來寫報頭。而後再發給網頁的服務器,這時它就覺得你就是一個正常的瀏覽器。從而就能夠爬了!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#python3.
4
爬蟲教程
#一個簡單的示例爬蟲
#林炳文Evankaka(博客:https:
//blog.csdn.net/evankaka/)
import
urllib.request
weburl = https:
//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())
|
來看看請求報頭,就是和咱們設置的一個樣。
返回的是同樣的:
再來一個複雜一點的請求報頭:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#python3.
4
爬蟲教程
#一個簡單的示例爬蟲
#林炳文Evankaka(博客:https:
//blog.csdn.net/evankaka/)
import
urllib.request
weburl = https:
//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())
|
看看生成 的結果:
返回仍是:
三、爬取網站上的圖片
前面咱們能夠爬網頁了,下一步咱們就能夠批量的自動下載該網頁上的各類數據了~,好比,這裏我要下載該網頁上的全部圖片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#python3.
4
爬蟲教程
#爬取網站上的圖片
#林炳文Evankaka(博客:https:
//blog.csdn.net/evankaka/)
import
urllib.request
import
socket
import
re
import
sys
import
os
targetDir = rD:PythonWorkPlaceload #文件保存路徑
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 = https:
//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(
'失敗'
) #異常拋出
|
這是正在運行的過程:
打開電腦上對應的文件夾,而後來看看圖片,這裏只是一部分哦!!。。
真實的網頁上的圖片
四、保存爬取回來的報文
1
2
3
4
5
6
7
8
9
10
11
12
|
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)
|
好比:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#python3.
4
爬蟲教程
#一個簡單的示例爬蟲
#林炳文Evankaka(博客:https:
//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 = https:
//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代碼編寫:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
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處理器,它負責從服務器下載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 =
'https://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 =
'ling20081005@126.com'
password =
'christmas258@'
#構造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())
|
來看看結果:
這時運行返回的
發送出去的請求頭
接收回來 的報頭
返回的數據是什麼意思呢:
很簡單, 咱們轉碼下: