Python爬蟲實戰之(四)| 模擬登陸京東商城

做者:xiaoyuhtml

微信公衆號:Python數據科學git

知乎:Python數據分析師github


前兩篇和你們分享了爬蟲中http的一些概念和使用方法,基礎篇咱們主要介紹了http的請求頭,高級篇咱們主要介紹了cookiesession(具體能夠點擊上面連接進行回顧)。但其實在爬蟲中還有不少關於http的內容須要瞭解,例如 tokenoauth等。對於這些概念博主將在後續文章中逐一的詳細介紹,本篇主要針對前兩篇內容與你們分享一個模擬登陸的實戰例子。算法

開始想以知乎爲例,可是看到網上關於知乎模擬登陸的教程太多了,因此就以「京東」爲例。api

你們都知道,京東是不須要登陸就能夠訪問主頁內容的,所以模擬登陸的意義在於查看我的信息,好比能夠獲取我的的交易信息(購物車商品,購物歷史記錄,待收貨商品信息等),或者賣家的商品銷售信息和評論等等。瀏覽器

好了,瞭解背景事後,讓咱們開始模擬登陸吧。安全

準備工做

你們都知道,模擬登陸其實就是經過http的post請求方式來提交用戶信息的(用戶名和密碼)。對於瀏覽器而言,只輸入用戶名和密碼就能夠登錄了(偶爾有驗證碼),那是由於瀏覽器在背後都幫你處理好了。而爬蟲的模擬登陸過程須要咱們本身解決,所以咱們須要弄清楚瀏覽器的那些背後操做是如何進行的才能對症下藥。bash

難點分析:服務器

  • 尋找提交表單所需字段信息
  • cookie信息的獲取和使用
  • 驗證碼的處理

咱們打開瀏覽器,博主用的Chrome瀏覽器。首先使用Ctrl+Shift+N進入乾淨的無痕模式,防止以前的cookie數據形成干擾。微信

輸入了京東的登錄網址 passport.jd.com/new/login.a…,進入以下登陸界面。

表單字段信息

如今咱們經過開發者工具來看看瀏覽器背後都幹了什麼吧。有的朋友提問到,輸入用戶名和密碼後頁面直接跳轉到主頁面了,看不到咱們要的數據了。其實這裏只須要故意將你的密碼輸錯不進入跳轉就能夠解決了。

點擊登陸,而後咱們看到有個FormData,這就是瀏覽器每次向服務器提交的表單信息。

第一眼看過去感受快要無望了。可是彆着急,這些字段信息其實都是有處可尋的。咱們Ctrl+U打開京東登陸頁面的源碼裏,而後Ctrl+F 試着搜一搜這些字段信息。

先搜第一個uuid字段,發現它就在源碼中,緊着後面是一些其它的字段信息,那就齊活了。咱們看到除了loginname,nloginpwd,authcode,其餘的字段全都是hidden的類型,也就是被隱藏了的字段。

好了,那下一步就天然知道幹什麼了。咱們能夠直接請求登陸頁面源碼提取字段信息了。

Cookie的處理

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的類,設置了實例的headerssession會話對象,以及三個後面請求須要用到的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字段進行表單提交完成登陸。
  • 若是爲false則不須要驗證碼,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的時候會發現圖片並無下載成功,爲何呢?

由於還須要在結尾加上時間戳,接着看後邊的 onclick,它的字符串中有和src2徹底同樣的連接,但在結尾處多了 &yys= ''。經過觀察內容發現有 datetime 字樣,因而能夠判斷這多是一個時間戳字符串

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)
複製代碼
  • 根據獲取的表單登陸信息進行提交登陸。
  • 請求的url是 https://passport.jd.com/uc/loginService
  • 注意這裏的 Service 中的 "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。在下載的源碼中搜索「牙」,而後找了目標。

代碼連接:github.com/xiaoyusmd/j…

總結

本篇主要介紹了京東商城的模擬登陸方法,固然還有一些網站的登陸機制比較複雜,好比weibo登陸須要調用api,須要咱們詳細閱讀api說明。

後續將會分享更多模擬登陸的內容,歡迎你們指正。

參考連接: https://github.com/xchaoinfo/fuck-login http://blog.csdn.net/weixin_38206454/article/details/78655209?locationNum=2&fps=1


關注微信公衆號Python數據科學,獲取 120G 人工智能 學習資料。

相關文章
相關標籤/搜索