爬蟲實戰(二):Selenium 模擬登陸並爬取信息

前敘

系列文章:php

爬蟲實戰(一):爬取微博用戶信息html

爬蟲實戰(二):Selenium 模擬登陸並爬取信息html5

爬蟲實戰(三):微博用戶信息分析python

該系列文章介紹了什麼?linux

1.爬蟲分析和處理方法git

2.Python中的數據庫操做方法github

3.Selenium瀏覽器自動化以及無頭瀏覽器使用方法web

4.對數據進行詞雲分析的方法正則表達式

5.對數據進行可視化的方法chrome

6.LDA隱含狄利克雷分佈模型的建模和使用方法

前言

前一篇文章 爬蟲實戰(一):爬取微博用戶信息 中爬取的是 weibo.cn 這個網頁,可是因爲該網頁缺乏維護,微博官方可能加了一些限制,致使稍微頻繁一點的訪問都會報 403 錯誤,加上每次手動獲取 cookies 也比較麻煩,不友好,因此針對這些狀況,我使用了一種新的抓取方式,也是一種更爲高級的爬蟲手段。

我以前在文章裏面提到「 爬取微博主頁 weibo.com/ 或者 m.weibo.cn/ 較爲困難 」,爲何會這麼說呢?由於這兩種頁面較新,因此採用的技術比較新穎,反爬措施作得要好一些。特別是它們採用了滾動式頁面,每次向下滾動到底後會加載出新的內容,這種動態加載模式使得傳統的改變網頁地址中的頁碼得到相應內容的方法失效了,含有用戶信息內容的源碼須要抓包獲取,或者直接操做瀏覽器獲取。後者通常都是Selenium+PhantomJS來實現。

因爲 Phantom.js 的維護者 Slobodin 在Google論壇上發帖表示,鑑於Chrome 59推出了無頭瀏覽特性,他認爲「Chrome比PhantomJS更快,更穩定」,沒有理由再繼續維護Phantom.js(開發者頗有自知之明:P,不過 Phantom.js 確實是一個很好用的東西),因此本文采用 Selenium+Chrome/Firefox 無頭瀏覽器的方式進行模擬登陸和抓取用戶動態信息的操做。

Selenium

Selenium 是一個瀏覽器自動化測試框架,起初是爲了自動化測試開發的,在爬蟲流行起來之後,也成爲了一種爬蟲的工具。它的功能簡單來講就是能夠控制瀏覽器,用代碼模擬人對瀏覽器的操做,實現自動化。

安裝

和大多數 python 包同樣,selenium 可使用 pip 進行安裝:

# python 2
pip install selenium

# python 3
pip3 install selenium
複製代碼

由於 selenium 是對瀏覽器進行控制,因此首先要裝對應的驅動(driver),Selenium 針對幾個主流的瀏覽器都有相應的官方 driver。讀者能夠根據本身的狀況下載並安裝。好比筆者是使用的 Linux 系統上的 Chrome 瀏覽器最新版本,那麼便下載相應版本的 driver ,下載完成之後,執行命令:

#/usr/bin 或者 /usr/local/bin
sudo cp 下載的driver位置 /usr/bin
sudo chmod +x /usr/bin/chromedriver
複製代碼

安裝完成之後測試一下是否成功。

測試

首先來測試一下是否安裝成功:

from selenium import webdriver
 
browser = webdriver.Chrome()
browser.get('http://www.baidu.com/')
複製代碼

運行這段代碼,會自動打開瀏覽器訪問百度。

若是程序執行錯誤,瀏覽器沒有打開,那麼多是沒有裝 Chrome 瀏覽器或者 Chrome 驅動沒有配置在環境變量裏或者驅動和瀏覽器版本不匹配。

模擬登陸

登陸微博須要使用驗證碼,自動識別驗證碼這一塊我研究了一下,使用圖像識別,也不難,可是由於咱們能夠將cookies 持久化保存下來,使用手動輸入驗證碼並不麻煩,因此自動識別驗證碼能夠暫時先放一放,後面慢慢來研究。

使用 selenium 控制瀏覽器,經過對頁面的元素進行定位來模擬人的操做,API 詳細介紹請見 參考文檔 。模擬登陸代碼以下:

