通过屡次尝试,模拟登陆淘宝终于成功了,实在是不容易,淘宝的登陆加密和验证太复杂了,煞费苦心,在此写出来和你们一块儿分享,但愿你们支持。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
.
|