運用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語句。