【0基礎學爬蟲】爬蟲基礎之自動化工具 Selenium 的使用

来源:https://www.cnblogs.com/ikdl/archive/2023/04/20/17337591.html
-Advertisement-
Play Games

大數據時代,各行各業對數據採集的需求日益增多,網路爬蟲的運用也更為廣泛,越來越多的人開始學習網路爬蟲這項技術,K哥爬蟲此前已經推出不少爬蟲進階、逆向相關文章,為實現從易到難全方位覆蓋,特設【0基礎學爬蟲】專欄,幫助小白快速入門爬蟲,本期為自動化工具 Selenium 的使用。 概述 目前,很多網站都 ...


0

大數據時代,各行各業對數據採集的需求日益增多,網路爬蟲的運用也更為廣泛,越來越多的人開始學習網路爬蟲這項技術,K哥爬蟲此前已經推出不少爬蟲進階、逆向相關文章,為實現從易到難全方位覆蓋,特設【0基礎學爬蟲】專欄,幫助小白快速入門爬蟲,本期為自動化工具 Selenium 的使用。

概述

目前,很多網站都採用 Ajax 等技術進行動態載入數據,想要採集這類網站的數據,需要通過抓包對網站的數據介面進行分析,去尋找想要採集的數據由哪個介面傳輸。而且,就算找到了數據介面,這些介面可能也是被加密過的,想要通過介面獲取數據,需要對加密參數進行逆向分析,這個過程對於初學者來說非常複雜。

為瞭解決這些問題,能夠更加簡單的進行爬取數據,我們可以使用到一些自動化工具,如 Selenium、playwright、pyppeteer 等,這些工具可以模擬瀏覽器運行,直接獲取到數據載入完成後的網頁源碼,這樣我們就可以省去複雜的抓包、逆向流程,直接拿到數據。

Selenium 的使用

介紹

Selenium 是一個流行的自動化測試框架,可用於測試 Web 應用程式的用戶界面。它支持多種編程語言,如Java、Python、Ruby等,並提供了一系列 API,可以直接操作瀏覽器進行測試。

安裝

使用 selenium 首先需要下載瀏覽器驅動文件,這裡以谷歌瀏覽器為例。在驅動下載頁面找到與自己瀏覽器版本最為接近的文件,如我的谷歌瀏覽器版本為 112.0.5615.86,最接近的文件為 112.0.5615.49,選擇此文件,下載對應系統版本的壓縮包,將壓縮包中的chromedriver.exe程式放到python目錄中。因為正常情況下Python在安裝時就會被添加到系統環境變數之中,將chromedriver.exe放到Python目錄下它就可以在任意位置被執行。

01

02

添加好驅動文件後需要安裝 Python 的第三方庫 selenium。

pip install selenium

使用

Selenium 支持多種瀏覽器,如谷歌、火狐、Edge、Safari等,這裡我們以谷歌瀏覽器為例。

from selenium import webdriver

# 初始化瀏覽器對象
driver = webdriver.Chrome()
# 驅動瀏覽器打開目標網址
driver.get('https://www.baidu.com/')
# 列印當前頁面的源代碼
print(driver.page_source)
# 關閉瀏覽器
driver.quit()

運行代碼後我們會發現自動打開了一個瀏覽器,訪問了目標網址,在控制台輸出了頁面的源代碼,然後自動關閉。

Selenium 提供了一系列實用的 Api,通過它我們可以實現更多操作。

元素查找

在之前的文章《解析庫的使用》中,我們已經講到了 Xpath、bs4 這兩個庫的使用方法,講到了 Xpath 的路徑表達式和 CSS 選擇器,因此這裡主要講解定位方法,路徑表達式與 CSS 選擇器的使用可以去前文中瞭解。

以京東首頁為例,想要獲取秒殺欄目的商品信息,我們可以通過多種方法來進行定位。

03

from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

driver.get('https://www.jd.com/')
# 根據 Xpath 定位
goods_xpath = driver.find_elements(By.XPATH, '//div[@class="slider_list"]/div/a[@class="slider_item seckill-item slider_active"]')

