Selenium+Python自動更新知乎首頁內容

最近刷知乎比較多,但是發現一個問題,相信很多人都會感覺到,知乎首頁的內容大量重複,雖然關注了很多話題,但首頁顯示的問題或文章總是那麼幾個,刷也刷不出新內容。雖然刷知乎就是圖個新奇好玩,但刷知乎也看不到新內容,那就很無聊了。不管知乎的推薦演算法工程師是怎麼想的,至少對我來說,這很困擾。

雖然首頁的問題邊上有個小叉叉,但我試了,手工點很多次會很累,而且還不太管用,還是會推薦相同的內容,可能是點的次數還是太少。所以我就想了讓程序自己去點這個叉叉,確實還有點效果。點幾千次,幾萬次之後,首頁的內容會有些變化。

實現的方法也很簡單,就是Selenium+Python,Selenium是一個網頁測試框架,可以拿來模擬用戶的瀏覽行為,所以干這事兒小菜一碟。

Selenium需要配合webdriver使用, Firefox, Chrome, IE都可以,電腦上要安裝相應的瀏覽器,好像還可以用無頭瀏覽器phantomJS, 沒試過,我這裡是用的Chrome, 系統Ubuntu16.04. 曾經在Windows上試過Firefox和Chrome,都是類似的,很方便。

下面簡單講下基本步驟:

1.安裝Selenium

sudo pip install selenium

2. 下載chromedriver

直接去Google 下載(翻牆自己解決),這是鏈接sites.google.com/a/chro

接下來就是寫腳本了,一步一步來。

3. 導入模塊

#coding:utf-8from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECimport time

除了第一個導入webdriver, 其他的是一些輔助功能,簡單粗暴的話可以不要。time模塊是為了實現等待頁面載入。

4.打開瀏覽器

driver = webdriver.Chrome(/home/bing/Downloads/chromedriver)

括弧里的是剛剛下載的chromedriver的位置。

現在driver就等於是一個瀏覽器。

如果腳本里只包含以上內容,運行的話,會自動彈出一個Chrome窗口,空白頁。

5.打開知乎登錄頁面

driver.get(https://www.zhihu.com#signin)

可以看到括弧里的就是這個知乎登錄頁面。(退出後可見)

6.輸入用戶名,密碼,點登錄

name = driver.find_element_by_name(account)name.send_keys(這裡填用戶名)passwd = driver.find_element_by_name(password)passwd.send_keys(這裡填密碼)submit = driver.find_element_by_tag_name(button)submit.click()

find_element_by_name是找到頁面上這個元素,有很多方法,可以by_class_name, by_id, by_css_selector, by_xpath等。

在瀏覽器里看到的輸入方框上,滑鼠按右鍵,點「檢查」或者"Inspect",可以看到這兩個元素的html代碼

<input type="text" name="account" aria-label="手機號或郵箱" placeholder="手機號或郵箱" required=""><input type="password" name="password" aria-label="密碼" placeholder="密碼" required="">

找到填用戶名,密碼的框框後,send_keys會幫你填入。

之後找到登錄按鈕,這是一個button元素,所以就直接by_tag_name了。這是它的html頁面代碼。

<button class="sign-button submit" type="submit">登錄</button>

submit.click(),顧名思義,找到之後點擊,就這麼簡單。

7.找到所有的叉叉

這是檢查之後看到的這個元素的html代碼。

<a href="#" class="ignore zu-autohide" name="dislike" data-tooltip="s$b$不感興趣"></a>

其實找到它很容易:

chacha = driver.find_element_by_name(dislike)

或者很多個相同的元素,在element後加s:

chacha = driver.find_element_by_name(dislike)

這樣返回一個列表。要知道有多少個:

chacha.__len__()

我在嘗試的過程中,發現每頁的載入條數,第一頁是10,以後會是20,或者30。

不過這裡有個問題,從上一步點登錄,到找到叉叉,中間是有時間的,雖然一般感覺不到,但如果網速慢就會看到,叉叉不是立馬出現。這樣程序有可能找不到它,會出錯。Selenium設計了一個函數,可以讓程序在這個元素出現之後,再行動。

之前導入的幾個輔助模塊,就是這麼用的。

chacha = WebDriverWait(driver, 30).until( EC.presence_of_all_elements_located((By.NAME,dislike)))number = dislike.__len__()

這樣在30秒之內,找到叉叉元素都不會出錯。

8. 點擊所有的叉叉,並且關掉通知

點擊叉叉之後,我會繼續點擊通知上的叉叉:

這樣整個步驟就是先點不感興趣的叉叉,然後再點通知的叉叉,這樣整個條目就消失了,而我們需要整個頁面所有的條目消失,之前已經找到所有的條目數量,是number,我們循環操作number次就好了:

for i in range(number): chacha = WebDriverWait(driver, 30).until( EC.presence_of_element_located((By.NAME, dislike))) chacha.click() time.sleep(1) close = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CLASS_NAME, close))) close.click() time.sleep(1)

