python爬蟲之selenium、phantomJs

圖片懶加載技術

什麼是圖片懶加載技術

圖片懶加載是一種網頁優化技術。圖片做爲一種網絡資源,在被請求時也與普通靜態資源同樣,將佔用網絡資源,而一次性將整個頁面的全部圖片加載完,將大大增長頁面的首屏加載時間。爲了解決這種問題,經過先後端配合,使圖片僅在瀏覽器當前視窗內出現時才加載該圖片,達到減小首屏圖片請求數的技術就被稱爲「圖片懶加載」。php

如何實現圖片懶加載技術

在網頁源碼中,在img標籤中首先會使用一個「僞屬性」(一般使用src2,original......)去存放真正的圖片連接而並不是是直接存放在src屬性中。當圖片出現到頁面的可視化區域中,會動態將僞屬性替換成src屬性,完成圖片的加載。css

如何破解圖片懶加載技術

其實很簡單,在對標籤屬性進行定位的時候,仔細觀察它真正的屬性進行提取。html

例如:python

import requests from lxml import etree def main(): responses = requests.get(url=url, headers=headers) coding = responses.apparent_encoding responses.encoding = coding res_text = responses.text # 建立etree對象 tree = etree.HTML(res_text) div_lst = tree.xpath('//div[@id="container"]/div') for one_div in div_lst: image_name = one_div.xpath('.//img/@alt')[0] image_url = one_div.xpath('.//img/@src2') print(image_name) print(image_url) if __name__ == '__main__': headers = {"User-Agent":'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0'} url = 'http://sc.chinaz.com/tupian/gudianmeinvtupian.html' main()

以上例子中就將src屬性換爲了src2屬性。jquery

selenium

1 什麼是Selenium?

selenium是Python的一個第三方庫,對外提供的接口能夠操做瀏覽器,而後讓瀏覽器完成自動化的操做。 
selenium最初是一個自動化測試工具,而爬蟲中使用它主要是爲了解決requests沒法直接執行JavaScript代碼的問題selenium本質是經過驅動瀏覽器,徹底模擬瀏覽器的操做,好比跳轉、輸入、點擊、下拉等,來拿到網頁渲染以後的結果,可支持多種瀏覽器。web

2 前期準備

selenium安裝就再也不概述了ajax

查看本身的谷歌瀏覽器版本正則表達式

查看本身對用的谷歌驅動: http://www.javashuo.com/article/p-wlhinbws-eo.html chrome

下載本身的谷歌驅動: http://chromedriver.storage.googleapis.com/index.htmlwindows

這裏我下載是:

而後加壓後把它放到python解釋器的scripts目錄中便可.

3 簡單示例
from selenium import webdriver from time import sleep # 啓動你的谷歌瀏覽 driver = webdriver.Chrome() # 用get方法打開百度首頁 driver.get('https://www.baidu.com') # 找到第一個連接標籤的文本並點擊 driver.find_elements_by_link_text('設置')[0].click() # 睡一秒 sleep(1) # 找到搜索設置並點擊 driver.find_elements_by_link_text('搜索設置')[0].click() sleep(2) # 找到id爲nr的標籤 ch = driver.find_element_by_id('nr') sleep(1) # 選擇第3個標籤點擊 # ch.find_element_by_xpath('//*[@id="nr"]/option[3]').click() ch.find_element_by_xpath('.//option[3]').click() sleep(2) # 保存設置 driver.find_elements_by_class_name("prefpanelgo")[0].click() sleep(2) # 處理彈出的警告 driver.switch_to_alert().accept() sleep(2) # 網搜索框裏傳入數據 driver.find_element_by_id('kw').send_keys('nba') sleep(2) # 點擊搜索按鈕 driver.find_element_by_id('su').click() sleep(2) # 關閉驅動 driver.close() # 關閉瀏覽器 driver.quit()

這是一個設置百度搜索每一個頁面顯示50條數據並搜索nba的程序

Selenium支持的瀏覽器很是多,如Chrome、Firefox、Edge等,還有Android、BlackBerry等手機端的瀏覽器。另外,也支持無界面瀏覽器PhantomJS,也就是後面要說的內容。

