目錄
- Python3爬蟲(chóng)模擬新浪微博登錄
- 過(guò)程分析
- 遇到的坑
- 關(guān)于第一步,賬號(hào)和密碼加密
- 登錄請(qǐng)求post數(shù)據(jù)包裝
- 關(guān)于登錄后如跳轉(zhuǎn)到主頁(yè)面
- 其他模塊
- 執(zhí)行結(jié)果
Python3爬蟲(chóng)模擬新浪微博登錄
初學(xué)Python3小白一枚,若有錯(cuò)誤請(qǐng)不吝賜教
過(guò)程分析
整個(gè)過(guò)程
從填寫(xiě)數(shù)據(jù)到跳轉(zhuǎn)到主頁(yè)一共經(jīng)歷了七個(gè)步驟:
1.在登陸前,輸入賬號(hào)結(jié)束,失去輸入框焦點(diǎn),瀏覽器會(huì)發(fā)送兩個(gè)請(qǐng)求,分別請(qǐng)求了登陸前加密密碼所需的servertime、nonce、pubkey(圖中對(duì)應(yīng)3)
2.第二個(gè)ajax請(qǐng)求的是關(guān)于驗(yàn)證碼的(圖中對(duì)應(yīng)4、5)
3.這個(gè)是點(diǎn)擊登錄按鈕后,將加密后的數(shù)據(jù)post到服務(wù)器(圖中對(duì)應(yīng)6)
4.服務(wù)器會(huì)返回一系列數(shù)據(jù),(對(duì)應(yīng)圖中的8),它包含了重定向的地址
5.多次頁(yè)面加載后,會(huì)接收到來(lái)自服務(wù)器的json數(shù)據(jù)包(對(duì)應(yīng)圖中的19)在這
個(gè)數(shù)據(jù)包中包含了每個(gè)微博用戶(hù)特定的uniqueid
6.這是一個(gè)攜帶有相關(guān)用戶(hù)信息的script腳本(對(duì)應(yīng)圖中的22)
7.經(jīng)過(guò)一系列的跳轉(zhuǎn)后,最終跳轉(zhuǎn)到個(gè)人主頁(yè)面
遇到的坑
遇到的最嚴(yán)重的坑,就是驗(yàn)證碼的啦
驗(yàn)證碼的請(qǐng)求分析,著實(shí)耗費(fèi)了大半天 。這是驗(yàn)證碼請(qǐng)求的服務(wù)器地址:
https://login.sina.com.cn/cgi/pin.php?r=18674039&s=0&p=yf-c92f2edb50c21d4bcbfdc3fccfdb94c4c23f
其中分析后發(fā)現(xiàn):
固定服務(wù)器url:https://login.sina.com.cn/cgi/pin.php?
攜帶的參數(shù):r = 18674039,p = yf-c92f2edb50c21d4bcbfdc3fccfdb94c4c23f,s = 0
其中s和p是固定值,r是一串不固定變化的數(shù)字,在分析的過(guò)程中,我試圖尋找關(guān)于r的規(guī)律,最后實(shí)在沒(méi)辦法,我打算在Fiddler中測(cè)試一下,看看不加參數(shù)r是否能獲得,結(jié)果是可喜可賀的,確實(shí)獲得了。
事實(shí)上,在保證cookie一致的情況下,去請(qǐng)求驗(yàn)證碼,也就是說(shuō)和你本次的登錄保持在一個(gè)cookie中,可以主動(dòng)的抓取驗(yàn)證碼。
# 獲取驗(yàn)證碼
def
get_verificationcode
(
)
:
print
(
"開(kāi)始請(qǐng)求獲取驗(yàn)證碼..."
)
url
=
"https://login.sina.com.cn/cgi/pin.php?s=0&p=yf-9f5e31626347e127bc21874aa9d6f4d745ca"
request
.
urlretrieve
(
url
=
url
,
filename
=
"./img/code.jpg"
)
print
(
"驗(yàn)證碼獲取成功!"
)
return
input
(
"請(qǐng)輸入驗(yàn)證碼:"
)
在應(yīng)對(duì)驗(yàn)證碼問(wèn)題上,我這里采用的是半人工半自動(dòng)的,將每次獲得的驗(yàn)證碼存到當(dāng)前目錄下的img文件中,人工查看和輸入驗(yàn)證碼。
關(guān)于第一步,賬號(hào)和密碼加密
經(jīng)分析在第二步發(fā)送登錄的post請(qǐng)求之前,瀏覽器會(huì)實(shí)現(xiàn)發(fā)一個(gè)請(qǐng)求,請(qǐng)求的響應(yīng)信息如下:
里邊攜帶的servertime、pubkey、nonce、rsakv等關(guān)鍵信息在后邊加密密碼和包裝post請(qǐng)求數(shù)據(jù)非常關(guān)鍵。關(guān)于如何得到這個(gè)分析以及整個(gè)爬蟲(chóng)的結(jié)構(gòu)也,參考了這篇博文:https://www.cnblogs.com/houkai/p/3488468.html.
以下是加密模塊encrypt.py的代碼
import
base64
import
binascii
import
rsa
# 對(duì)用戶(hù)名加密
def
encryUsername
(
username
)
:
print
(
"開(kāi)始加密用戶(hù)名..."
)
text
=
(
base64
.
b64encode
(
username
.
encode
(
encoding
=
"utf-8"
)
)
)
text
=
text
.
decode
(
)
return
str
(
text
)
.
replace
(
"="
,
""
)
# 對(duì)密碼加密
def
encryPassword
(
password
,
servertime
,
nonce
,
pubkey
)
:
print
(
"開(kāi)始加密密碼..."
)
rsaPublickey
=
int
(
pubkey
,
16
)
key
=
rsa
.
PublicKey
(
rsaPublickey
,
65537
)
# 創(chuàng)建公鑰
message
=
str
(
servertime
)
+
'\t'
+
str
(
nonce
)
+
'\n'
+
str
(
password
)
# 拼接明文js加密文件中得到
message
=
bytes
(
message
,
encoding
=
"utf-8"
)
passwd
=
rsa
.
encrypt
(
message
,
key
)
# 加密
passwd
=
binascii
.
b2a_hex
(
passwd
)
# 將加密信息轉(zhuǎn)換為16進(jìn)制。
return
passwd
登錄請(qǐng)求post數(shù)據(jù)包裝
在Chrome的開(kāi)發(fā)者模式下,可以抓取相關(guān)參數(shù)信息
# 組織post數(shù)據(jù)
def
get_postData
(
su
,
password
,
servertime
,
nonce
,
pubkey
,
rsakv
)
:
print
(
"開(kāi)始組織post數(shù)據(jù)..."
)
# 密碼加密
sp
=
encrypt
.
encryPassword
(
password
,
servertime
,
nonce
,
pubkey
)
# 驗(yàn)證碼請(qǐng)求
door
=
get_verificationcode
(
)
# 構(gòu)造post請(qǐng)求參數(shù)
data
=
{
"door"
:
door
,
"entry"
:
"weibo"
,
"gateway"
:
1
,
"from"
:
""
,
"savestate"
:
7
,
"su"
:
su
,
"sp"
:
sp
,
"servertime"
:
servertime
,
"service"
:
"miniblog"
,
"nonce"
:
nonce
,
"rsakv"
:
rsakv
,
"encoding"
:
"UTF-8"
,
"domain"
:
"sina.com.cn"
,
"returntype"
:
"META"
,
"vsnf"
:
1
,
"useticket"
:
1
,
"pwencode"
:
"rsa2"
,
"prelt"
:
372
,
"qrcode_flag"
:
"false"
,
"url"
:
"https://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack"
}
data
=
parse
.
urlencode
(
data
)
.
encode
(
"utf-8"
)
return
data
關(guān)于登錄后如跳轉(zhuǎn)到主頁(yè)面
這個(gè)過(guò)程參考了:https://www.cnblogs.com/woaixuexi9999/p/9404745.html
在模塊login.py中定義了一個(gè)類(lèi)Login,其中的登錄方法代碼:
def
login
(
self
)
:
# 第一步 獲得時(shí)間戳、公鑰、nonce等數(shù)據(jù)
req
=
request
.
Request
(
url
=
self
.
__preloginUrl
,
headers
=
self
.
headers1
,
method
=
"get"
)
response
=
request
.
urlopen
(
req
)
text
=
response
.
read
(
)
servertime
,
nonce
,
pubkey
,
rsakv
=
dealdata
.
get_prelogin
(
text
=
text
)
# 第二步 向服務(wù)器發(fā)送post請(qǐng)求 登錄信息
postdata
=
dealdata
.
get_postData
(
self
.
__su
,
self
.
__password
,
servertime
,
nonce
,
pubkey
,
rsakv
)
req
=
request
.
Request
(
url
=
self
.
__loginUrl
,
headers
=
self
.
__postheaders
,
data
=
postdata
,
method
=
"post"
)
response
=
request
.
urlopen
(
req
)
text
=
response
.
read
(
)
# 第三步 解析登錄響應(yīng)數(shù)據(jù) 獲取中間鏈接
replaceUrl
=
dealdata
.
get_replaceUrl
(
text
=
text
)
# 分析登錄結(jié)果
result
,
retcode
,
reason
=
dealdata
.
get_reason
(
replaceUrl
)
if
result
==
False
:
print
(
"登錄失敗!"
)
print
(
"原因"
,
reason
)
return
else
:
print
(
"登錄成功!"
)
print
(
"正在向個(gè)人主頁(yè)跳轉(zhuǎn)..."
)
# 第四步 加載中間鏈接 提取ticket
response
=
request
.
urlopen
(
replaceUrl
)
text
=
response
.
read
(
)
ticket
=
dealdata
.
get_ticket
(
text
=
text
)
# 第五步 利用ticket組合關(guān)鍵部分構(gòu)造網(wǎng)址 獲得攜帶uniqueid的json數(shù)據(jù)
uniqueidUrl
=
ticket
+
"&callback=sinaSSOController.doCrossDomainCallBack&scriptId=ssoscript0&client=ssologin.js(v1.4.19)&_=1564805281285"
response
=
request
.
urlopen
(
uniqueidUrl
)
text
=
response
.
read
(
)
uniqueid
=
dealdata
.
get_uniqueid
(
text
)
# 第六步 跳轉(zhuǎn)到主頁(yè)
print
(
"進(jìn)入個(gè)人主頁(yè)..."
)
homeUrl
=
"https://weibo.com/u/"
+
uniqueid
+
"/home"
request
.
urlretrieve
(
homeUrl
,
"./html/home.html"
)
其他模塊
處理數(shù)據(jù)的dealdata.py模塊
工程文件列表
code.jpg是驗(yàn)證碼
home.html是加載的主頁(yè)
執(zhí)行結(jié)果
初學(xué)Python,深感Python的強(qiáng)大。人生苦短,我用Python。
此程序僅供嘗試使用,不可商用。
轉(zhuǎn)載請(qǐng)注明出處:https://blog.csdn.net/Blz624613442/article/details/98368815
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