# 根據 Css 選擇器定位
goods_css = driver.find_elements(By.CSS_SELECTOR, 'a[class="slider_item seckill-item slider_active"]')

# 根據類名定位
goods_class_name = driver.find_elements(By.CLASS_NAME,'seckill-item')

print(goods_xpath)

for goods in goods_xpath:
    # 輸出節點的文本信息
    print(goods.text)
    
driver.quit()
# [<selenium.webdriver.remote.webelement.WebElement(session="f49c1906753e404ca0a017...]
# 歐臻廷保濕修護亮顏銀霜面霜70ml護膚品化妝品乳液滋潤送女友禮物禮盒款
# ¥1380.00
# Redmi K50Pro 天璣9000 AMOLED 2K柔性直屏 OIS光學防抖 120W快充 幻鏡 8GB+256GB 5G智能手機 小米紅米
# ¥2619.00
# 卡詩(KERASTASE)黑鑽鑰源魚子醬洗髮水250ml 改善毛躁呵護受損
# ¥219.00

除了示例代碼中的,還有其它定位方法:

driver.find_elements(By.ID,'ID')
driver.find_elements(By.LINK_TEXT,'LINK_TEXT')
driver.find_elements(By.PARTIAL_LINK_TEXT,'PARTIAL_LINK_TEXT')
driver.find_elements(By.TAG_NAME,'TAG_NAME')

元素交互

Selenium 可以實現對頁面中元素的點擊、輸入等操作。

想要採集京東的指定商品信息,首先需要在輸入框輸入商品名稱,然後點擊搜索按鈕,網頁就會跳轉到搜索頁面,展示我們搜索的商品信息。這個流程我們也可以通過 Selenium 來模擬實現。

driver.get('https://www.jd.com/')
# 獲取搜索框
search = driver.find_element(By.XPATH,'//div[@role="serachbox"]/input')
# 獲取查詢按鈕
button = driver.find_element(By.XPATH,'//div[@role="serachbox"]/button')
# 在搜索框中輸入 Python
search.send_keys('Python')
# 點擊查詢按鈕
button.click()

等待

在我們使用 Selenium 時會遇到以下兩種情況:

  1. 頁面未載入完畢,但是我們需要的元素已經載入完畢
  2. 頁面載入完畢,但是我們需要的元素為載入完畢

Selenium 的 get 方法是預設等待頁面載入完畢後再執行下麵的操作。在遇到第一種情況時,要採集的數據已經生成了,但是可能由於某個資源載入緩慢導致頁面一直在載入中狀態,這樣 Selenium 就會一直等待頁面完全載入,造成採集速度緩慢等問題。而情況二,頁面已經載入完成了,但是要採集的數據依舊沒有渲染出來,這就使 Selenium 定位元素失敗導致程式異常。為了避免解決這兩種情況,我們可以設置不等待頁面完全載入,只等待目標元素載入完畢。

from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

caps = DesiredCapabilities().CHROME
#不等待頁面載入
caps["pageLoadStrategy"] = "none"
driver = webdriver.Chrome(desired_capabilities=caps)

強制等待

使用 time.sleep() 實現強制等待。不推薦使用。

driver.get('https://www.jd.com/')
# 強制休眠6秒
time.sleep(6)

隱式等待

等待頁面載入的時間,當頁面載入完成後執行下一步,如果載入時間超過設置的時間時直接執行下一步。不推薦使用。

# 隱式等待10秒
driver.implicitly_wait(10)
driver.get('https://www.jd.com/')

顯式等待

等待條件滿足後執行下一步,條件不滿足則一直等待,當超過設置的時間時拋出異常。推薦使用。

from selenium import webdriver
import selenium.common.exceptions
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
try:
    WebDriverWait(driver, 10).until(
        EC.presence_of_all_elements_located(
            (By.CSS_SELECTOR, 'a[class="slider_item seckill-item slider_active"]')
        )
    )
except selenium.common.exceptions.TimeoutException:
    print('元素載入超時')

當 CSS 選擇器指向的元素存在時則執行下一部,不存在則繼續等待,直到超過設置的10秒,拋出超時異常。

Actions