4 webdriver的元素定位
# 經過id屬性 find_element_by_id() # 經過name屬性 find_element_by_name() # 經過class的名字 find_element_by_class_name() # 經過標籤的名字 find_element_by_tag_name() # 經過連接標籤的文本 find_element_by_link_text() # 經過連接標籤的部分文本 find_element_by_partial_link_text() # 經過xpath find_element_by_xpath() # 經過css選擇器 find_element_by_css_selector() 注意: 1 find_element_by_xxx找的是第一個符合條件的標籤,find_elements_by_xxx找的是全部符合條件的標籤。 2 elenium還提供了通用方法find_element(),它須要傳入兩個參數:查找方式By和值。實際上,它就是find_element_by_id() 這種方法的通用函數版本,好比find_element_by_id(id)就等價於find_element(By.ID, id),兩者獲得的結果徹底一致。
5 對節點進行交互
# 經過id知道輸入框 input = browser.find_element_by_id('q') # 向裏面出入文本MAC input.send_keys('MAC') # 清楚文本框 input.clear() # 再傳入一個文本IPhone input.send_keys('IPhone') # 經過classname找到一個事件 button = browser.find_element_by_class_name('btn-search') # 點擊它 button.click()
6 動做鏈

什麼是動做鏈呢?

在節點交互中,交互動做都是針對某個節點執行的。好比對於輸入框,就調用它輸入和清空的方法,對於按鈕,就調用它點擊的方法,其實還有一些操做,它們沒有特定的執行對象,好比鼠標拖拽,鍵盤按鍵,它們使用另外一種方式來執行,就是動做鏈。

如下例子演示了把一個節點從一處拖動到另外一處:

from selenium import webdriver from time import sleep from selenium.webdriver import ActionChains driver = webdriver.Chrome() # 菜鳥教程的js演示代碼 url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable' driver.get(url) # 進入嵌套的頁面 driver.switch_to.frame('iframeResult') # 點位要拖動的標籤 start = driver.find_element_by_css_selector('.ui-draggable') # 拖動的目標標籤 end = driver.find_element_by_css_selector('.ui-droppable') # 建立一個鼠標事件 actions = ActionChains(driver) # 點擊要拖動的標籤不鬆動 sleep(1) actions.click_and_hold(start).perform() # 而後移動到另外一個標籤 actions.move_to_element(end).perform() # 往x軸移動40,y軸移動20 sleep(1) actions.move_by_offset(xoffset=40, yoffset=20).perform() # 釋放動做 actions.release()

可能有人會對driver.switch_to.frame('iframeResult')這句代碼有疑問

這個就是frame嵌套的。

在 web 應用中常常會出現 iframe 嵌套的應用,假設頁面上有 A、B 兩個 iframe,其中 B 在 A 內,那麼定位 B 中的內容則須要先到 A,而後再到 B。

因此咱們使用driver.switch_to.frame('iframeResult')直接進入嵌套的頁面。

 7 執行js

有些api是selenium沒有提供的,好比下拉進度條,可是能夠經過嗎模擬運行js來實現。

from selenium import webdriver from time import sleep driver = webdriver.Chrome() driver.get('https://www.jd.com/') # 移動到頁面最底部 driver.execute_script("window.scrollTo(0, document.body.scrollHeight)") sleep(2) # 執行alert123這個代碼 就是彈出123 driver.execute_script("alert('123')")

 這一塊自動化測試用的挺多的,想學自動化測試的同窗能夠多學習下。

8 獲取節點信息

經過page_source屬性能夠獲取網頁的源代碼,接着就可使用解析庫(如正則表達式、Beautiful Soup、pyquery等)來提取信息了。

selenium本身也提供了提取節點信息的方法,如屬性、文本等。這樣的話,咱們就能夠不用經過解析源代碼來提取信息了,很是方便。

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as E from selenium.webdriver.support.wait import WebDriverWait driver = webdriver.Chrome() # 訪問亞馬遜首頁 driver.get("https://www.amazon.cn/") # 顯示等待10秒 wait = WebDriverWait(driver, 10) # 判斷元素是否被加載到了dom中 wait.until(E.presence_of_element_located((By.ID,'cc-lm-tcgShowImgContainer'))) # 經過選擇器找到這個元素 tag=driver.find_element(By.CSS_SELECTOR,'#cc-lm-tcgShowImgContainer img') #獲取標籤屬性, print(tag.get_attribute('src')) #獲取標籤ID,位置,名稱,大小(瞭解) print(tag.id) print(tag.location) print(tag.tag_name) print(tag.size) driver.close()
9 延時等待

