Pythonr基于selenium如何實現(xiàn)不同商城的商品價格差異分析系統(tǒng)
1. 前言
selenium 原本是一款自動化測試工具,因其出色的頁面數(shù)據(jù)解析和用戶行為模擬能力而常用于爬蟲程序中,致使爬蟲程序的爬取過程更簡單、快捷。
爬蟲程序與其它類型程序相比較,本質(zhì)一樣,為數(shù)據(jù)提供處理邏輯,只是爬蟲程序的數(shù)據(jù)來源于 HTML 代碼片段中。
怎樣準確查找到頁面中數(shù)據(jù)所在的標簽(或叫節(jié)點、元素、組件)就成了爬蟲程序的關(guān)鍵,只有這一步成立,后續(xù)的數(shù)據(jù)提取、清洗、匯總才有可能。
相比較于 Beaufulsoup 模塊, selenium 底層依靠的是強大的瀏覽器引擎,在頁面解析能力上頗有王者的從容和決絕。
本文將使用 selenium 自動摸擬用戶的搜索行為,獲取不同商城上同類型商品的價格信息,最終生成商品在不同商城上的價格差對比表。
本文通過實現(xiàn)程序流程講解 selenium,只會講解程序中涉及到的 selenium 功能。不會深究其它 selenium API 的細節(jié)。所以你在閱讀本文時,請確定你對 selenium 有所一點點的了解。
2、程序設(shè)計流程
2.1 需求分析:
本程序?qū)崿F(xiàn)了用戶不打開瀏覽器、只需要輸入一個商品關(guān)鍵字,便能全自動化的實現(xiàn)在不同商城中查找商品價格,并匯總出價格一些差異信息。
1、程序運行時,提示使用者輸入需要搜索的商品關(guān)鍵字。
本程序僅為探研 selenium 的奇妙之處,感受其王者風范,沒有在程序結(jié)構(gòu)和界面上費心力。
2、使用 selenium 摸擬用戶打開京東和蘇寧易購首頁。
為什么選擇京東和蘇寧易,而不選擇淘寶?
因為這 2 個網(wǎng)站使用搜索功能時沒有登錄驗證需要,可簡化本程序代碼。
3、使用 selenium 在首頁的文本搜索框中自動輸入商品關(guān)鍵字,然后自動觸發(fā)搜索按鈕的點擊事件,進入商品列表頁面。
4、使用 selenium 分析、爬取不同商城中商品列表頁面中的商品名稱和價格數(shù)據(jù)。
5、對商品的價格數(shù)據(jù)做簡單分析后,使用 CSV 模塊以文件方式保存。
主要分析商品在不同商城上的平均價格、最低價格、最高體系的差異。
當然,如果有需要,可以借助其它的模塊或分析邏輯,得到更多的數(shù)據(jù)分析結(jié)論。
2.2 認識 selenium
雖然本文不深究 selenium API 的細節(jié),但是,既然要用它,其使用流程還是要面面俱到。
1、安裝:
selenium 是 python 第三庫,使用前要安裝,安裝細節(jié)就沒必要在此多費筆墨。
pip3 install selenium
除了安裝 selenium 模塊,還需要為它下載一個瀏覽器驅(qū)動程序,否則它無法工作。
什么是瀏覽器驅(qū)動程序?為什么需要它?
解釋這個問題,需要從 selenium 的工作原理說起。
2、淺淡 selenium 的工作原理:
Beautiful soup 使用特定的解析器程序解析 HTML 頁面。selenium 更干脆、直接借助瀏覽器的解析能力。通過調(diào)用瀏覽器的底層 API 完成頁面數(shù)據(jù)查找,也是跪服了,不僅爬取,還可以向瀏覽器模擬用戶行為發(fā)送操作指令。
有沒有感覺瀏覽器就是 selenium 手中的牽線木偶(玩弄瀏覽器于股掌之中)。 selenium 的工作就是驅(qū)動瀏覽器,向瀏覽器發(fā)送指令或接收瀏覽的反饋,此過程中,瀏覽器驅(qū)動程序(webdriver)就起到了上傳下達的作用。
典型的組件開發(fā)模式。
很顯然,因不同瀏覽器的內(nèi)核存在差異性,驅(qū)動程序必然也不相同,所以,下載驅(qū)動程序之前,請確定你使用的瀏覽器類型和版本。
本文使用谷歌瀏覽器,需要下載與谷歌瀏覽器對應(yīng)的 webdriver 驅(qū)動程序。
進入 https://www.selenium.dev/downloads/ 網(wǎng)站,選擇 python 語言,選擇最新穩(wěn)定版本。
請選擇與正使用的瀏覽版本一致的驅(qū)動程序。
下載完畢后,指定一個驅(qū)動程序的存放目錄,本文存放在 D:\chromedriver\chromedriver.exe 。也可存放在瀏覽器的安裝目錄。
2.3 功能函數(shù)設(shè)計
準備工作就緒后,開始編碼:
導(dǎo)入程序所需要的模塊,定義程序所需要的變量。
from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By import csv import time import math # 瀏覽器對象 chrome_browser = None # 商品關(guān)鍵字 search_keyword = None # 保存在京東商城搜索到的商品數(shù)據(jù),格式{商品名:價格} jd_data = {} # 保存在蘇寧商城搜索到的商品數(shù)據(jù),格式{商品名:價格} sn_data = {}
- webdriver: 用來構(gòu)建瀏覽器對象,從底層設(shè)計角度講,是 selenium 和瀏覽器之間的接口層。selenium 向上為用戶提供高級應(yīng)用接口,向下通過 webdriver 和瀏覽器無障礙溝通。
- Service: webdriver 構(gòu)建瀏覽器對象時的參數(shù)類型。
- By: ** 封裝了查找頁面組件的各種方式。selenium** 向開者提供了很多高級方法用來查詢 HTML 頁面組件,如通過元素 ID、樣式、樣式選擇器、XPATH……By 封裝了這些方案。
諸如:find_element_by_class_name( )、 find_element_by_id()、find_element_by_()、find_element_by_tag_name()、find_element_by_class_name()、find_element_by_xpath()、find_element_by_css_selector()
以上方法已經(jīng)被標注為過時,請使用 find_element( ) 方法,配合 By 對象切換方式。
- csv: 用來把獲取到的數(shù)據(jù)以 csv 格式保存。
- time: 時間模塊,用來模擬網(wǎng)絡(luò)延遲。
- math: 數(shù)學(xué)模塊,輔助數(shù)據(jù)分析。
初始化函數(shù):初始化瀏覽器對象和用戶輸入數(shù)據(jù)
''' 初始瀏覽器對象 ''' def init_data(): # 驅(qū)動程序存放路徑 webdriver_path = r"D:\chromedriver\chromedriver.exe" service = Service(webdriver_path) # 構(gòu)建瀏覽器對象 browser = webdriver.Chrome(service=service) # 等待瀏覽器就緒 browser.implicitly_wait(10) return browser ''' 初始用戶輸入的商品名稱關(guān)鍵字 ''' def input_search_key(): info = input("請輸入商品關(guān)鍵字:") return info
查詢京東商品信息。在京東商城查詢商品,分兩個步驟,在首頁輸入商品關(guān)鍵字,點擊搜索后,在結(jié)果頁面查詢價格信息。完整代碼如下:
''' 進入京東商城查詢商品信息 ''' def search_jd(): global jd_data products_names = [] products_prices = [] # 京東首頁 jd_index_url = r"https://www.jd.com/" # 打開京東首面 try: if chrome_browser is None: raise Exception() else: # 打開京東首頁 chrome_browser.get(jd_index_url) # 模擬網(wǎng)絡(luò)延遲 chrome_browser.implicitly_wait(10) # 找到文本輸入組件 search_input = chrome_browser.find_element(By.ID, "key") # 在文本框中輸入商品關(guān)鍵字 search_input.send_keys(search_keyword) chrome_browser.implicitly_wait(5) # 找到搜索按鈕 這里使用 CSS 選擇器方案 search_button = chrome_browser.find_element(By.CSS_SELECTOR, "#search > div > div.form > button") # 觸發(fā)按鈕事件 search_button.click() chrome_browser.implicitly_wait(5) # 獲取所有打開的窗口(當點擊按鈕后應(yīng)該有 2 個) windows = chrome_browser.window_handles # 切換新打開的窗口,使用負索引找到最后打開的窗口 chrome_browser.switch_to.window(windows[-1]) chrome_browser.implicitly_wait(5) # 獲取商品價格 product_price_divs = chrome_browser.find_elements(By.CLASS_NAME, "p-price") for i in range(5): div = product_price_divs[i] if len(div.text) != 0: # 刪除價格前面的美元符號 products_prices.append(float(div.text[1:])) # 獲取商品名稱 product_name_divs = chrome_browser.find_elements(By.CLASS_NAME, "p-name") chrome_browser.implicitly_wait(10) for i in range(5): div = product_name_divs[i] if len(div.text) != 0: products_names.append(div.text) jd_data = dict(zip(products_names, products_prices)) jd_data["平均價格"] = sum(products_prices) / len(products_prices) jd_data["最低價格"] = min(products_prices) jd_data["最高價格"] = max(products_prices) # 使用 CSV 模塊寫入文檔 csv_save("京東商城", jd_data) except Exception as e: print(e)
chrome_browser: 由 webdriver 構(gòu)建出來的對瀏覽器映射的對象,selenium 通過此對象控制對瀏覽器的所有操作。
此對象有一個 find_element( ) 核心方法,用來查找(定位)HTML 頁面元素。查找時,可以通過 By 對象指定查找的方式(這里使用了工廠設(shè)計模式), By 的取值可以是 ID、CSS_SELECTOR、XPATH、CLASS_NAME、CSS_SELECTOR、TAG_NAME、LINK_TEX、PARTIAL_LINK_TEXT。
打開京東首頁后,先定位定位文本搜索框和搜索按鈕。
使用瀏覽器的開發(fā)者工具,檢查到文本框的源代碼是一段 input html 片段,為了精確地定位到此組件,一般先試著分析此組件有沒有獨有的屬性或特征值,id 是一個不錯的選擇。html 語法規(guī)范 id 值應(yīng)該是一個唯一值。
search_input = chrome_browser.find_element(By.ID, "key")
找到組件后,可以對此組件進行一系列操作,常用的操作:
- text 屬性: 獲取組件的文本內(nèi)容。
- send_keys( ) 方法:為此組件賦值。
- get_attribute( ) 方法:獲取組件的屬性值。
這里使用 send_keys 給文本組件賦予用戶輸入商品關(guān)鍵字。
search_input.send_keys(search_keyword)
再查找搜索按鈕組件:
按鈕組件是一段 button html 代碼,沒有過于顯著的特性屬性值,為了找到這個唯一組件,可以使用 XPATH 或 CSS 選擇器方式。右擊此代碼片段,在彈出的快捷菜單中找到“復(fù)制”命令,再找到此組件的 CSS選擇器值。
search_button = chrome_browser.find_element(By.CSS_SELECTOR, "#search > div > div.form > button")
調(diào)用按鈕組件的 click() 方法,模擬用戶點擊操作,此操作會打開新窗口,并以列表方式顯示搜索出來的商品數(shù)據(jù)。
search_button.click()
selenium 接收到瀏覽器打開新窗后的反饋后,可以使用 window_handles 屬性獲取瀏覽器中已經(jīng)打開的所有窗口,并以列表的方式存儲每一個窗口的操作引用。
windows = chrome_browser.window_handles
對頁面元素進行定位查找時,有一個當前窗口(當前可以、正在操作的窗口)的概念。剛開始是在首頁窗口操作,現(xiàn)在要在搜索結(jié)果窗口中進行操作,所以要切換到剛打開的新窗口。使用負索引得到剛打開的窗口(剛打開的窗口一定是最后一個窗口)。
chrome_browser.switch_to.window(windows[-1])
注意,這時切換到了搜索結(jié)果窗口,便可以在這個窗口中搜索所需要組件。
在這個頁面中,只需要獲取前 5 名的商品具體信息,包括商品名、商品價格。至于具體要獲取什么數(shù)據(jù),可以根據(jù)自己的需要定奪。本程序只需要商品的價格和名稱,則檢查頁面,找到對應(yīng)的 html 片段。
商品名信息存放在一個 div 片段中,此 div 有一個值為 p-name 的 class 屬性。可以使用 CSS-NAME 方式獲取,因為所有的商品采用相同片段模板,這里使用 find_elements( ) 方法即可。
product_name_divs = chrome_browser.find_elements(By.CLASS_NAME, "p-name")
find_elements 方法返回具有相同 CSS-NAME 的組件列表,編寫代碼迭代出每一個組件,并獲取數(shù)據(jù),然后存儲在商品名稱列表中。
for i in range(5): div = product_name_divs[i] if len(div.text) != 0: products_names.append(div.text)
以同樣的方式,獲取到價格數(shù)據(jù)。再把商品名稱和價格數(shù)據(jù)制成字典,并對價格數(shù)據(jù)做簡單分析。
jd_data = dict(zip(products_names, products_prices)) jd_data["平均價格"] = sum(products_prices) / len(products_prices) jd_data["最低價格"] = min(products_prices) jd_data["最高價格"] = max(products_prices) csv_save("京東商城", jd_data)
以 CSV 格式存儲從京東商城上爬取下來的數(shù)據(jù)。
獲取蘇寧易購上的商品數(shù)據(jù)。與從京東上獲取數(shù)據(jù)的邏輯一樣(兩段代碼可以整合到一個函數(shù)中,為了便于理解,本文分開編寫)。兩者的區(qū)別在于頁面結(jié)構(gòu)、承載數(shù)據(jù)的頁面組件不一樣或組件的屬性設(shè)置不一樣。
def search_sn(): global sn_data # 保存商品名稱 products_names = [] # 保存商品價格 products_prices = [] # 蘇寧首頁 sn_index_url = r"https://www.suning.com/" try: if chrome_browser is None: raise Exception() else: # 打開首頁 chrome_browser.get(sn_index_url) # 摸擬網(wǎng)絡(luò)延遲 chrome_browser.implicitly_wait(10) # 查找文本輸入組件 search_input = chrome_browser.find_element(By.ID, "searchKeywords") # 在文本框中輸入商品關(guān)鍵字 search_input.send_keys(search_keyword) time.sleep(2) # 找到搜索按鈕 這里使用 CSS 選擇器方案 search_button = chrome_browser.find_element(By.ID, "searchSubmit") # 觸發(fā)按鈕事件 search_button.click() time.sleep(3) # 獲取所有打開的窗口(當點擊按鈕后應(yīng)該有 2 個) windows = chrome_browser.window_handles # 切換新打開的窗口,使用負索引找到最后打開的窗口 chrome_browser.switch_to.window(windows[-1]) chrome_browser.implicitly_wait(20) # 獲取商品價格所在標簽 product_price_divs = chrome_browser.find_elements(By.CLASS_NAME, "def-price") # 僅查看前 5 個商品信息 for i in range(5): div = product_price_divs[i] # 刪除價格前面的美元符號 if len(div.text) != 0: products_prices.append(float(div.text[1:])) chrome_browser.implicitly_wait(10) # 獲取商品名稱 product_name_divs = chrome_browser.find_elements(By.CLASS_NAME, "title-selling-point") for i in range(5): products_names.append(product_name_divs[i].text) # sn_data = dict(zip(products_names, products_prices)) sn_data["平均價格"] = sum(products_prices) / len(products_prices) sn_data["最低價格"] = min(products_prices) sn_data["最高價格"] = max(products_prices) # 使用 CSV 模塊寫入文檔 csv_save("蘇寧商城", sn_data) except Exception as e: print(e)
獲取到蘇寧易購上的商品數(shù)據(jù)后,同樣以 CSV 格式存儲。
存儲最終的分析結(jié)果。這里僅分析了兩個商城上同類型商品的平均價格、最低價、最高價的差異性。
def price_result(): if len(jd_data) != 0 and len(sn_data) != 0: with open("d:/商品比較表.csv", "w", newline='') as f: csv_writer = csv.writer(f) jd_name = list(jd_data.keys()) jd_price = list(jd_data.values()) sn_price = list(sn_data.values()) csv_writer.writerow(["比較項", "京東價格", "蘇寧價格", "價格差"]) for i in range(5, len(jd_price)): csv_writer.writerow([jd_name[i], jd_price[i], sn_price[i], math.fabs(jd_price[i] - sn_price[i])])
保存了兩個商城上商品價格的平均值、最小值、最大值以及絕對差。
最終測試代碼
if __name__ == '__main__': search_keyword = input_search_key() chrome_browser = init_data() search_jd() time.sleep(2) search_sn() price_result()
請輸入商品關(guān)鍵字:華為meta 40
3. 總結(jié)
本文主要是應(yīng)用 selenium 。通過應(yīng)用過程對 selenium 做一個講解,了解 selenium 的基本使用流程。數(shù)據(jù)分析并不是本文的重點。
如果要得到更全面的分析結(jié)果,則需要提供更多維度的數(shù)據(jù)分析邏輯。
到此這篇關(guān)于Pythonr基于selenium如何實現(xiàn)不同商城的商品價格差異分析系統(tǒng)的文章就介紹到這了,更多相關(guān)Pythonr selenium商品價格差異分析系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實現(xiàn)GUI學(xué)生管理系統(tǒng)的示例代碼
這篇文章主要為大家介紹了如何留Python語言實現(xiàn)簡易的GUI學(xué)生管理系統(tǒng),文中的示例代碼講解詳細,對我們學(xué)習Python有一定幫助,需要的可以參考下2022-06-06Python?ArcPy實現(xiàn)批量計算多時相遙感影像的各項元平均值
這篇文章主要為大家詳細介紹了如何基于Python中ArcPy模塊,實現(xiàn)對大量長時間序列柵格遙感影像文件的每一個像元進行多時序平均值的求取,感興趣的可以了解一下2023-04-04python+unittest+requests實現(xiàn)接口自動化的方法
這篇文章主要介紹了python+unittest+requests實現(xiàn)接口自動化的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11