上文中講到了元素交互,其中點擊、輸入行為都是屬於 Selenium 的動作 Api 之中的,除此之外,Selenium還提供了非常豐富的動作 Api,這裡只介紹常用的方法。

滑鼠操作

from selenium.webdriver import ActionChains

# 單擊元素並按住
clickable = driver.find_element(By.ID, "clickable")
ActionChains(driver).click_and_hold(clickable).perform()

# 雙擊,將滑鼠移動到元素中心並雙擊
clickable = driver.find_element(By.ID, "clickable")
ActionChains(driver).double_click(clickable).perform()

# 按偏移量移動滑鼠
mouse_tracker = driver.find_element(By.ID, "mouse-tracker")
ActionChains(driver).move_to_element_with_offset(mouse_tracker, 8, 0).perform()

# 按當前指針位置進行偏移,如之前沒有移動滑鼠,則預設在視窗的左上角。(13, 15)為橫縱坐標的偏移值,13為向右移動13,15為向下移動15,負數則反之。
ActionChains(driver).move_by_offset( 13, 15).perform()

# 按偏移拖放。點擊元素並按鈕,移動指定偏移量,然後釋放滑鼠
draggable = driver.find_element(By.ID, "draggable")
start = draggable.location
finish = driver.find_element(By.ID, "droppable").location
ActionChains(driver).drag_and_drop_by_offset(draggable, finish['x'] - start['x'], finish['y'] - start['y']).perform()

滾輪

# 滾動到指定元素
iframe = driver.find_element(By.TAG_NAME, "iframe")
ActionChains(driver).scroll_to_element(iframe).perform()
# 按給定值滾動,(0, delta_y) 為向右和向下滾動的量,負值則反之。
footer = driver.find_element(By.TAG_NAME, "footer")
delta_y = footer.rect['y']
ActionChains(driver).scroll_by_amount(0, delta_y).perform()

反檢測

Selenium 有著非常明顯的缺陷,就是容易被網站檢測到。我們通過 Selenium 打開網頁時會發現,視窗上方會顯示瀏覽器正受到自動測試軟體的控制,這就說明 Selenium 驅動瀏覽器與用戶正常打開瀏覽器是不同的,它存在著許多 WebDriver 的特征,網站可以通過檢測這些特征來禁止 Selenium 訪問。

04

我們可以通過一些特征值檢測的網站來對比正常訪問與 Selenium 訪問的區別。

05

06

上面是正常訪問,下麵是 Selenium 訪問,可以很清晰的看到 WebDriver 一欄標紅了,這就說明 Selenium 被檢測到了。網站的檢測原理主要是通過檢查 window.navigator 對象中是否存在 webdriver 屬性。我們瞭解到這一點後,可以通過一些操作來修改window.navigator 對象,在頁面未載入時將它的 webdriver 屬性設置為 false,這樣或許就能避開網站的檢測機制。

from selenium import webdriver
from selenium.webdriver import ChromeOptions

options = ChromeOptions()
# 以最高許可權運行
options.add_argument('--no-sandbox')
# navigator.webdriver 設置為 false
options.add_argument("--disable-blink-features=AutomationControlled")
# 隱藏"Chrome正在受到自動軟體的控制"提示
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options)
with open('./stealth.min.js', 'r') as f:
    js = f.read()
driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': js})

可以看到,我們進行了一些隱藏特征的操作,但在最後我們讀取一個文件,然後將這個文件信息傳入到了execute_cdp_cmd()方法中,這個操作其實也是在隱藏特征。

stealth.min.js 來自於 puppeteer 的一個插件,puppeteer 是一個控制 headless Chrome 的 Node.js API ,puppeteer 有一個插件名為 puppeteer-extra-plugin-stealth,它的開發目的就是為了防止 puppeteer 被檢測,它可以隱藏許多自動化特征。puppeteer-extra 的作者也編寫了一個腳本,用於將最新的特征隱藏方法puppeteer-extra-stealth 提取到 JS 文件之中,生成的 JS 文件可以用於純 CDP 實現,也可以用於測試開發工具中的檢測規避。而 Selenium 正好支持 CDP 的調用,CDP 全稱(Chrome DevTools Protocol),利用它可以在瀏覽器載入之前執行 JS 語句。

