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 下載(翻牆自己解決),這是鏈接https://sites.google.com/a/chromium.org/chromedriver/downloads
接下來就是寫腳本了,一步一步來。
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="">
之後找到登錄按鈕,這是一個button元素,所以就直接by_tag_name了。這是它的html頁面代碼。
<button class="sign-button submit" type="submit">登錄</button>
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