def get():
    conf, engine = Connect('conf.yaml')  # 獲取配置文件的內容
    loginname = conf.get('loginname')
    password = conf.get('password')

    loginname = list(loginname.values())
    password = list(password.values())
    with open('cookies.pkl', 'wb') as f:
        for i in range(len(password)):  # 將每一個帳號的cookies保存下來.
            try:
                driver = webdriver.Chrome()
                driver.set_window_size(1124, 850)  # 防止獲得的WebElement的狀態is_displayed爲False,即不可見
                driver.get("http://www.weibo.com/login.php")
                time.sleep(5)
                #自動點擊並輸入用戶名
                driver.find_element_by_xpath('//*[@id="loginname"]').clear()
                driver.find_element_by_xpath('//*[@id="loginname"]').send_keys(loginname[i])
                driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[2]/div/input').clear()

                time.sleep(2)
                #自動點擊並輸入登陸的密碼
                driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[2]/div/input').send_keys(
                    password[i])
                driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[6]/a').click()
				
                #輸入驗證碼
                driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[3]/div/input').send_keys(
                    input("輸入驗證碼: "))

                time.sleep(1)
                driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[6]/a').click()
            except Exception as e:
                print("驗證碼輸入錯誤,請從新輸入!")
                driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[3]/div/input').send_keys(
                    input("輸入驗證碼: "))
                time.sleep(1)
                driver.find_element_by_xpath('//*[@id="pl_login_form"]/div/div[3]/div[6]/a').click()
            cookies = driver.get_cookies()
            pickle.dump(cookies, f)#序列化cookies對象
複製代碼

代碼註釋應該寫得比較清楚,其中有一個細節就是咱們須要將獲取的 cookies 序列化。什麼是序列化?

咱們把變量從內存中變成可存儲或傳輸的過程稱之爲序列化,即把數據寫入臨時或持久性存儲區,而把變量內容從序列化的對象從新讀到內存裏稱之爲反序列化。

意思是在這裏將 cookies 以二進制形式保存下來,這樣能夠方便後續爬蟲使用。

使用 selenium 爬取用戶信息

爬取用戶信息的大體思路和上一篇文章 爬蟲實戰(一):爬取微博用戶信息 差很少 ,但仍然有如下區別:

  • 爬取 https://m.weibo.cn/ 而不是 https://weibo.cn/
  • 使用 seenium 代替 requests 獲取源碼
  • 使用 selenium 加載滾動頁面直到全部動態信息加載完成
  • 先使用正常的Chrome調試,調試完成之後再改爲無頭瀏覽器

首先咱們來看微博 html5 移動端的頁面長什麼樣:

weibo3-1.png

爲何選這個網址而不是PC端的頁面呢?由於PC端的頁面每向下滑動三次須要跳頁,操做要繁瑣一些,並且 selenium 容易由於失去焦點致使跳轉失敗,我也沒找到很好的解決方法,而 html5 移動端的頁面屢次滑動到底即可以得到全部動態信息,不須要跳頁,因此要簡單不少。

再來看看使用 selenium 如何操做瀏覽器滑動到底,下面是相關的處理函數,這個函數將 web 頁面滑動屢次直到沒法再滑動(即滑動到底了)並使用正則表達式提取出動態和動態發佈時間:

#獲取用戶全部動態信息和動態發佈時間並返回
def execute_times(driver):
    dynamic = []
    T = []
    d = re.compile(r'og"><div class="weibo-text">(.*?)<', re.S)  # 匹配動態
    t = re.compile(r'<span class="time">(.*?)<', re.S)  # 匹配動態發佈時間
	
	#返回滾動高度
    last_height = driver.execute_script("return document.body.scrollHeight")

    while True:
        # 滑動一次
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

        # 等待加載
        time.sleep(random.random())

        # 計算新的滾動高度並與上一個滾動高度進行比較
        new_height = driver.execute_script("return document.body.scrollHeight")
        if new_height == last_height:
            break
        last_height = new_height

    html = driver.page_source

    dynamic += re.findall(d, html)
    T += re.findall(t, html)
    return dynamic, T #返回用戶全部動態信息和動態發佈時間列表
複製代碼

獲得用戶全部動態信息和動態發佈時間列表之後,其餘處理和前一篇文章相似,在此再也不累述,詳情請見源碼 weibo_spider.py

由於每次運行程序都須要彈出瀏覽器窗口,並且速度較慢,因此能夠將瀏覽器設置成無頭模式:

#Chrome
opt = webdriver.ChromeOptions()  # 建立chrome參數對象
opt.set_headless()  # 把chrome設置成無頭模式,不論windows仍是linux均可以,自動適配對應參數
driver = webdriver.Chrome(options=opt)#不制定options選項則是普通有頭瀏覽器

#Firefox
opt = webdriver.FirefoxOptions()  
opt.set_headless() 
driver = webdriver.Firefox(options=opt)
複製代碼

至此模擬登陸並爬取信息方法介紹完畢。

源碼地址:https://github.com/starFalll/Spider

相關文章
相關標籤/搜索