引言css
自從學習了爬蟲以後,天天不寫個小爬蟲爬爬小姐姐,都以爲渾身難受:html
小姐姐是挺好看的,只是身體日漸消瘦而已,多喝養分快線就好!python
抓多了發現有一些小網站很狡猾,居然搞起反爬蟲來了,不直接 生成數據,而是經過加載JS來生成數據,而後你打開Chrome瀏覽器的 開發者選項,而後你會發現Elements頁面結構和Network抓包抓包 返回的內容居然是不同的,Network抓包那裏居然沒有對應的數據, 本該是數據的地方,居然是JS代碼,好比煎蛋的妹子圖:git
對於我這種不會JS的安卓狗來講,不由感嘆:github
抓不到數據怎麼破,開始我還想着自學一波JS基本語法,再去模擬抓包 拿到別人的JS文件,本身再去分析邏輯,而後搗鼓出真正的URL,後來 仍是放棄了,有些JS居然他麼的是加密的,並且要抓的頁面那麼多, 每一個這樣分析分析到何時...web
後面意外發現有個自動化測試框架:Selenium 能夠幫咱們處理這個問題。 簡單說下這個東西有什麼用吧,咱們能夠編寫代碼讓瀏覽器:chrome
而後這個東西是不支持瀏覽器功能的,你須要和第三方的瀏覽器 一塊兒搭配使用,支持下述瀏覽器,須要把對應的瀏覽器驅動下載 到Python的對應路徑下:json
Chrome:sites.google.com/a/chromium.… FireFox:github.com/mozilla/gec… PhantomJS:phantomjs.org/ IE:selenium-release.storage.googleapis.com/index.html Edge:developer.microsoft.com/en-us/micro… Opera:github.com/operasoftwa…windows
直接開始本節的內容吧~api
這個就很簡單了,直接經過pip命令行進行安裝:
sudo pip install selenium
複製代碼
PS:想起以前公司小夥伴問過我pip在win上怎麼執行不了,又另外下了不少pip, 其實若是你安裝了Python3的話,已經默認帶有pip了,你須要另外配置下環境 變量,pip的路徑在Python安裝目錄的Scripts目錄下~
Path後面加上這個路徑就好~
由於Selenium是不帶瀏覽器的,因此須要依賴第三方的瀏覽器,要調用第三方 的瀏覽器的話,須要下載瀏覽器的驅動,由於筆者用到是Chrome,這裏就以 Chrome爲例子吧,其餘瀏覽器的自行搜索相關資料了!打開Chrome瀏覽器,鍵入:
chrome://version
複製代碼
能夠查看Chrome瀏覽器版本的相關信息,這裏主要是關注版本號就好了:
61,好的,接下來到下面的這個網站查看對應的驅動版本號:
chromedriver.storage.googleapis.com/2.34/notes.…
好的,那就下載v2.34版本的瀏覽器驅動吧:
chromedriver.storage.googleapis.com/index.html?…
下載完成後,把zip文件解壓下,解壓後的chromedriver.exe拷貝到Python 的Scripts目錄下。(這裏不用糾結win32,在64位的瀏覽器上也是能夠正常使用的!)
PS:Mac的話把解壓後的文件拷貝到usr/local/bin目錄下 Ubuntu的話拷貝到:usr/bin目錄下
接下來咱們寫個簡單的代碼來測試下:
from selenium import webdriver
browser = webdriver.Chrome() # 調用本地的Chrome瀏覽器
browser.get('http://www.baidu.com') # 請求頁面,會打開一個瀏覽器窗口
html_text = browser.page_source # 得到頁面代碼
browser.quit() # 關閉瀏覽器
print(html_text)
複製代碼
執行這段代碼,會自動調起瀏覽器,而且訪問百度:
而且控制檯會輸出HTML的代碼,就是直接獲取的Elements頁面結構, JS執行完後的頁面~接下來咱們就能夠來抓咱們的煎蛋妹子圖啦~
直接分析Elements頁面結構,找到想要的關鍵結點:
明顯這就是咱們抓取的小姐姐圖片,複製下這個URL,看下咱們打印出的 頁面結構有沒有這個東西:
能夠,很棒,有這個頁面數據,接下來就走一波Beautiful Soup獲取到咱們 想要的數據啦~
通過上面的過濾就可以拿到咱們的妹子圖片URL:
隨手打開一個驗證下,嘖嘖:
看了下一頁只有30個小姐姐,這顯然是知足不了咱們的,咱們在第一次加載 的時候先拿到一波頁碼,而後就知道有多少頁了,而後本身再去拼接URL加載 不一樣的頁面,好比這裏總共又448頁:
拼接成這樣的URL便可:http://jandan.net/ooxx/page-448 過濾下拿到頁碼:
接下來就把代碼補齊咯,循環抓取每一頁的小姐姐,而後下載到本地, 完整代碼以下:
import os
from selenium import webdriver
from bs4 import BeautifulSoup
import urllib.request
import ssl
import urllib.error
base_url = 'http://jandan.net/ooxx'
pic_save_path = "output/Picture/JianDan/"
# 下載圖片
def download_pic(url):
correct_url = url
if url.startswith('//'):
correct_url = url[2:]
if not url.startswith('http'):
correct_url = 'http://' + correct_url
print(correct_url)
headers = {
'Host': 'wx2.sinaimg.cn',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/61.0.3163.100 Safari/537.36 '
}
try:
req = urllib.request.Request(correct_url, headers=headers)
resp = urllib.request.urlopen(req)
pic = resp.read()
pic_name = correct_url.split("/")[-1]
with open(pic_save_path + pic_name, "wb+") as f:
f.write(pic)
except (OSError, urllib.error.HTTPError, urllib.error.URLError, Exception) as reason:
print(str(reason))
# 打開瀏覽器模擬請求
def browser_get():
browser = webdriver.Chrome()
browser.get('http://jandan.net/ooxx')
html_text = browser.page_source
page_count = get_page_count(html_text)
# 循環拼接URL訪問
for page in range(page_count, 0, -1):
page_url = base_url + '/page-' + str(page)
print('解析:' + page_url)
browser.get(page_url)
html = browser.page_source
get_meizi_url(html)
browser.quit()
# 獲取總頁碼
def get_page_count(html):
soup = BeautifulSoup(html, 'html.parser')
page_count = soup.find('span', attrs={'class': 'current-comment-page'})
return int(page_count.get_text()[1:-1]) - 1
# 獲取每一個頁面的小姐姐
def get_meizi_url(html):
soup = BeautifulSoup(html, 'html.parser')
ol = soup.find('ol', attrs={'class': 'commentlist'})
href = ol.findAll('a', attrs={'class': 'view_img_link'})
for a in href:
download_pic(a['href'])
if __name__ == '__main__':
ssl._create_default_https_context = ssl._create_unverified_context
if not os.path.exists(pic_save_path):
os.makedirs(pic_save_path)
browser_get()
複製代碼
運行結果:
看下咱們輸出文件夾~
是的,貼那麼多小姐姐,就是想騙你學Python!
PhantomJS沒有界面的瀏覽器,特色:會把網站加載到內存並執行頁面上的 JavaScript,由於不會展現圖形界面,因此運行起來比完整的瀏覽器要高效。 (在一些Linux的主機上沒有圖形化界面,就不能用有界面的瀏覽器了, 能夠經過PhantomJS來規避這個問題)。
Win上安裝PhantomJS:
Ubuntu/MAC上安裝PhantomJS:
sudo apt-get install phantomjs
複製代碼
!!!關於PhantomJS的重要說明:
在今年的四月份,Phantom.js的維護者(Maintainer)宣佈退出PhantomJS, 意味着這個項目項目可能不會再進行維護了!!!Chrome和FireFox也開始 提供Headless模式(無需吊起瀏覽器),因此,估計使用PhantomJS的小夥伴 也會慢慢遷移到這兩個瀏覽器上。Windows Chrome須要60以上的版本才支持 Headless模式,啓用Headless模式也很是簡單:
selenium官方文檔也寫了:
運行的時候也會報這個警告:
CSDN登陸網站:passport.csdn.net/account/log…
分析下頁面結構,不難找到對應的登陸輸入框,以及登陸按鈕:
咱們要作的就是在這兩個結點輸入帳號密碼,而後觸發登陸按鈕, 同時把Cookie保存到本地,後面就能夠帶着Cookie去訪問相關頁面了~
先編寫模擬登陸的方法吧:
找到輸入帳號密碼的節點,設置下本身的帳號密碼,而後找到登陸 按鈕節點,click一下,而後坐等登陸成功,登陸成功後能夠比較 current_url是否發生了改變。而後把Cookies給保存下來,這裏 我用的是pickle庫,能夠用其餘,好比json,或者字符串拼接, 而後保存到本地。如無心外應該是能拿到Cookie的,接着就利用 Cookie去訪問主頁。
經過add_cookies方法來設置Cookie,參數是字典類型的,另外要先 訪問get一次連接,再去設置cookie,否則會報沒法設置cookie的錯誤!
看下右下角是否變爲登陸狀態就能夠知道是否使用Cookie登陸成功了:
Seleninum做爲自動化測試的工具,天然是提供了不少自動化操做的函數, 下面列舉下我的以爲比較經常使用的函數,更多可見官方文檔: 官方API文檔:seleniumhq.github.io/selenium/do…
PS:把element改成elements會定位全部符合條件的元素,返回一個List 好比:find_elements_by_class_name
有時須要在頁面上模擬鼠標操做,好比:單擊,雙擊,右鍵,按住,拖拽等 能夠導入ActionChains類:selenium.webdriver.common.action_chains.ActionChains 使用ActionChains(driver).XXX調用對應節點的行爲
對應類:selenium.webdriver.common.alert.Alert,感受應該用得很少...
若是你觸發了某個時間,彈出了對話框,能夠調用下述方法得到對話框: alert = driver.switch_to_alert(),而後能夠調用下述方法:
切換窗口: driver.switch_to.window("窗口名") 或者經過window_handles來遍歷 for handle in driver.window_handles: driver.switch_to_window(handle) driver.forward() #前進 driver.back() # 後退
driver.save_screenshot("截圖.png")
如今的網頁愈來愈多采用了 Ajax技術,這樣程序便不能肯定什麼時候某個元素徹底 加載出來了。若是實際頁面等待時間過長致使某個dom元素還沒出來,可是你的 代碼直接使用了這個WebElement,那麼就會拋出NullPointer的異常。
爲了不這種元素定位困難並且會提升產生 ElementNotVisibleException的機率。 因此 Selenium 提供了兩種等待方式,一種是隱式等待,一種是顯式等待。
顯式等待:
顯式等待指定某個條件,而後設置最長等待時間。若是在這個時間尚未 找到元素,那麼便會拋出異常了。
from selenium import webdriver
from selenium.webdriver.common.by import By
# WebDriverWait 庫,負責循環等待
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions 類,負責條件出發
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.PhantomJS()
driver.get("http://www.xxxxx.com/loading")
try:
# 每隔10秒查找頁面元素 id="myDynamicElement",直到出現則返回
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
finally:
driver.quit()
複製代碼
若是不寫參數,程序默認會 0.5s 調用一次來查看元素是否已經生成, 若是原本元素就是存在的,那麼會當即返回。
下面是一些內置的等待條件,你能夠直接調用這些條件,而不用本身 寫某些等待條件了。
title_is title_contains presence_of_element_located visibility_of_element_located visibility_of presence_of_all_elements_located text_to_be_present_in_element text_to_be_present_in_element_value frame_to_be_available_and_switch_to_it invisibility_of_element_located element_to_be_clickable – it is Displayed and Enabled. staleness_of element_to_be_selected element_located_to_be_selected element_selection_state_to_be element_located_selection_state_to_be alert_is_present
隱式等待:
隱式等待比較簡單,就是簡單地設置一個等待時間,單位爲秒。
from selenium import webdriver
driver = webdriver.PhantomJS()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")
複製代碼
固然若是不設置,默認等待時間爲0。
driver.execute_script(js語句) 好比滾動到底部: js = document.body.scrollTop=10000 driver.execute_script(js)
本節講解了一波使用Selenium自動化測試框架來抓取JavaScript動態生成數據, Selenium需依賴於第三方的瀏覽器,要注意PhantomJS無界面瀏覽器過期的 問題,可使用Chrome和FireFox提供的HeadLess來替換;經過抓取煎蛋妹子 圖以及模擬CSDN自動登陸的例子來熟悉Selenium的基本使用,仍是收貨良多的。 固然Selenium的水仍是很深的,當前咱們可以使用它來應付JS動態加載數據頁面 數據的抓取就夠了。
最近天氣略冷,各位小夥伴記得適時添衣~ 另外這周由於事比較多,就先斷更了,下週再見,接下里要啃的骨頭是 Python多線程,目測得啃好幾節,敬請期待~
順道記錄下本身的想到的東西:
本節源碼下載:
本節參考文獻:
來啊,Py交易啊
想加羣一塊兒學習Py的能夠加下,智障機器人小Pig,驗證信息裏包含: Python,python,py,Py,加羣,交易,屁眼 中的一個關鍵詞便可經過;
驗證經過後回覆 加羣 便可得到加羣連接(不要把機器人玩壞了!!!)~~~ 歡迎各類像我同樣的Py初學者,Py大神加入,一塊兒愉快地交流學♂習,van♂轉py。