做者:xiaoyuhtml
微信公衆號:Python數據科學git
知乎:Python數據分析師github
前兩篇和你們分享了爬蟲中http的一些概念和使用方法,基礎篇咱們主要介紹了http的請求頭
,高級篇咱們主要介紹了cookie
和session
(具體能夠點擊上面連接進行回顧)。但其實在爬蟲中還有不少關於http的內容須要瞭解,例如 token
,oauth
等。對於這些概念博主將在後續文章中逐一的詳細介紹,本篇主要針對前兩篇內容與你們分享一個模擬登陸
的實戰例子。算法
開始想以知乎爲例,可是看到網上關於知乎模擬登陸的教程太多了,因此就以「京東」
爲例。api
你們都知道,京東是不須要登陸就能夠訪問主頁內容的,所以模擬登陸的意義在於查看我的信息,好比能夠獲取我的的交易信息(購物車商品,購物歷史記錄,待收貨商品信息等),或者賣家的商品銷售信息和評論等等。瀏覽器
好了,瞭解背景事後,讓咱們開始模擬登陸吧。安全
你們都知道,模擬登陸其實就是經過http的post請求
方式來提交用戶信息的(用戶名和密碼
)。對於瀏覽器而言,只輸入用戶名和密碼就能夠登錄了(偶爾有驗證碼),那是由於瀏覽器在背後都幫你處理好了。而爬蟲的模擬登陸過程須要咱們本身解決,所以咱們須要弄清楚瀏覽器的那些背後操做是如何進行的才能對症下藥。bash
難點分析:服務器
咱們打開瀏覽器,博主用的Chrome
瀏覽器。首先使用Ctrl+Shift+N
進入乾淨的無痕模式,防止以前的cookie數據形成干擾。微信
輸入了京東的登錄網址 passport.jd.com/new/login.a…,進入以下登陸界面。
如今咱們經過開發者工具來看看瀏覽器背後都幹了什麼吧。有的朋友提問到,輸入用戶名和密碼後頁面直接跳轉到主頁面了,看不到咱們要的數據了。其實這裏只須要故意將你的密碼輸錯不進入跳轉就能夠解決了。
點擊登陸,而後咱們看到有個FormData
,這就是瀏覽器每次向服務器提交的表單信息。
第一眼看過去感受快要無望了。可是彆着急,這些字段信息其實都是有處可尋的。咱們Ctrl+U
打開京東登陸頁面的源碼裏,而後Ctrl+F
試着搜一搜這些字段信息。
先搜第一個uuid
字段,發現它就在源碼中,緊着後面是一些其它的字段信息,那就齊活了。咱們看到除了loginname,nloginpwd,authcode,
其餘的字段全都是hidden
的類型,也就是被隱藏
了的字段。
好了,那下一步就天然知道幹什麼了。咱們能夠直接請求登陸頁面源碼提取字段信息了。
Cookie能夠經過使用http的Cookiejar
定製opener
進行獲取,也能夠直接使用requests
模塊來實現。
requests模塊實現起來比較方便,由於內部已經封裝好了自動處理Cookie的功能。第一次發送請求能夠經過服務器獲取Cookie,後續的請求則會自動帶着已獲取的Cookie信息進行發送。固然,也能夠手動添加Cookie,手動添加的Cookie優先級高,將會覆蓋默認的信息。
爲了說明模擬登陸的用法,本篇博主將使用簡便的requests模塊來完成對Cookie的處理。
驗證碼的處理方法也有多種,能夠分爲自動識別
的和手動識別
。
OCR
智能圖文識別,機器學習
進行識別訓練等。本篇將選擇手動錄入驗證碼,旨在理解模擬登陸的過程。
class JD_crawl:
def __init__(self, username, password):
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36'
' (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
'Referer': 'https://www.jd.com/',
}
self.login_url = "https://passport.jd.com/new/login.aspx"
self.post_url = "https://passport.jd.com/uc/loginService"
self.auth_url = "https://passport.jd.com/uc/showAuthCode"
self.session = requests.session()
self.username = username
self.password = password
複製代碼
JD_crawl
的類,設置了實例的headers
和session
會話對象,以及三個後面請求須要用到的url。session會話對象
。def get_login_info(self):
html = self.session.get(self.login_url, headers=self.headers).content
soup = BeautifulSoup(html, 'lxml')
uuid = soup.select('#uuid')[0].get('value')
eid = soup.select('#eid')[0].get('value')
fp = soup.select('input[name="fp"]')[0].get('value') # session id
_t = soup.select('input[name="_t"]')[0].get('value') # token
login_type = soup.select('input[name="loginType"]')[0].get('value')
pub_key = soup.select('input[name="pubKey"]')[0].get('value')
sa_token = soup.select('input[name="sa_token"]')[0].get('value')
auth_page = self.session.post(self.auth_url,
data={'loginName': self.username, 'nloginpwd': self.password}).text
print(auth_page)
if 'true' in auth_page:
auth_code_url = soup.select('#JD_Verification1')[0].get('src2')
auth_code = str(self.get_auth_img(auth_code_url))
else:
auth_code = ''
data = {
'uuid': uuid,
'eid': eid,
'fp': fp,
'_t': _t,
'loginType': login_type,
'loginname': self.username,
'nloginpwd': self.password,
'chkRememberMe': True,
'pubKey': pub_key,
'sa_token': sa_token,
'authcode': auth_code
}
return data
複製代碼
login_url
發起請求,獲取登錄頁面源碼後經過BeautifulSoup
解析工具ccs選擇器
來提取隱藏字段信息。loginname,nloginpwd,authcode
三個非隱藏字段須要用戶手動錄入。https://passport.jd.com/uc/showAuthCode
(代碼中的auth_url)來判斷。請求結果是一個以下格式的字符串。
請求結果: ({"verifycode":xxx})
xxx:true 或者 false
複製代碼
所以能夠簡單的查看結果中是否有true
來判斷是否須要驗證碼。
true
就須要調用驗證碼函數方法,將驗證碼圖片下載,輸入圖片上的驗證碼,並賦給authcode
字段進行表單提交完成登陸。authcode
字段爲空字符串。通常當咱們屢次輸入了錯誤的帳號或密碼時,構成安全危險,就會提示輸入驗證碼。
def get_auth_img(self, url):
auth_code_url = 'http:{}&yys={}'.format(url, str(int(time.time()*1000)))
auth_img = self.session.get(auth_code_url, headers=self.headers)
with open('authcode.jpg', 'wb') as f:
f.write(auth_img.content)
code_typein = input('請根據下載圖片輸入驗證碼:')
return code_typein
複製代碼
src2
src2="//authcode.jd.com/verify/image?a=1&acid=dcb4370b-2763-44e6-83ff-4b89bc01193d&uid=dcb4370b-2763-44e6-83ff-4b89bc01193d"
複製代碼
所以,咱們須要將它補全,在src2
前面拼接字符串 http:
。可是當咱們嘗試這個url的時候會發現圖片並無下載成功,爲何呢?
由於還須要在結尾加上時間戳,接着看後邊的 onclic
k,它的字符串中有和src2
徹底同樣的連接,但在結尾處多了 &yys= ''
。經過觀察內容發現有 date
和 time
字樣,因而能夠判斷這多是一個時間戳字符串
。
onclick="this.src= document.location.protocol +'//authcode.jd.com/verify/image?a=1&acid=dcb4370b-2763-44e6-83ff-4b89bc01193d&uid=dcb4370b-2763-44e6-83ff-4b89bc01193d&yys='+new Date().getTime();$('#authcode').val('');"
複製代碼
小提示:
時間戳(引自百度百科):
時間戳是指格林威治時間1970年01月01日00時00分00秒(北京時間1970年01月01日08時00分00秒)起至如今的總秒數。
時間戳在Python中能夠用time模塊
來完成:
time.time()*1000
複製代碼
jpg
格式,儲存在項目文件目錄下。能夠看到圖片就在目錄下,咱們雙擊打開而後按照圖片輸入驗證碼。
def login(self):
data = self.get_login_info()
headers = {
'Referer': self.post_url,
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36'
' (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
try:
login_page = self.session.post(self.post_url, data=data, headers=headers)
print(login_page.text)
except Exception as e:
print(e)
複製代碼
https://passport.jd.com/uc/loginService
"S"
是大寫。若是登陸成功,則會顯示如下字符串。
({"success":"http://www.jd.com"})
複製代碼
爲了驗證登陸真的成功了,現將博主的購物車拿出來作實驗,若是在獲取源碼中找到了指定商品名稱,那麼就說明成功了。
好吧,都是以前隨便放的,就以牙線
爲測試目標吧。
def shopping(self):
carshop = self.session.post('https://cart.jd.com/cart.action', headers=self.headers)
print(carshop.text)
複製代碼
簡單的請求了一下購物車url
。在下載的源碼中搜索「牙」
,而後找了目標。
本篇主要介紹了京東商城的模擬登陸方法,固然還有一些網站的登陸機制比較複雜,好比weibo
登陸須要調用api
,須要咱們詳細閱讀api說明。
後續將會分享更多模擬登陸的內容,歡迎你們指正。
參考連接: https://github.com/xchaoinfo/fuck-login http://blog.csdn.net/weixin_38206454/article/details/78655209?locationNum=2&fps=1
關注微信公衆號Python數據科學,獲取 120G
人工智能 學習資料。