通過屢次嘗試,模擬登陸淘寶終於成功了,實在是不容易,淘寶的登陸加密和驗證太複雜了,煞費苦心,在此寫出來和你們一塊兒分享,但願你們支持。css
1. python模擬登陸淘寶網頁html
2. 獲取登陸用戶的全部訂單詳情python
3. 學會應對出現驗證碼的狀況git
4. 體會一下複雜的模擬登陸機制github
1. 淘寶的密碼用了AES加密算法,最終將密碼轉化爲256位,在POST時,傳輸的是256位長度的密碼。web
2. 淘寶在登陸時必需要輸入驗證碼,在通過幾回嘗試失敗後最終獲取了驗證碼圖片讓用戶手動輸入來驗證。正則表達式
3. 淘寶另外有複雜且天天在變的 ua 加密算法,在程序中咱們須要提早獲取某一 ua 碼纔可進行模擬登陸。算法
4. 在獲取最後的登陸 st 碼時,歷經了屢次請求和正則表達式提取,且 st 碼只可以使用一次。windows
1. 手動到瀏覽器獲取 ua 碼以及 加密後的密碼,只獲取一次便可,一勞永逸。瀏覽器
2. 向登陸界面發送登陸請求,POST 一系列參數,包括 ua 碼以及密碼等等,得到響應,提取驗證碼圖像。
3. 用戶輸入手動驗證碼,從新加入驗證碼數據再次用 POST 方式發出請求,得到響應,提取 J_Htoken。
4. 利用 J_Htoken 向 alipay 發出請求,得到響應,提取 st 碼。
5. 利用 st 碼和用戶名,從新發出登陸請求,得到響應,提取重定向網址,存儲 cookie。
6. 利用 cookie 向其餘我的頁面如訂單頁面發出請求,得到響應,提取訂單詳情。
是否是沒看懂?沒事,下面我將一點點說明本身模擬登陸的過程,但願你們能夠理解。
因爲淘寶的 ua 算法和 aes 密碼加密算法太複雜了,ua 算法在淘寶天天都是在變化的,不過,這個內容你獲取以後一直用便可,通過測試以後沒有問題,一勞永逸。
那麼 ua 和 aes 密碼怎樣獲取呢?
咱們就從瀏覽器裏面直接獲取吧,打開瀏覽器,找到淘寶的登陸界面,按 F12 或者瀏覽器右鍵審查元素。
在這裏我用的是火狐瀏覽器,首先記得在瀏覽器中設置一下顯示持續日誌,要否則頁面跳轉了你就看不到以前抓取的信息了。在這裏截圖以下:
好,那麼接下來咱們就從瀏覽器中獲取 ua 和 aes 密碼
點擊網絡選項卡,這時都是空的,什麼數據也沒有截取。這時你就在網頁上登陸一下試試吧,輸入用戶名啊,密碼啊,有必要時須要輸入驗證碼,點擊登陸。
等跳轉成功後,你就能夠看到好多日誌記錄了,點擊圖中的那一行 login.taobo.com,而後查看參數,你就會發現表單數據了,其中就包括 ua 還有下面的 password2,把這倆複製下來,咱們以後要用到的。這就是咱們須要的 ua 還有 aes 加密後的密碼。
恩,讀到這裏,你應該獲取到了屬於本身的 ua 和 password2 兩個內容。
通過博主本人親自驗證,有時候,在模擬登陸時你並不須要輸入驗證碼,它直接返回的結果就是前面所說的下一步用到的 J_Token,而有時候你則會須要輸入驗證碼,等你手動輸入驗證碼以後,從新請求登陸一次。
博主是邊寫程序邊更新文章的,如今寫完了是否有必要輸入驗證碼的檢驗以及在瀏覽器中呈現驗證碼。
代碼以下
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
__author__
=
'CQC'
# -*- coding:utf-8 -*-
import
urllib
import
urllib2
import
cookielib
import
re
import
webbrowser
#模擬登陸淘寶類
class
Taobao
:
#初始化方法
def
__init__
(
self
)
:
#登陸的URL
self
.
loginURL
=
"https://login.taobao.com/member/login.jhtml"
#代理IP地址,防止本身的IP被封禁
self
.
proxyURL
=
'http://120.193.146.97:843'
#登陸POST數據時發送的頭部信息
self
.
loginHeaders
=
{
'Host'
:
'login.taobao.com'
,
'User-Agent'
:
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0'
,
'Referer'
:
'https://login.taobao.com/member/login.jhtml'
,
'Content-Type'
:
'application/x-www-form-urlencoded'
,
'Connection'
:
'Keep-Alive'
}
#用戶名
self
.
username
=
'cqcre'
#ua字符串,通過淘寶ua算法計算得出,包含了時間戳,瀏覽器,屏幕分辨率,隨機數,鼠標移動,鼠標點擊,其實還有鍵盤輸入記錄,鼠標移動的記錄、點擊的記錄等等的信息
self
.
ua
=
'191UW5TcyMNYQwiAiwTR3tCf0J/QnhEcUpkMmQ=|Um5Ockt0TXdPc011TXVKdyE=|U2xMHDJ+H2QJZwBxX39Rb1d5WXcrSixAJ1kjDVsN|VGhXd1llXGNaYFhkWmJaYl1gV2pIdUtyTXRKfkN4Qn1FeEF6R31TBQ==|VWldfS0TMw8xDjYWKhAwHiUdOA9wCDEVaxgkATdcNU8iDFoM|VmNDbUMV|V2NDbUMV|WGRYeCgGZhtmH2VScVI2UT5fORtmD2gCawwuRSJHZAFsCWMOdVYyVTpbPR99HWAFYVMpUDUFORshHiQdJR0jAT0JPQc/BDoFPgooFDZtVBR5Fn9VOwt2EWhCOVQ4WSJPJFkHXhgoSDVIMRgnHyFqQ3xEezceIRkmahRqFDZLIkUvRiEDaA9qQ3xEezcZORc5bzk=|WWdHFy0TMw8vEy0UIQE0ADgYJBohGjoAOw4uEiwXLAw2DThu9a==|WmBAED5+KnIbdRh1GXgFQSZbGFdrUm1UblZqVGxQa1ZiTGxQcEp1I3U=|W2NDEz19KXENZwJjHkY7Ui9OJQsre09zSWlXY1oMLBExHzERLxsuE0UT|XGZGFjh4LHQdcx5zH34DRyBdHlFtVGtSaFBsUmpWbVBkSmpXd05zTnMlcw==|XWdHFzl5LXUJYwZnGkI/VitKIQ8vEzMKNws3YTc=|XmdaZ0d6WmVFeUB8XGJaYEB4TGxWbk5yTndXa0tyT29Ta0t1QGBeZDI='
#密碼,在這裏不能輸入真實密碼,淘寶對此密碼進行了加密處理,256位,此處爲加密後的密碼
self
.
password2
=
'7511aa68sx629e45de220d29174f1066537a73420ef6dbb5b46f202396703a2d56b0312df8769d886e6ca63d587fdbb99ee73927e8c07d9c88cd02182e1a21edc13fb8e140a4a2a4b5c253bf38484bd0e08199e03eb9bf7b365a5c673c03407d812b91394f0d3c7564042e3f2b11d156aeea37ad6460118914125ab8f8ac466f'
self
.
post
=
post
=
{
'ua'
:
self
.
ua
,
'TPL_checkcode'
:
''
,
'CtrlVersion'
:
'1,0,0,7'
,
'TPL_password'
:
''
,
'TPL_redirect_url'
:
'http://i.taobao.com/my_taobao.htm?nekot=udm8087E1424147022443'
,
'TPL_username'
:
self
.
username
,
'loginsite'
:
'0'
,
'newlogin'
:
'0'
,
'from'
:
'tb'
,
'fc'
:
'default'
,
'style'
:
'default'
,
'css_style'
:
''
,
'tid'
:
'XOR_1_000000000000000000000000000000_625C4720470A0A050976770A'
,
'support'
:
'000001'
,
'loginType'
:
'4'
,
'minititle'
:
''
,
'minipara'
:
''
,
'umto'
:
'NaN'
,
'pstrong'
:
'3'
,
'llnick'
:
''
,
'sign'
:
''
,
'need_sign'
:
''
,
'isIgnore'
:
''
,
'full_redirect'
:
''
,
'popid'
:
''
,
'callback'
:
''
,
'guf'
:
''
,
'not_duplite_str'
:
''
,
'need_user_id'
:
''
,
'poy'
:
''
,
'gvfdcname'
:
'10'
,
'gvfdcre'
:
''
,
'from_encoding '
:
''
,
'sub'
:
''
,
'TPL_password_2'
:
self
.
password2
,
'loginASR'
:
'1'
,
'loginASRSuc'
:
'1'
,
'allp'
:
''
,
'oslanguage'
:
'zh-CN'
,
'sr'
:
'1366*768'
,
'osVer'
:
'windows|6.1'
,
'naviVer'
:
'firefox|35'
}
#將POST的數據進行編碼轉換
self
.
postData
=
urllib
.
urlencode
(
self
.
post
)
#設置代理
self
.
proxy
=
urllib2
.
ProxyHandler
(
{
'http'
:
self
.
proxyURL
}
)
#設置cookie
self
.
cookie
=
cookielib
.
LWPCookieJar
(
)
#設置cookie處理器
self
.
cookieHandler
=
urllib2
.
HTTPCookieProcessor
(
self
.
cookie
)
#設置登陸時用到的opener,它的open方法至關於urllib2.urlopen
self
.
opener
=
urllib2
.
build_opener
(
self
.
cookieHandler
,
self
.
proxy
,
urllib2
.
HTTPHandler
)
#獲得是否須要輸入驗證碼,此次請求的相應有時會不一樣,有時須要驗證有時不須要
def
needIdenCode
(
self
)
:
#第一次登陸獲取驗證碼嘗試,構建request
request
=
urllib2
.
Request
(
self
.
loginURL
,
self
.
postData
,
self
.
loginHeaders
)
#獲得第一次登陸嘗試的相應
response
=
self
.
opener
.
open
(
request
)
#獲取其中的內容
content
=
response
.
read
(
)
.
decode
(
'gbk'
)
#獲取狀態嗎
status
=
response
.
getcode
(
)
#狀態碼爲200,獲取成功
if
status
==
200
:
print
u
"獲取請求成功"
#\u8bf7\u8f93\u5165\u9a8c\u8bc1\u7801這六個字是請輸入驗證碼的utf-8編碼
pattern
=
re
.
compile
(
u
'\u8bf7\u8f93\u5165\u9a8c\u8bc1\u7801'
,
re
.
S
)
result
=
re
.
search
(
pattern
,
content
)
#若是找到該字符,表明須要輸入驗證碼
if
result
:
print
u
"這次安全驗證異常,您須要輸入驗證碼"
return
content
#不然不須要
else
:
print
u
"這次安全驗證經過,您此次不須要輸入驗證碼"
return
False
else
:
print
u
"獲取請求失敗"
#獲得驗證碼圖片
def
getIdenCode
(
self
,
page
)
:
#獲得驗證碼的圖片
pattern
=
re
.
compile
(
'<img id="J_StandardCode_m.*?data-src="(.*?)"'
,
re
.
S
)
#匹配的結果
matchResult
=
re
.
search
(
pattern
,
page
)
#已經匹配獲得內容,而且驗證碼圖片連接不爲空
if
matchResult
and
matchResult
.
group
(
1
)
:
print
matchResult
.
group
(
1
)
return
matchResult
.
group
(
1
)
else
:
print
u
"沒有找到驗證碼內容"
return
False
#程序運行主幹
def
main
(
self
)
:
#是否須要驗證碼,是則獲得頁面內容,不是則返回False
needResult
=
self
.
needIdenCode
(
)
if
not
needResult
==
False
:
print
u
"您須要手動輸入驗證碼"
idenCode
=
self
.
getIdenCode
(
needResult
)
#獲得了驗證碼的連接
if
not
idenCode
==
False
:
print
u
"驗證碼獲取成功"
print
u
"請在瀏覽器中輸入您看到的驗證碼"
webbrowser
.
open_new_tab
(
idenCode
)
#驗證碼連接爲空,無效驗證碼
else
:
print
u
"驗證碼獲取失敗,請重試"
else
:
print
u
"不須要輸入驗證碼"
taobao
=
Taobao
(
)
taobao
.
main
(
)
|
恩,請把裏面的 ua 和 password2 還有用戶名換成本身的進行嘗試,用個人可能會產生錯誤的。
運行結果
而後會蹦出瀏覽器,顯示了驗證碼的內容,這個須要你來手動輸入。
在這裏有小夥伴向我反映有這麼個錯誤
通過查證,居然是版本問題,博主本人用的是 2.7.7,而小夥伴用的是 2.7.9。後來換成 2.7.7 就行了…,我也是醉了,但願有相同錯誤的小夥伴,能夠嘗試換一下版本…
好啦,運行時會彈出瀏覽器,如圖
那麼,咱們如今須要手動輸入驗證碼,從新向登陸界面發出登陸請求,以前的post數據內容加入驗證碼這一項,從新請求一次,若是請求成功,則會返回 下一步咱們須要的 J_HToken,若是驗證碼輸入錯誤,則會返回驗證碼輸入錯誤的選項。好,下面,我已經寫到了獲取J_HToken的進度,代碼以下,如今運行程序,會 蹦出瀏覽器,而後提示你輸入驗證碼,用戶手動輸入以後,則會返回一個頁面,咱們提取出 J_Htoken便可。
注意,到如今爲止,你尚未登陸成功,只是獲取到了J_HToken的值。
目前寫到的代碼以下
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
__author__
=
'CQC'
# -*- coding:utf-8 -*-
import
urllib
import
urllib2
import
cookielib
import
re
import
webbrowser
#模擬登陸淘寶類
class
Taobao
:
#初始化方法
def
__init__
(
self
)
:
#登陸的URL
self
.
loginURL
=
"https://login.taobao.com/member/login.jhtml"
#代理IP地址,防止本身的IP被封禁
self
.
proxyURL
=
'http://120.193.146.97:843'
#登陸POST數據時發送的頭部信息
self
.
loginHeaders
=
{
'Host'
:
'login.taobao.com'
,
'User-Agent'
:
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0'
,
'Referer'
:
'https://login.taobao.com/member/login.jhtml'
,
'Content-Type'
:
'application/x-www-form-urlencoded'
,
'Connection'
:
'Keep-Alive'
}
#用戶名
self
.
username
=
'cqcre'
#ua字符串,通過淘寶ua算法計算得出,包含了時間戳,瀏覽器,屏幕分辨率,隨機數,鼠標移動,鼠標點擊,其實還有鍵盤輸入記錄,鼠標移動的記錄、點擊的記錄等等的信息
self
.
ua
=
'191UW5TcyMNYQwiAiwTR3tCf0J/QnhEcUpkMmQ=|Um5Ockt0TXdPc011TXVKdyE=|U2xMHDJ+H2QJZwBxX39Rb1d5WXcrSixAJ1kjDVsN|VGhXd1llXGNaYFhkWmJaYl1gV2pIdUtyTXRKfkN4Qn1FeEF6R31TBQ==|VWldfS0TMw8xDjYWKhAwHiUdOA9wCDEVaxgkATdcNU8iDFoM|VmNDbUMV|V2NDbUMV|WGRYeCgGZhtmH2VScVI2UT5fORtmD2gCawwuRSJHZAFsCWMOdVYyVTpbPR99HWAFYVMpUDUFORshHiQdJR0jAT0JPQc/BDoFPgooFDZtVBR5Fn9VOwt2EWhCOVQ4WSJPJFkHXhgoSDVIMRgnHyFqQ3xEezceIRkmahRqFDZLIkUvRiEDaA9qQ3xEezcZORc5bzk=|WWdHFy0TMw8vEy0UIQE0ADgYJBohGjoAOw4uEiwXLAw2DThuOA==|WmBAED5+KnIbdRh1GXgFQSZbGFdrUm1UblZqVGxQa1ZiTGxQcEp1I3U=|W2NDEz19KXENZwJjHkY7Ui9OJQsre09zSWlXY1oMLBExHzERLxsuE0UT|XGZGFjh4LHQdcx5zH34DRyBdHlFtVGtSaFBsUmpWbVBkSmpXd05zTnMlcw==|XWdHFzl5LXUJYwZnGkI/VitKIQ8vEzMKNws3YTc=|XmdaZ0d6WmVFeUB8XGJaYEB4TGxWbk5yTndXa0tyT29Ta0t1QGBeZDI='
#密碼,在這裏不能輸入真實密碼,淘寶對此密碼進行了加密處理,256位,此處爲加密後的密碼
self
.
password2
=
'7511aa6854629e45de220d29174f1066537a73420ef6dbb5b46f202396703a2d56b0312df8769d886e6ca63d587fdbb99ee73927e8c07d9c88cd02182e1a21edc13fb8e0a4a2a4b5c253bf38484bd0e08199e03eb9bf7b365a5c673c03407d812b91394f0d3c7564042e3f2b11d156aeea37ad6460118914125ab8f8ac466f'
self
.
post
=
post
=
{
'ua'
:
self
.
ua
,
'TPL_checkcode'
:
''
,
'CtrlVersion'
:
'1,0,0,7'
,
'TPL_password'
:
''
,
'TPL_redirect_url'
:
'http://i.taobao.com/my_taobao.htm?nekot=udm8087E1424147022443'
,
'TPL_username'
:
self
.
username
,
'loginsite'
:
'0'
,
'newlogin'
:
'0'
,
'from'
:
'tb'
,
'fc'
:
'default'
,
'style'
:
'default'
,
'css_style'
:
''
,
'tid'
:
'XOR_1_000000000000000000000000000000_625C4720470A0A050976770A'
,
'support'
:
'000001'
,
'loginType'
:
'4'
,
'minititle'
:
''
,
'minipara'
:
''
,
'umto'
:
'NaN'
,
'pstrong'
:
'3'
,
'llnick'
:
''
,
'sign'
:
''
,
'need_sign'
:
''
,
'isIgnore'
:
''
,
'full_redirect'
:
''
,
'popid'
:
''
,
'callback'
:
''
,
'guf'
:
''
,
'not_duplite_str'
:
''
,
'need_user_id'
:
''
,
'poy'
:
''
,
'gvfdcname'
:
'10'
,
'gvfdcre'
:
''
,
'from_encoding '
:
''
,
'sub'
:
''
,
'TPL_password_2'
:
self
.
password2
,
'loginASR'
:
'1'
,
'loginASRSuc'
:
'1'
,
'allp'
:
''
,
'oslanguage'
:
'zh-CN'
,
'sr'
:
'1366*768'
,
'osVer'
:
'windows|6.1'
,
'naviVer'
:
'firefox|35'
}
#將POST的數據進行編碼轉換
self
.
postData
=
urllib
.
urlencode
(
self
.
post
)
#設置代理
self
.
proxy
=
urllib2
.
ProxyHandler
(
{
'http'
:
self
.
proxyURL
}
)
#設置cookie
self
.
cookie
=
cookielib
.
LWPCookieJar
(
)
#設置cookie處理器
self
.
cookieHandler
=
urllib2
.
HTTPCookieProcessor
(
self
.
cookie
)
#設置登陸時用到的opener,它的open方法至關於urllib2.urlopen
self
.
opener
=
urllib2
.
build_opener
(
self
.
cookieHandler
,
self
.
proxy
,
urllib2
.
HTTPHandler
)
#獲得是否須要輸入驗證碼,此次請求的相應有時會不一樣,有時須要驗證有時不須要
def
needCheckCode
(
self
)
:
#第一次登陸獲取驗證碼嘗試,構建request
request
=
urllib2
.
Request
(
self
.
loginURL
,
self
.
postData
,
self
.
loginHeaders
)
#獲得第一次登陸嘗試的相應
response
=
self
.
opener
.
open
(
request
)
#獲取其中的內容
content
=
response
.
read
(
)
.
decode
(
'gbk'
)
#獲取狀態嗎
status
=
response
.
getcode
(
)
#狀態碼爲200,獲取成功
if
status
==
200
:
print
u
"獲取請求成功"
#\u8bf7\u8f93\u5165\u9a8c\u8bc1\u7801這六個字是請輸入驗證碼的utf-8編碼
pattern
=
re
.
compile
(
u
'\u8bf7\u8f93\u5165\u9a8c\u8bc1\u7801'
,
re
.
S
)
result
=
re
.
search
(
pattern
,
content
)
print
content
#若是找到該字符,表明須要輸入驗證碼
if
result
:
print
u
"這次安全驗證異常,您須要輸入驗證碼"
return
content
#不然不須要
else
:
#返回結果直接帶有J_HToken字樣,代表直接驗證經過
tokenPattern
=
re
.
compile
(
'id="J_HToken"'
)
tokenMatch
=
re
.
search
(
tokenPattern
,
content
)
if
tokenMatch
:
print
u
"這次安全驗證經過,您此次不須要輸入驗證碼"
return
False
else
:
print
u
"獲取請求失敗"
return
None
#獲得驗證碼圖片
def
getCheckCode
(
self
,
page
)
:
#獲得驗證碼的圖片
pattern
=
re
.
compile
(
'<img id="J_StandardCode_m.*?data-src="(.*?)"'
,
re
.
S
)
#匹配的結果
matchResult
=
re
.
search
(
pattern
,
page
)
#已經匹配獲得內容,而且驗證碼圖片連接不爲空
if
matchResult
and
matchResult
.
group
(
1
)
:
print
matchResult
.
group
(
1
)
return
matchResult
.
group
(
1
)
else
:
print
u
"沒有找到驗證碼內容"
return
False
#輸入驗證碼,從新請求,若是驗證成功,則返回J_HToken
def
loginWithCheckCode
(
self
)
:
#提示用戶輸入驗證碼
checkcode
=
raw_input
(
'請輸入驗證碼:'
)
#將驗證碼從新添加到post的數據中
self
.
post
[
'TPL_checkcode'
]
=
checkcode
#對post數據從新進行編碼
self
.
postData
=
urllib
.
urlencode
(
self
.
post
)
try
:
#再次構建請求,加入驗證碼以後的第二次登陸嘗試
request
=
urllib2
.
Request
(
self
.
loginURL
,
self
.
postData
,
self
.
loginHeaders
)
#獲得第一次登陸嘗試的相應
response
=
self
.
opener
.
open
(
request
)
#獲取其中的內容
content
=
response
.
read
(
)
.
decode
(
'gbk'
)
#檢測驗證碼錯誤的正則表達式,\u9a8c\u8bc1\u7801\u9519\u8bef 是驗證碼錯誤五個字的編碼
pattern
=
re
.
compile
(
u
'\u9a8c\u8bc1\u7801\u9519\u8bef'
,
re
.
S
)
result
=
re
.
search
(
pattern
,
content
)
#若是返回頁面包括了,驗證碼錯誤五個字
if
result
:
print
u
"驗證碼輸入錯誤"
return
False
else
:
#返回結果直接帶有J_HToken字樣,說明驗證碼輸入成功,成功跳轉到了獲取HToken的界面
tokenPattern
=
re
.
compile
(
'id="J_HToken" value="(.*?)"'
)
tokenMatch
=
re
.
search
(
tokenPattern
,
content
)
#若是匹配成功,找到了J_HToken
if
tokenMatch
:
print
u
"驗證碼輸入正確"
print
tokenMatch
.
group
(
1
)
return
tokenMatch
.
group
(
1
)
else
:
#匹配失敗,J_Token獲取失敗
print
u
"J_Token獲取失敗"
return
False
except
urllib2
.
HTTPError
,
e
:
print
u
"鏈接服務器出錯,錯誤緣由"
,
e
.
reason
return
False
#程序運行主幹
def
main
(
self
)
:
#是否須要驗證碼,是則獲得頁面內容,不是則返回False
needResult
=
self
.
needCheckCode
(
)
#請求獲取失敗,獲得的結果是None
if
not
needResult
==
None
:
if
not
needResult
==
False
:
print
u
"您須要手動輸入驗證碼"
idenCode
=
self
.
getCheckCode
(
needResult
)
#獲得了驗證碼的連接
if
not
idenCode
==
False
:
print
u
"驗證碼獲取成功"
print
u
"請在瀏覽器中輸入您看到的驗證碼"
webbrowser
.
open_new_tab
(
idenCode
)
J_HToken
=
self
.
loginWithCheckCode
(
)
print
"J_HToken"
,
J_HToken
#驗證碼連接爲空,無效驗證碼
else
:
print
u
"驗證碼獲取失敗,請重試"
else
:
print
u
"不須要輸入驗證碼"
else
:
print
u
"請求登陸頁面失敗,沒法確認是否須要驗證碼"
taobao
=
Taobao
(
)
taobao
.
main
(
)
|
如今的運行結果是這樣的,咱們已經能夠獲得 J_HToken 了,離成功又邁進了一步。
好,到如今爲止,咱們應該能夠獲取到J_HToken的值啦。
st也是一個經計算獲得的code,能夠這麼理解,st是淘寶後臺利用J_HToken以及其餘數據通過計算以後獲得的,能夠利用st和用戶名直接 用get方式登陸,因此st能夠理解爲一個祕鑰。這個st值只會使用一次,若是第二次用get方式登陸則會失效。因此它是一次性使用的。
下面J_HToken計算st的方法以下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#經過token得到st
def
getSTbyToken
(
self
,
token
)
:
tokenURL
=
'https://passport.alipay.com/mini_apply_st.js?site=0&token=%s&callback=stCallback6'
%
token
request
=
urllib2
.
Request
(
tokenURL
)
response
=
urllib2
.
urlopen
(
request
)
#處理st,得到用戶淘寶主頁的登陸地址
pattern
=
re
.
compile
(
'{"st":"(.*?)"}'
,
re
.
S
)
result
=
re
.
search
(
pattern
,
response
.
read
(
)
)
#若是成功匹配
if
result
:
print
u
"成功獲取st碼"
#獲取st的值
st
=
result
.
group
(
1
)
return
st
else
:
print
u
"未匹配到st"
return
False
|
獲得st以後,基本上就大功告成啦,一段辛苦終於沒有白費,你能夠直接構建get方式請求的URL,直接訪問這個URL即可以實現登陸。
1
|
stURL
=
'https://login.taobao.com/member/vst.htm?st=%s&TPL_username=%s'
%
(
st
,
username
)
|
好比
1
|
https
:
/
/
login
.
taobao
.
com
/
member
/
vst
.
htm
?
st
=
1uynJELa4hKfsfWU3OjPJCw
&
TPL_username
=
cqcre
|
直接訪問該連接便可實現登陸,不過我這個應該已經失效了吧~
代碼在這先不貼了,剩下的一塊兒貼了~
已買到的寶貝的頁面地址是
1
|
http
:
/
/
buyer
.
trade
.
taobao
.
com
/
trade
/
itemlist
/
list_bought_items
.
htm
|
另外還有頁碼的參數。
從新構建一個帶有cookie的opener,將上面的帶有st的URL打開,保存它的cookie,而後再利用這個opener打開已買到的寶貝的頁面,你就會獲得已買到的寶貝頁面詳情了。
1
2
3
4
5
6
|
#得到已買到的寶貝頁面
def
getGoodsPage
(
self
,
pageIndex
)
:
goodsURL
=
'http://buyer.trade.taobao.com/trade/itemlist/listBoughtItems.htm?action=itemlist/QueryAction&event_submit_do_query=1&pageNum='
+
str
(
pageIndex
)
response
=
self
.
newOpener
.
open
(
goodsURL
)
page
=
response
.
read
(
)
.
decode
(
'gbk'
)
return
page
|
正則表達式提取信息
這是個人已買到的寶貝界面,審查元素能夠看到,每個寶貝都是tbody標籤包圍着。
咱們如今想獲取訂單時間,訂單號,賣家店鋪名稱,寶貝名稱,原價,購買數量,最後付款多少,交易狀態這幾個量,具體就再也不分析啦,正則表達式還不熟悉的同窗請參考前面所說的正則表達式的用法,在這裏,正則表達式匹配的代碼是
1
2
3
4
5
6
7
8
9
|
#u'\u8ba2\u5355\u53f7'是訂單號的編碼
pattern
=
re
.
compile
(
u
'dealtime.*?>(.*?)</span>.*?\u8ba2\u5355\u53f7.*?<em>(.*?)</em>.*?shopname.*?title="(.*?)".*?baobei-name">.*?<a.*?>(.*?)</a>.*?'
u
'price.*?title="(.*?)".*?quantity.*?title="(.*?)".*?amount.*?em.*?>(.*?)</em>.*?trade-status.*?<a.*?>(.*?)</a>'
,
re
.
S
)
result
=
re
.
findall
(
pattern
,
page
)
for
item
in
result
:
print
'------------------------------------------------------------'
print
"購買日期:"
,
item
[
0
]
.
strip
(
)
,
'訂單號:'
,
item
[
1
]
.
strip
(
)
,
'賣家店鋪:'
,
item
[
2
]
.
strip
(
)
print
'寶貝名稱:'
,
item
[
3
]
.
strip
(
)
print
'原價:'
,
item
[
4
]
.
strip
(
)
,
'購買數量:'
,
item
[
5
]
.
strip
(
)
,
'實際支付:'
,
item
[
6
]
.
strip
(
)
,
'交易狀態'
,
item
[
7
]
.
strip
(
)
|
恩,你懂得,最重要的東西來了,通過博主2天多的奮戰,代碼基本就構建完成。寫了兩個類,其中提取頁面信息的方法我單獨放到了一個類中,叫 tool.py,類名爲 Tool。
先看一下運行結果吧~
最終代碼以下
1
|
tool
.
py
|
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
|
__author__
=
'CQC'
# -*- coding:utf-8 -*-
import
re
#處理得到的寶貝頁面
class
Tool
:
#初始化
def
__init__
(
self
)
:
pass
#得到頁碼數
def
getPageNum
(
self
,
page
)
:
pattern
=
re
.
compile
(
u
'<div class="total">.*?\u5171(.*?)\u9875'
,
re
.
S
)
result
=
re
.
search
(
pattern
,
page
)
if
result
:
print
"找到了共多少頁"
pageNum
=
result
.
group
(
1
)
.
strip
(
)
print
'共'
,
pageNum
,
'頁'
return
pageNum
def
getGoodsInfo
(
self
,
page
)
:
#u'\u8ba2\u5355\u53f7'是訂單號的編碼
pattern
=
re
.
compile
(
u
'dealtime.*?>(.*?)</span>.*?\u8ba2\u5355\u53f7.*?<em>(.*?)</em>.*?shopname.*?title="(.*?)".*?baobei-name">.*?<a.*?>(.*?)</a>.*?'
u
'price.*?title="(.*?)".*?quantity.*?title="(.*?)".*?amount.*?em.*?>(.*?)</em>.*?trade-status.*?<a.*?>(.*?)</a>'
,
re
.
S
)
result
=
re
.
findall
(
pattern
,
page
)
for
item
in
result
:
print
'------------------------------------------------------------'
print
"購買日期:"
,
item
[
0
]
.
strip
(
)
,
'訂單號:'
,
item
[
1
]
.
strip
(
)
,
'賣家店鋪:'
,
item
[
2
]
.
strip
(
)
print
'寶貝名稱:'
,
item
[
3
]
.
strip
(
)
print
'原價:'
,
item
[
4
]
.
strip
(
)
,
'購買數量:'
,
item
[
5
]
.
strip
(
)
,
'實際支付:'
,
item
[
6
]
.
strip
(
)
,
'交易狀態'
,
item
[
7
]
.
strip
(
)
|
1
|
taobao
.
py
|
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
|
__author__
=
'CQC'
# -*- coding:utf-8 -*-
import
urllib
import
urllib2
import
cookielib
import
re
import
webbrowser
import
tool
#模擬登陸淘寶類
class
Taobao
:
#初始化方法
def
__init__
(
self
)
:
#登陸的URL
self
.
loginURL
=
"https://login.taobao.com/member/login.jhtml"
#代理IP地址,防止本身的IP被封禁
self
.
proxyURL
=
'http://120.193.146.97:843'
#登陸POST數據時發送的頭部信息
self
.
loginHeaders
=
{
'Host'
:
'login.taobao.com'
,
'User-Agent'
:
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0'
,
'Referer'
:
'https://login.taobao.com/member/login.jhtml'
,
'Content-Type'
:
'application/x-www-form-urlencoded'
,
'Connection'
:
'Keep-Alive'
}
#用戶名
self
.
username
=
'cqcre'
#ua字符串,通過淘寶ua算法計算得出,包含了時間戳,瀏覽器,屏幕分辨率,隨機數,鼠標移動,鼠標點擊,其實還有鍵盤輸入記錄,鼠標移動的記錄、點擊的記錄等等的信息
self
.
ua
=
'191UW5TcyMNYQwiAiwTR3tCf0J/QnhEcUpkMmQ=|Um5Ockt0TXdPc011TXVKdyE=|U2xMHDJ+H2QJZwBxX39Rb1d5WXcrSixAJ1kjDVsN|VGhXd1llXGNaYFhkWmJaYl1gV2pIdUtyTXRKfkN4Qn1FeEF6R31TBQ==|VWldfS0TMw8xDjYWKhAwHiUdOA9wCDEVaxgkATdcNU8iDFoM|VmNDbUMV|V2NDbUMV|WGRYeCgGZhtmH2VScVI2UT5fORtmD2gCawwuRSJHZAFsCWMOdVYyVTpbPR99HWAFYVMpUDUFORshHiQdJR0jAT0JPQc/BDoFPgooFDZtVBR5Fn9VOwt2EWhCOVQ4WSJPJFkHXhgoSDVIMRgnHyFqQ3xEezceIRkmahRqFDZLIkUvRiEDaA9qQ3xEezcZORc5bzk=|WWdHFy0TMw8vEy0UIQE0ADgYJBohGjoAOw4uEiwXLAw2DThuOA==|WmBAED5+KnIbdRh1GXgFQSZbGFdrUm1UblZqVGxQa1ZiTGxQcEp1I3U=|W2NDEz19KXENZwJjHkY7Ui9OJQsre09zSWlXY1oMLBExHzERLxsuE0UT|XGZGFjh4LHQdcx5zH34DRyBdHlFtVGtSaFBsUmpWbVBkSmpXd05zTnMlcw==|XWdHFzl5LXUJYwZnGkI/VitKIQ8vEzMKNws3YTc=|XmdaZ0d6WmVFeUB8XGJaYEB4TGxWbk5yTndXa0tyT29Ta0t1QGBeZDI='
#密碼,在這裏不能輸入真實密碼,淘寶對此密碼進行了加密處理,256位,此處爲加密後的密碼
self
.
password2
=
'7511aa6854629e45de220d29174f1066537a73420ef6dbb5b46f202396703a2d56b0312df8769d886e6ca63d587fdbb99ee73927e8c07d9c88cd02182e1a21edc13fb8e140a4a2a4b53bf38484bd0e08199e03eb9bf7b365a5c673c03407d812b91394f0d3c7564042e3f2b11d156aeea37ad6460118914125ab8f8ac466f'
self
.
post
=
post
=
{
'ua'
:
self
.
ua
,
'TPL_checkcode'
:
''
,
'CtrlVersion'
:
'1,0,0,7'
,
'TPL_password'
:
''
,
'TPL_redirect_url'
:
'http://i.taobao.com/my_taobao.htm?nekot=udm8087E1424147022443'
,
'TPL_username'
:
self
.
username
,
'loginsite'
:
'0'
,
'newlogin'
:
'0'
,
'from'
:
'tb'
,
'fc'
:
'default'
,
'style'
:
'default'
,
'css_style'
:
''
,
'tid'
:
'XOR_1_000000000000000000000000000000_625C4720470A0A050976770A'
,
'support'
:
'000001'
,
'loginType'
:
'4'
,
'minititle'
:
''
,
'minipara'
:
''
,
'umto'
:
'NaN'
,
'pstrong'
:
'3'
,
'llnick'
:
''
,
'sign'
:
''
,
'need_sign'
:
''
,
'isIgnore'
:
''
,
'full_redirect'
:
''
,
'popid'
:
''
,
'callback'
:
''
,
'guf'
:
''
,
'not_duplite_str'
:
''
,
'need_user_id'
:
''
,
'poy'
:
''
,
'gvfdcname'
:
'10'
,
'gvfdcre'
:
''
,
'from_encoding '
:
''
,
'sub'
:
''
,
'TPL_password_2'
:
self
.
password2
,
'loginASR'
:
'1'
,
'loginASRSuc'
:
'1'
,
'allp'
:
''
,
'oslanguage'
:
'zh-CN'
,
'sr'
:
'1366*768'
,
'osVer'
:
'windows|6.1'
,
'naviVer'
:
'firefox|35'
}
#將POST的數據進行編碼轉換
self
.
postData
=
urllib
.
urlencode
(
self
.
post
)
#設置代理
self
.
proxy
=
urllib2
.
ProxyHandler
(
{
'http'
:
self
.
proxyURL
}
)
#設置cookie
self
.
cookie
=
cookielib
.
LWPCookieJar
(
)
#設置cookie處理器
self
.
cookieHandler
=
urllib2
.
HTTPCookieProcessor
(
self
.
cookie
)
#設置登陸時用到的opener,它的open方法至關於urllib2.urlopen
self
.
opener
=
urllib2
.
build_opener
(
self
.
cookieHandler
,
self
.
proxy
,
urllib2
.
HTTPHandler
)
#賦值J_HToken
self
.
J_HToken
=
''
#登陸成功時,須要的Cookie
self
.
newCookie
=
cookielib
.
CookieJar
(
)
#登錄成功時,須要的一個新的opener
self
.
newOpener
=
urllib2
.
build_opener
(
urllib2
.
HTTPCookieProcessor
(
self
.
newCookie
)
)
#引入工具類
self
.
tool
=
tool
.
Tool
(
)
#獲得是否須要輸入驗證碼,此次請求的相應有時會不一樣,有時須要驗證有時不須要
def
needCheckCode
(
self
)
:
#第一次登陸獲取驗證碼嘗試,構建request
request
=
urllib2
.
Request
(
self
.
loginURL
,
self
.
postData
,
self
.
loginHeaders
)
#獲得第一次登陸嘗試的相應
response
=
self
.
opener
.
open
(
request
)
#獲取其中的內容
content
=
response
.
read
(
)
.
decode
(
'gbk'
)
#獲取狀態嗎
status
=
response
.
getcode
(
)
#狀態碼爲200,獲取成功
if
status
==
200
:
print
u
"獲取請求成功"
#\u8bf7\u8f93\u5165\u9a8c\u8bc1\u7801這六個字是請輸入驗證碼的utf-8編碼
pattern
=
re
.
compile
(
u
'\u8bf7\u8f93\u5165\u9a8c\u8bc1\u7801'
,
re
.
S
)
result
=
re
.
search
(
pattern
,
content
)
#若是找到該字符,表明須要輸入驗證碼
if
result
:
print
u
"這次安全驗證異常,您須要輸入驗證碼"
return
content
#不然不須要
else
:
#返回結果直接帶有J_HToken字樣,代表直接驗證經過
tokenPattern
=
re
.
compile
(
'id="J_HToken" value="(.*?)"'
)
tokenMatch
=
re
.
search
(
tokenPattern
,
content
)
if
tokenMatch
:
self
.
J_HToken
=
tokenMatch
.
group
(
1
)
print
u
"這次安全驗證經過,您此次不須要輸入驗證碼"
return
False
else
:
print
u
"獲取請求失敗"
return
None
#獲得驗證碼圖片
def
getCheckCode
(
self
,
page
)
:
#獲得驗證碼的圖片
pattern
=
re
.
compile
(
'<img id="J_StandardCode_m.*?data-src="(.*?)"'
,
re
.
S
)
#匹配的結果
matchResult
=
re
.
search
(
pattern
,
page
)
#已經匹配獲得內容,而且驗證碼圖片連接不爲空
if
matchResult
and
matchResult
.
group
(
1
)
:
return
matchResult
.
group
(
1
)
else
:
print
u
"沒有找到驗證碼內容"
return
False
#輸入驗證碼,從新請求,若是驗證成功,則返回J_HToken
def
loginWithCheckCode
(
self
)
:
#提示用戶輸入驗證碼
checkcode
=
raw_input
(
'請輸入驗證碼:'
)
#將驗證碼從新添加到post的數據中
self
.
post
[
'TPL_checkcode'
]
=
checkcode
#對post數據從新進行編碼
self
.
postData
=
urllib
.
urlencode
(
self
.
post
)
try
:
#再次構建請求,加入驗證碼以後的第二次登陸嘗試
request
=
urllib2
.
Request
(
self
.
loginURL
,
self
.
postData
,
self
.
loginHeaders
)
#獲得第一次登陸嘗試的相應
response
=
self
.
opener
.
open
(
request
)
#獲取其中的內容
content
=
response
.
read
(
)
.
decode
(
'gbk'
)
#檢測驗證碼錯誤的正則表達式,\u9a8c\u8bc1\u7801\u9519\u8bef 是驗證碼錯誤五個字的編碼
pattern
=
re
.
compile
(
u
'\u9a8c\u8bc1\u7801\u9519\u8bef'
,
re
.
S
)
result
=
re
.
search
(
pattern
,
content
)
#若是返回頁面包括了,驗證碼錯誤五個字
if
result
:
print
u
"驗證碼輸入錯誤"
return
False
else
:
#返回結果直接帶有J_HToken字樣,說明驗證碼輸入成功,成功跳轉到了獲取HToken的界面
tokenPattern
=
re
.
compile
(
'id="J_HToken" value="(.*?)"'
)
tokenMatch
=
re
.
search
(
tokenPattern
,
content
)
#若是匹配成功,找到了J_HToken
if
tokenMatch
:
print
u
"驗證碼輸入正確"
self
.
J_HToken
=
tokenMatch
.
group
(
1
)
return
tokenMatch
.
group
(
1
)
else
:
#匹配失敗,J_Token獲取失敗
print
u
"J_Token獲取失敗"
return
False
except
urllib2
.
HTTPError
,
e
:
print
u
"鏈接服務器出錯,錯誤緣由"
,
e
.
reason
return
False
#經過token得到st
def
getSTbyToken
(
self
,
token
)
:
tokenURL
=
'https://passport.alipay.com/mini_apply_st.js?site=0&token=%s&callback=stCallback6'
%
token
request
=
urllib2
.
Request
(
tokenURL
)
response
=
urllib2
.
urlopen
(
request
)
#處理st,得到用戶淘寶主頁的登陸地址
pattern
=
re
.
compile
(
'{"st":"(.*?)"}'
,
re
.
S
)
result
=
re
.
search
(
pattern
,
response
.
read
(
)
)
#若是成功匹配
if
result
:
print
u
"成功獲取st碼"
#獲取st的值
st
=
result
.
group
(
1
)
return
st
else
:
print
u
"未匹配到st"
return
False
#利用st碼進行登陸,獲取重定向網址
def
loginByST
(
self
,
st
,
username
)
:
stURL
=
'https://login.taobao.com/member/vst.htm?st=%s&TPL_username=%s'
%
(
st
,
username
)
headers
=
{
'User-Agent'
:
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0'
,
'Host'
:
'login.taobao.com'
,
'Connection'
:
'Keep-Alive'
}
request
=
urllib2
.
Request
(
stURL
,
headers
=
headers
)
response
=
self
.
newOpener
.
open
(
request
)
content
=
response
.
read
(
)
.
decode
(
'gbk'
)
#檢測結果,看是否登陸成功
pattern
=
re
.
|