為爬蟲獲取登入cookies:使用萬能鑰匙 Selenium 搞定一切登入

王平發表於2018-12-03

Selenium, 大名鼎鼎的Web自動化測試工具,可以跨越Linux、Windows、macOS等平臺使用,支援Java、Python、C#、Ruby等多種語言程式設計,為Web系統自動化測試帶來強大支援。通過WebDriver方便操作瀏覽器,這也給爬蟲界帶來十分的便利。它可以被稱為爬蟲登入的萬能鑰匙,可以橫掃一切網站的登入。

Selenium使用

如果說,完全用Python程式碼模擬登入是我們智力的體現,那麼選擇 Selenium 就是我們的智慧所在。沒辦法,用它就是一個字兒:倍兒爽!

1. Selenium 登入獲取cookies的流程

利用這把萬能鑰匙的流程大致如下:

  1. 使用Selenium WebDriver 開啟瀏覽器;
  2. 如果沒有驗證碼,可以通過程式碼輸入使用者名稱和密碼並點選登入按鈕;如果需要人工輸入變態的驗證碼,就讓WebDriver sleep一定時間,等待人工輸入完成;
  3. 登入後獲取cookies,並儲存到檔案或資料庫。

如果上述過程是不需要人工輸入驗證碼的,可以使用 Headless Chrome ,它能在無桌面環境下執行,比如Linux 伺服器上一般是沒有安裝桌面環境的。

獲取cookies以後,我們可以繼續用webdriver抓取資料頁面,這適合於非同步載入的頁面的抓取;或者把cookies匯入到requests的session,利用requests抓取資料頁面,這適合於非非同步載入的頁面。

2. Selenium 登入的實現

按照上面的思路,我們實現兩個登入的過程,一個需要驗證碼,一個不需要驗證碼。

不需要人工輸入驗證碼的登入:

def login_auto(login_url, username, password,
               username_xpath, password_xpath,
               submit_xpath, cookies_file, browser=None):
    if browser is None:
        options = webdriver.ChromeOptions()
        # chrome在系統PATH時,可以不指定 binary_location 
        # options.binary_location = ‘/usr/bin/google-chrome’
        options.add_argument('headless')
        options.add_argument('window-size=1200x600')
        browser = webdriver.Chrome(chrome_options=options)
    browser.maximize_window()
    browser.get(login_url)
    time.sleep(9) # 等登入載入完成
    browser.find_element_by_xpath(username_xpath).send_keys(username)
    browser.find_element_by_xpath(password_xpath).send_keys(password)
    browser.find_element_by_xpath(submit_xpath).send_keys(Keys.ENTER)
    time.sleep(9) # 等登入載入完成
    cookies = browser.get_cookies()
    print(cookies)
    save_cookies(cookies, cookies_file)

這個login_auto()函式,使用了headless的chrome,最大化視窗的目的是讓整個頁面都顯示出來,如果預設大小,微博登入頁面就不顯示登入輸入框,自動填寫使用者名稱時會儲存。

sleep的目的是等待載入登入頁面完成,還是微博,它的登入跳轉比較費時間,不能一下子載入完成,必須等待。

登入完成我們就可以得到cookies了。通過webdriver的get_cookies()得到的cookies是一個列表,每個元素是一個字典,包含了domain, expiry, name, value等等欄位。

最後我們把得到的cookies儲存為檔案,這裡用pickle直接序列化到硬碟,這個cookies就可以被爬蟲使用抓取資料了。

需要人工輸入驗證碼的登入

def login_manually(login_url, cookies_file, browser=None):
    # 既然是手動,這裡就不自動填寫使用者名稱和密碼了
    if browser is None:
        browser = webdriver.Chrome()
    browser.get(login_url)
    time.sleep(30) # 給自己多了點時間輸入使用者名稱、密碼、驗證碼
    cookies = browser.get_cookies()
    print(cookies)
    save_cookies(cookies, cookies_file)

需要人工介入的登入,就是讓程式自動開啟一個瀏覽器,然後人工輸入登入資訊完成登入,最後程式儲存cookies的過程。

這裡可不能用headless的Chrome哦,不然你看不到瀏覽器視窗無法輸入,哈哈哈~

當然,你也可以讓程式自動填寫使用者名稱、密碼,類似login_auto()那樣實現,小猿們有興趣的話可以新增這部分功能。

3. Selenium 登入後的cookies的使用

用Selenium儲存的cookies,可以繼續給WebDriver使用,去抓取複雜的非同步載入(AJAX)的網頁,也可以給requests使用快速載入非非同步頁面。為此,我們實現兩個不同的載入函式:

載入cookies到WebDriver

def load_to_browser(cookies_file, browser=None):
    with open(cookies_file, 'rb') as f:
        cookies = pickle.load(f)
    if browser is None:
        browser = webdriver.Chrome()
    for cookie in cookies:
        browser.add_cookie(cookie)
    return browser

儲存時用的是pickle序列化到硬碟,讀取到記憶體時同樣使用pickle, 把cookies放入WebDriver很簡單,把cookies逐個用add_cookie()放入即可。

載入cookies到requests的session

requests的cookies是用RequestsCookieJar這個類管理的,它的結構和WebDriver 的cookies不太一樣,它只需要name, value即可,所以載入到requests有些不同:

def load_to_requests(cookies_file, session=None):
    with open(cookies_file, 'rb') as f:
        cookies = pickle.load(f)
    if session is None:
        session = requests.Session()
    for cookie in cookies:
        session.cookies.set(cookie['name'], cookie['value'])

4. Selenium 登入實戰: 微博、嗶哩嗶哩、知乎的登入

微博有時候是不需要輸入驗證碼的,此時就可以自動化登入。幸運的是,我的賬號在我機器上就不需要輸入驗證碼,省的我費勁去找一個不需要驗證碼的網站(現如今真的很難找啊~)
好了,看程式碼:

login_url = 'https://weibo.com/'
username_xpath = '//input[@id="loginname"]'
password_xpath = '//input[@name="password"]'
submit_xpath = '//a[@action-type="btn_submit"]'
username = 'your-username'
password = 'your-password'
login_auto(login_url, username, password, username_xpath, password_xpath, submit_xpath, 'z-weibo.cookies')
 ```

而嗶哩嗶哩、知乎都需要手動解鎖驗證碼,那我們就用人工介入的模式登入:
```python
login_url = 'https://passport.bilibili.com/login'
login_manually(login_url, 'z-bilibili.cookies')

借用login_manually()函式是不是非常的簡單,同樣的知乎的也很簡單:

login_url = 'https://passport.bilibili.com/login'
login_manually(login_url, 'z-zhihu.cookies')

出乎意料的是,登入知乎出現了問題,報了一個錯誤:Missing argument grant_type。網上有人說是Chrome版本問題,降低版本後就可以了。

猿人學banner宣傳圖

我的公眾號:猿人學 Python 上會分享更多心得體會,敬請關注。

***版權申明:若沒有特殊說明,文章皆是猿人學 yuanrenxue.com 原創,沒有猿人學授權,請勿以任何形式轉載。***

相關文章