天天看點

【爬蟲學習4】Python爬取動态頁面思路(二)運用selenium爬取知乎timeline動态加載内容

運用selenium爬取知乎timeline動态加載内容

在前之前文章中嘗試用簡單的Requests爬取知乎timeline時發現動态加載内容無法成功爬取,嘗試分析資料包來爬取也沒有成功,于是最後在這裡使用selenium來嘗試,終于成功。

全部代碼見于我的Git

selenium思路

網上關于selenium的教程有很多,也很詳細,但還是推薦看官方文檔,單就爬蟲而言,看完官方文檔的example夠用了。

使用selenium的思路就是利用selenium對浏覽器的操作,模拟人下拉頁面,進而讓網站實作動态加載。

首先要使用selenium必須安裝對應浏覽器的webdriver,官方文檔1.3節中有相應說明,由于一些原因,在這裡使用的是Microsoft edge浏覽器,edge的webdriver與其他幾家不同,下載下傳下來是個exe檔案,需要放到path中存在的檔案夾中才能順利杯selenium調用,我選擇的是放在python檔案夾中。

對于模拟人下拉頁面,主要思路是,擷取滾動條的高度,然後讓滾動條的深度=高度,于是滾動條到底了,觸發頁面動态加載。

def down_page(driver, times):
    for i in range(, times+):
        driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
        time.sleep()
           

實際上是在selenium中使用的javascript來對浏覽器進行操作。

driver是通過webdriver.Edge()建立的drivers對象

times是向下滑動的次數

execute_script()是使用javascript腳本進行

使用方法如下:

def main():
    url = 'https://www.zhihu.com'
    driver = webdriver.Edge()
    driver.get(url)
    down_page(driver, )
    html = driver.page_source
           

幾個要點

雖然參考了許多資料,但是還是遇到了許多問題,這裡進行一下記錄與說明。

注意cookies

selenium對cookies的儲存方式與requests不同:

requests是直接以字典形式存儲:

{'name':'value','name':'value'}
           

selenium則是以字典清單存儲,其中每個字典存儲一對name:value,形式為

[
    {'name':'namedata', 'value':'valuetat', 'path':'pathdata', 'domain':'domaindata', 'expiry': number, 'secure': False/Truse, 'httpOnly': False/Truse},
    {'name':'namedata', 'value':'valuetat', 'path':'pathdata', 'domain':'domaindata', 'expiry': number, 'secure': False/Truse, 'httpOnly': False/Truse},
]
           

是以,若想用driver.add_cookies()加入cookies需要先通過driver.get_cookies()獲得path、domain等内容再去建構cookies。

在這裡,因為edge的webdriver本身保留之前的cookies記錄,是以隻要之前在爬取前登入一次網頁即可。

(網上有說selenium打開的視窗是全新的無cookies,可能在Firefox或者Chrome上存在,Edge不存在這個困擾)

擷取網頁代碼

對網頁代碼的擷取使用的是

html = driver.page_source
           

這個方法和requesrs.get()所擷取的頁面代碼是有差別的(更詳細)是以正規表達式得重寫。

自動登入

嘗試過進行自動登入,碰到了三個問題:

1.網上可查到的删除cookies的方法delete_all_cookies()和delete_cookie()是錯誤的,準确的說不是錯的,而是這個方法在selenium中是用在Remote WebDriver中的,本地使用并沒有删除cookie的方法。

猜想:都在本地了,自己在程式運作之前手動删一下,不就成了?

2.如果浏覽器已經 儲存密碼 了,那麼以下代碼會出現問題:

account = driver.find_element_by_name('account')
password = driver.find_element_by_name('password')
account.clear()
password.clear()
time.sleep()
account.send_keys('account') #換成自己賬号
password.send_keys('password')  #換成自己密碼
           

問題在于 即使你清除了文本内容,隻要你send_keys,浏覽器就會自動填充密碼,于是你再填充一次密碼,在密碼欄中就填了兩遍密碼,明顯會密碼錯誤。

删除浏覽器記錄的密碼,或者幹脆去掉password.send_keys語句

3.知乎的倒立漢字驗證碼真的很煩。。。。

怎麼解決這個問題,查了一些資料,還在研究,但是并不影響本次程式的正常運作,是以留待下篇文章再說

自動登入代碼(無驗證碼、無自動填充密碼):

from selenium import webdriver
import time

def login(driver):
    time.sleep()
    driver.find_element_by_link_text('登入').click()
    time.sleep()
    driver.find_element_by_class_name('signin-switch-password').click()
    time.sleep()
    account = driver.find_element_by_name('account')
    password = driver.find_element_by_name('password')
    account.clear()
    password.clear()
    time.sleep()
    account.send_keys('account') #換成自己賬号
    password.send_keys('password')  #換成自己密碼
    time.sleep()
    driver.find_element_by_class_name('sign-button submit').click()

def main():
    url = "http://www.zhihu.com"
    driver = webdriver.Edge()
    driver.get(url)
    try:
        driver.find_element_by_link_text('登入')
    except Exception as e:
        print('已經登入')
    else:
        login(driver)

    cookie = driver.get_cookies()
    print(cookie)

if __name__ == '__main__':
    main()
           

這裡,因為selenium中get element語句隻要沒有獲得結果就會報錯,是以不能用if判斷,必須用try語句。