同樣也是用的智能等待,等元素出現之後再定位,點擊,不過一次只找一個,點一個。

因為Selenium是點擊人眼能看到的部分,所以雖然已經找到所有元素,但必須讓之後的條目出現在視野中才能點擊,所以我們需要這麼一個一個來。

中間加入的time.sleep(1),是讓程序等待一秒,再執行下面的操作,點擊叉叉之後,需要一個很短的時間通知才會出來。這個可以自己設置,0.3秒,3秒,都可以。

這樣執行number次之後,頁面上沒有條目,只剩下一個「更多」的按鈕。

9.點擊「更多」按鈕

如果是人在拉進度條,會出現:

這兩個是一樣的,沒關係。

不過我發現,有時需要點兩次,才會出現新內容,所以中間間隔一秒,點兩次:

more = driver.find_element_by_id("zh-load-more")more.click()time.sleep(1)more = driver.find_element_by_id("zh-load-more")more.click()

這個按鈕的id是』zu-load-more,by_id就可以定位,而且只有一個。click()點擊。

之後等待5秒,時間長短看網速:

time.sleep(5)

這樣就出現新的問題或文章了。重複以上步驟100次,1000次都可以。

我看了,大約100次差不多,可以換點口味。

當然最後的結果可能是熱門的問題都被點「不感興趣了」, 那就去關注新的話題吧,其實我最近在想關注所有話題會咋樣。

10.可能情況

有時會出現錯誤,也許是網頁載入問題,可以適當延長time.sleep()的時間,或增加條件判斷,那就更複雜化了。

結論:

可以看到,Selenium模仿人的瀏覽行為,是很簡潔的,如果懂一點HTML/CSS, JavaScript,組合起來使用,基本上所有網頁瀏覽行為都可以自動化。這裡只是展示了基本功能,還有很多高級功能,cookie, 執行JavaScript腳本,切換窗口,保存截圖等等,可以自己嘗試。另外,Selenium是一個獨立的工具,可以在很多語言上使用,Java, C#, Python, Ruby, Perl, PHP, JavaScript都有獨立的包。

完整代碼:

#coding:utf-8from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECimport timedriver = webdriver.Chrome(/home/bing/Downloads/chromedriver)driver.get(https://www.zhihu.com#signin) # 打開登錄頁面name = driver.find_element_by_name(account)name.send_keys(你的用戶名)passwd = driver.find_element_by_name(password)passwd.send_keys(你的密碼)submit = driver.find_element_by_tag_name(button)submit.click()for i in range(100): # 循環100頁 chacha = WebDriverWait(driver, 30).until( EC.presence_of_all_elements_located((By.NAME,dislike))) number = dislike.__len__() # 本頁叉叉數量 for i in range(num): chacha = WebDriverWait(driver, 30).until( EC.presence_of_element_located((By.NAME, dislike))) chacha.click() # 找到一個點一個 time.sleep(1) close = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CLASS_NAME, close))) close.click() # 點擊通知的叉叉 time.sleep(1) more = driver.find_element_by_id("zh-load-more") # 點擊「更多」 more.click() time.sleep(1) more = driver.find_element_by_id("zh-load-more") more.click() time.sleep(5) # 等待載入新問題

推薦閱讀:

有哪些應用場景適合用python的gevent來完成?
Python爬蟲簡易代理池
《機器學習實戰》學習總結(六)——支持向量機SVM(一)
從Python官方文檔中挖礦之List Comprehensions

TAG:Python | Selenium | 知乎 |