如果你已經安裝了 node.js ,npx extract-stealth-evasions 執行此命令就可以生成 stealth.min.js 文件。下圖就隱藏特征後訪問結果。

07

無頭模式

無頭模式下網站運行不會彈出視窗,可以減少一些資源消耗,也避免了瀏覽器視窗運行時對設備正常使用帶來的影響,在伺服器上運行需要用到。但是無頭模式下被網站檢測的特征點非常多,因此需要根據自己的應用場景來使用。

options = ChromeOptions()
options.add_argument('--headless')

driver = webdriver.Chrome(options=options)

總結

使用 Selenium 來進行數據的爬取是一種優勢與劣勢都非常明顯的選擇。它的優勢就是簡單,不需要對網站進行調試,不需要關註數據的來源,大大減少了爬蟲程式的開發時間。它的劣勢有多種:採集效率低,資源占用大,不穩定,容易被檢測,且需要依賴於 WebDriver,當瀏覽器更新後就需要更新對應的 WebDriver。因此 Selenium 適用於那些逆向難度較大,且對採集效率要求不高的場景。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近看到一個有趣的問題:Person類具有Hand,Hand可以操作杯子Cup,但是在石器時代是沒有杯子的,這個問題用編程怎麼解決? 簡單代碼實現 我們先用簡單代碼實現原問題: @Data public class Person { private final String name; privat ...
  • 本文首發於公眾號:Hunter後端 原文鏈接:Django筆記二十六之資料庫函數之數學公式函數 這一篇來介紹一下公式函數,主要是數學公式。 其中 sin,cos 這種大多數情況下用不上的就不介紹了,主要介紹下麵幾種: Abs() 絕對值 Ceil() 向上取整 Floor() 向下取整 Mod() ...
  • 正所謂百家爭鳴、見仁見智、眾說紛紜、各有千秋!在工作流bpmn2.0可視化建模工具實現的細分領域,網上撲面而來的是 bpmn.js 這個渲染工具包和web建模器,而筆者卻認為使用flowable官方開源 editor-app 才是王道。 Flowable 開源版本中的 web 版流程設計器edito ...
  • 背景:1、正常啟動,xml文件放在java目錄和resource目錄下均正常 2、junit啟動,xml文件放在resource目錄下正常,放在java目錄下報BindingException錯誤 mapperlocation綁定地址為:"classpath:com/a/b/**/*.xml" 原因 ...
  • 禁止轉載 重寫了之前博客寫的泛型相關內容,全部整合到這一篇文章里了,把坑都填了,後續不再糾結這些問題了。本文深度總結了函數式思想、泛型對在Java中的應用,解答了許多比較難的問題。 純函數 協變 逆變 泛型通配符 PECS法則 自限定 Part 1: 協變與逆變 Java8 引入了函數式介面,從此方 ...
  • 教程簡介 PHP開發入門教程 - 一個簡單而簡短的PHP教程和所有內置PHP函數的完整參考手冊。本教程是為初學者和高級開發人員設計的。您將瞭解PHP內置函數,預定義變數示例,面向對象的PHP,數字,標量,數組,散列文件I / O,IF,ELSEIF,執行,迴圈,運算符,正則表達式,GET,POST, ...
  • 教程簡介 Hibernate是一個開放源代碼的對象關係映射框架,它對JDBC進行了非常輕量級的對象封裝,它將POJO與資料庫表建立映射關係,是一個全自動的orm框架,hibernate可以自動生成SQL語句,自動執行,使得Java程式員可以隨心所欲的使用對象編程思維來操縱資料庫。 Hibernate ...
  • 函數式編程 面向對象過分強調“必須通過對象的形式來做事情”,而函數式思想則儘量忽略面向對象的複雜語法——強調做什麼,而不是怎麼做。 有時只是為了做某事情而不得不創建一個對象,而傳遞一段代碼才是我們真正的目的。 Lambda Lambda是一個匿名函數,可以理解為一段可以傳遞的代碼。 當需要啟動一個線 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...