在selenium中,get()方法會在頁面框加載結束後,結束執行。此時若是得到get_source,可能不是瀏覽器徹底加載完成後的頁面,某些額外的js,ajax可能不必定獲取到,因此須要延時等待一下,確保節點加載出來了,這裏等待的方式有2中:顯式等待和隱式等待。

1 顯式等待

上個例子就用到了顯式等待,顯式等待會設置一個固定的等待時間,可是實際狀況是因爲外界因素的影響,咱們也不可能判斷出須要多少時間,全部顯示等待還有一種寫法,若是在規定時間加載出了這個節點,就對這個節點進行操做,若是沒有加載出,就拋出超時異常。

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support import expected_conditions as E from selenium.webdriver.support.wait import WebDriverWait driver = webdriver.Chrome() driver.get('https://www.baidu.com/') input_tag = driver.find_element_by_id('kw') input_tag.send_keys('美女') # 模擬鍵盤迴車鍵 input_tag.send_keys(Keys.ENTER) # 建立一個顯式等待 wait = WebDriverWait(driver, 10) # 等待直到加載出content_left(content是左半區) wait.until(E.presence_of_element_located((By.ID, 'content_left'))) content = driver.find_element(By.CSS_SELECTOR, "#content_left") print(content) driver.close()

若是將webDriverWait中的時間設置太低,會報錯:

2 隱式等待

當使用隱式等待執行測試的時候,若是Selenium沒有在DOM中找到節點,將繼續等待,超出設定時間後,則拋出找不到節點的異常。

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() # 設置隱式等待 driver.implicitly_wait(10) driver.get('https://www.baidu.com/') input_tag = driver.find_element_by_id('kw') input_tag.send_keys('NBA') # 模擬鍵盤迴車鍵 input_tag.send_keys(Keys.ENTER) content = driver.find_element(By.CSS_SELECTOR, "#content_left") print(content) driver.close()
 10 cookie

使用selenium還能夠對cookie進行操做,獲取,添加,刪除cookie:

from selenium import webdriver driver = webdriver.Chrome() driver.get('https://www.zhihu.com/explore') # 獲取cookie print(driver.get_cookies()) # 添加cookie driver.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'germey'}) print(driver.get_cookies()) # 刪除cookie driver.delete_all_cookies() print(driver.get_cookies())
[{'domain': '.zhihu.com', 'httpOnly': False, 'name': 'l_n_c', 'path': '/', 'secure': False, 'value': '1'}, {'domain': 'www.zhihu.com', 'expiry': 1555763561.220174, 'httpOnly': False, 'name': 'tgw_l7_route', 'path': '/', 'secure': False, 'value': '537a925d07d06cecbf34cd06a153f671'}, {'domain': '.zhihu.com', 'expiry': 1650370661.220268, 'httpOnly': False, 'name': 'q_c1', 'path': '/', 'secure': False, 'value': '9ca2467feeaa4987a63360951034c876|1555762662000|1555762662000'}, {'domain': 'www.zhihu.com', 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': '270095e8c0bc05224a3eb61674d59ce0'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220341, 'httpOnly': False, 'name': 'r_cap_id', 'path': '/', 'secure': False, 'value': '"ZjhkMmMxZWE5NjlhNDY3OWE4ODA1NjI4MjhkYzc0Y2Y=|1555762662|257a989723432c66a22d10794cd998b22d419794"'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220391, 'httpOnly': False, 'name': 'cap_id', 'path': '/', 'secure': False, 'value': '"NTY2OWZiYmI2ODdlNDFkZWE1MzBiZTEyYTQ5MDFmYzk=|1555762662|5c5e5d6a7150c0da99f86af9d85cc63cafbea752"'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220438, 'httpOnly': False, 'name': 'l_cap_id', 'path': '/', 'secure': False, 'value': '"Njk2NWI1ZTIxYjg2NGZhZDhiOGJiYjM5ODg0Y2U2ZmM=|1555762662|6a4e7d4ab33c72012e5bf133ffadfe34aa88b8eb"'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': 'n_c', 'path': '/', 'secure': False, 'value': '1'}, {'domain': '.zhihu.com', 'expiry': 1650370664.061236, 'httpOnly': False, 'name': 'd_c0', 'path': '/', 'secure': False, 'value': '"AJDm50C_Tg-PTkHkupcfIBQqf8xnPhGsu4M=|1555762665"'}, {'domain': '.zhihu.com', 'expiry': 1633522664.358119, 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': 'mzatpYVVTALiHdu45yqz9q4yljxCPZ7n'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '_zap', 'path': '/', 'secure': False, 'value': 'ec95407d-3b81-4e43-81d5-277adf4b33b9'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '__utma', 'path': '/', 'secure': False, 'value': '51854390.2113439272.1555762665.1555762665.1555762665.1'}, {'domain': '.zhihu.com', 'expiry': 1555764464, 'httpOnly': False, 'name': '__utmb', 'path': '/', 'secure': False, 'value': '51854390.0.10.1555762665'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': '__utmc', 'path': '/', 'secure': False, 'value': '51854390'}, {'domain': '.zhihu.com', 'expiry': 1571530664, 'httpOnly': False, 'name': '__utmz', 'path': '/', 'secure': False, 'value': '51854390.1555762665.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '__utmv', 'path': '/', 'secure': False, 'value': '51854390.000--|3=entry_date=20190420=1'}] [{'domain': '.zhihu.com', 'httpOnly': False, 'name': 'l_n_c', 'path': '/', 'secure': False, 'value': '1'}, {'domain': 'www.zhihu.com', 'expiry': 1555763561.220174, 'httpOnly': False, 'name': 'tgw_l7_route', 'path': '/', 'secure': False, 'value': '537a925d07d06cecbf34cd06a153f671'}, {'domain': '.zhihu.com', 'expiry': 1650370661.220268, 'httpOnly': False, 'name': 'q_c1', 'path': '/', 'secure': False, 'value': '9ca2467feeaa4987a63360951034c876|1555762662000|1555762662000'}, {'domain': 'www.zhihu.com', 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': '270095e8c0bc05224a3eb61674d59ce0'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220341, 'httpOnly': False, 'name': 'r_cap_id', 'path': '/', 'secure': False, 'value': '"ZjhkMmMxZWE5NjlhNDY3OWE4ODA1NjI4MjhkYzc0Y2Y=|1555762662|257a989723432c66a22d10794cd998b22d419794"'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220391, 'httpOnly': False, 'name': 'cap_id', 'path': '/', 'secure': False, 'value': '"NTY2OWZiYmI2ODdlNDFkZWE1MzBiZTEyYTQ5MDFmYzk=|1555762662|5c5e5d6a7150c0da99f86af9d85cc63cafbea752"'}, {'domain': '.zhihu.com', 'expiry': 1558354661.220438, 'httpOnly': False, 'name': 'l_cap_id', 'path': '/', 'secure': False, 'value': '"Njk2NWI1ZTIxYjg2NGZhZDhiOGJiYjM5ODg0Y2U2ZmM=|1555762662|6a4e7d4ab33c72012e5bf133ffadfe34aa88b8eb"'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': 'n_c', 'path': '/', 'secure': False, 'value': '1'}, {'domain': '.zhihu.com', 'expiry': 1650370664.061236, 'httpOnly': False, 'name': 'd_c0', 'path': '/', 'secure': False, 'value': '"AJDm50C_Tg-PTkHkupcfIBQqf8xnPhGsu4M=|1555762665"'}, {'domain': '.zhihu.com', 'expiry': 1633522664.358119, 'httpOnly': False, 'name': '_xsrf', 'path': '/', 'secure': False, 'value': 'mzatpYVVTALiHdu45yqz9q4yljxCPZ7n'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '_zap', 'path': '/', 'secure': False, 'value': 'ec95407d-3b81-4e43-81d5-277adf4b33b9'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '__utma', 'path': '/', 'secure': False, 'value': '51854390.2113439272.1555762665.1555762665.1555762665.1'}, {'domain': '.zhihu.com', 'expiry': 1555764464, 'httpOnly': False, 'name': '__utmb', 'path': '/', 'secure': False, 'value': '51854390.0.10.1555762665'}, {'domain': '.zhihu.com', 'httpOnly': False, 'name': '__utmc', 'path': '/', 'secure': False, 'value': '51854390'}, {'domain': '.zhihu.com', 'expiry': 1571530664, 'httpOnly': False, 'name': '__utmz', 'path': '/', 'secure': False, 'value': '51854390.1555762665.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)'}, {'domain': '.zhihu.com', 'expiry': 1618834664, 'httpOnly': False, 'name': '__utmv', 'path': '/', 'secure': False, 'value': '51854390.000--|3=entry_date=20190420=1'}, {'domain': 'www.zhihu.com', 'expiry': 2186482664, 'httpOnly': False, 'name': 'name', 'path': '/', 'secure': True, 'value': 'germey'}] []
 11 異常處理
from selenium import webdriver from selenium.common.exceptions import TimeoutException, NoSuchFrameException try: driver = webdriver.Chrome() driver.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable') driver.switch_to.frame('iframssseResult') except TimeoutException as e: print(e) except NoSuchFrameException as e: print(e) finally: driver.close()

超時等待哪裏就能夠這樣寫。

phantomJs

phantomJs是一款無界面的瀏覽器,其自動化操做流程和上面的谷歌瀏覽器是一致的。

因爲是無界面的,爲了可以展現自動化操做流程,PhantomJS爲用戶提供了一個截屏的功能,使用save_screenshot函數實現。

from selenium import webdriver import time # exe路徑 path = r'C:\phantomjs-2.1.1-windows\bin\phantomjs.exe' driver = webdriver.PhantomJS(path) driver.get("https://www.baidu.com") time.sleep(2) driver.save_screenshot(r'baidu.png') my_input = driver.find_element_by_id('kw') my_input.send_keys('nba') driver.save_screenshot(r'nba.png') # 查找搜索按鈕 button = driver.find_elements_by_class_name('s_btn')[0].click() time.sleep(3) driver.save_screenshot(r'show.png') driver.close() driver.quit()

 使用selenum+phantomJs能夠解決某些網頁js動態加載問題。

selenium+phantomJs爬取豆瓣電影的電影信息

 首先來看下這個頁面:https://movie.douban.com/typerank?type_name=%E6%81%90%E6%80%96&type=20&interval_id=100:90&action=

查看他的網頁源代碼:發現它是js動態加載顯示的

from selenium import webdriver import time def main(): path = r'C:\phantomjs-2.1.1-windows\bin\phantomjs.exe' driver = webdriver.PhantomJS(path) driver.get(url) time.sleep(2) driver.save_screenshot(r'1.png') driver.execute_script('window.scrollTo(0,document.body.scrollHeight)') time.sleep(2) driver.save_screenshot('2.png') time.sleep(1) html_source = driver.page_source with open('source.html', 'w', encoding='utf-8') as f: f.write(html_source) driver.quit() if __name__ == "__main__": url = 'https://movie.douban.com/typerank?type_name=%E6%81%90%E6%80%96&type=20&interval_id=100:90&action=' main()

這樣就能夠拿到它的源碼了:

谷歌無頭瀏覽器 Headless Chrome

因爲phantomJs已經中止了更新和維護,因此推薦使用谷歌的無頭瀏覽器,這是一款無界面的谷歌瀏覽器

from selenium import webdriver from selenium.webdriver.chrome.options import Options from time import sleep # 建立一個無頭瀏覽器對象 chrome_options = Options() # 設置它爲無框模式 chrome_options.add_argument('--headless') # 若是在windows上運行須要加代碼 chrome_options.add_argument('--disable-gpu') browser = webdriver.Chrome(chrome_options=chrome_options) browser.get('https://www.baidu.com/') sleep(2) browser.save_screenshot('first_page.png') browser.quit()
 使用谷歌無頭瀏覽器爬取網易新聞的國內模塊

單獨寫了一篇博客:https://www.cnblogs.com/xiaozx/p/10744604.html

相關文章
相關標籤/搜索