Python 教你如何批量獲取百度指數

百度指數:搜尋指數是以網民在百度的搜尋量為資料基礎,以關鍵詞為統計物件,科學分析並計算出各個關鍵詞在百度網頁搜尋中搜尋頻次的加權和。其在研究關鍵詞搜尋趨勢、洞察網民需求變化、監測媒體輿情趨勢、定位數字消費者特徵方面有重要的作用。

之前我們還戲稱百度指數才是百度的良心之作!

如果想要批量獲取一些欄位的百度指數時,就涉及資料獲取啦。

我查詢了很多資料,發現一些教程在獲取百度搜尋指數的時候,使用的是爬蟲技術,通過分析請求引數來獲取指數資訊。一些教程提出了使用截圖進行,然後進行影象識別,那麼對於不懂這些技術的小夥伴該怎麼進行指數的獲取呢?

本文將通過uiautomation來進行獲取,學好了這個技術你還可以對桌面系統進行自動化。

什麼是uiautomation?

Microsoft UI 自動化是一個輔助功能框架,它使 Windows 應用程式能夠提供和使用有關使用者介面 (UI) 的程式設計資訊。它提供對桌面上大多數 UI 元素的程式設計訪問。它使輔助技術產品(例如螢幕閱讀器)能夠向終端使用者提供有關 UI 的資訊並通過標準輸入以外的方式操作 UI。UI 自動化還允許自動化測試指令碼與 UI 互動。

具體可以從以下連結中學習:

https://docs.microsoft.com/en-us/dotnet/framework/ui-automation/ui-automation-overview?redirectedfrom=MSDN

當然了先安裝:

pip install uiautomation

這個uiautomation庫並不是官方的,而是一個作者自己封裝的。感謝這位作者,大家可以從這個連結學習:

https://github.com/yinkaisheng/Python-UIAutomation-for-Windows/

瀏覽器的啟動

由於我們是要基於UI來進行資料的獲取的,如果這個應用程式不是使用微軟提供的標準控制元件來實現的就不能使用uiautomation,也就是說不支援UI框架應用程式是不能使用Uiautomation了,比如 Chrome和基於Electron開發的應用程式。但是也有解決辦法:啟動時新增引數--force-renderer-accessibility才能支援UIAutomation。

這裡我們啟動Chrome並在百度搜尋指數網址:

那麼如何找到這個搜尋框的位置和“開始搜尋”的按鈕呢?

我們可以藉助一個工具inspect.exe去尋找,雙擊這個程式之後,我們找到這個輸入框:

藉助inspect可以看出當前頁面的程式控制元件資訊,如上圖可以看出,其Name為"請輸入您想查詢的關鍵詞",ControlType為UIA_EditControlTypeId,所以可以使用以下程式碼實現我們的功能了,程式碼中沒有進行控制元件查詢超時的異常處理,大家可以自己新增。

import subprocess import uiautomation as auto def show_index_window():     print('root Control:', auto.GetRootControl())     chromePath = "C://Program Files (x86)//Google//Chrome//Application//chrome.exe"     url = r'https://index.baidu.com/v2/index.html#/'     parameter = '--force-renderer-accessibility'     startmax = '-start-maximized'     run_cmd = chromePath   ' '   url   ' '   parameter   ' '   startmax     subprocess.Popen(run_cmd)     mainWindow = auto.DocumentControl(ClassName='Chrome_RenderWidgetHostHWND')     if mainWindow.Name == '百度指數':         print('open success')     # 輸入"特斯拉"並點選"開始探索按鈕"     edit = auto.EditControl(mainWindow, Name='請輸入您想查詢的關鍵詞')     try:         edit.SendKeys('特斯拉')         # editConttol.GetPattern(auto.PatternId.ValuePattern).SetValue('特斯拉')     except LookupError as ex:         return "find control time out "     # 點選按鈕     # time.sleep(1)     textControl = auto.TextControl(mainWindow, Name='開始探索')     try:         print(textControl.Name)     except LookupError as ex:         return "find control time out "     rect = textControl.BoundingRectangle     print(rect)     left = rect.left     top = rect.top     right = rect.right     bottom = rect.bottom     # 進行點選     # 作差取得控制元件中間位置也可     auto.Click(left   10, top   10)

這樣就自動進入到“特斯拉”百度指數詳情介面。

接下來我們就來提取其中的搜尋指數數字資訊。

提取指數資訊

通過inspect發現搜尋指數資訊的控制元件是影象型別的即,ControlType為ImageControl。因此開啟開發者模式是無法提取到的。但是我們又需要裡面的資訊,我們這樣來操作:

因為這些數字是通過懸浮視窗才顯示的,我的做法是這樣的:先執行程式:

python D:/Python/Python38/Scripts/automation.py -t 8

然後切換到指數介面,將滑鼠移動影象曲線開始處的位置上比如2021-06-18那天的指數資料(也不一定是曲線)顯示指數資訊上圖所示。然後可以在automation.py同一目錄出現控制元件資訊檔案@AutomationLog.txt。在這個控制元件資訊檔案中我們找到目標:

可以看出,目標數值24653就顯示出來了:

那麼怎麼將滑鼠移動到開始的位置,很簡單。先獲取控制元件然後獲取屬性BoundingRectangle即可,跟上述點選“開始探索”按鈕一樣。這裡留給讀者自己實現。在不能直接獲取到目標控制元件的時候,可以先獲取某一個元素,比如“新聞頭條”等控制元件,然後獲取其父元素,在獲取子元素。

接下來我們就通過“新聞頭條”控制元件來獲取目標資訊:

程式碼如下:

# -*- coding: utf-8 -*- import time import uiautomation as auto def get_index_baidu():     mainWindow = auto.PaneControl(ClassName='Chrome_WidgetWin_1')     if mainWindow.Exists(3,1):         handle = mainWindow.NativeWindowHandle         # auto.SetWindowTopmost(handle, 'True')         # auto.SwitchToThisWindow(handle)         auto.ShowWindow(handle, auto.SW.Maximize)     news = auto.ListItemControl(mainWindow, Name = '新聞頭條')     try:         print('news:',news)         # editConttol.GetPattern(auto.PatternId.ValuePattern).SetValue('特斯拉')     except LookupError as ex:         return "find control time out"       # 獲取父元素     f_new = news.GetParentControl()     ff_new = f_new.GetParentControl()     # 下一元素     target = ff_new.GetNextSiblingControl()     # 第一個子元素     target_z = target.GetChildren()[0]     # 等待元素載入     """     這裡呼叫滑鼠移動到曲線上。     如果想要自動化,則需要獲取內建控制元件的資訊,然後通過座標來移動。     """     # 這裡等待移動滑鼠到曲線上     time.sleep(2)     f_target_z = target_z.GetChildren()[1]     target_son = f_target_z.GetChildren()     for each in target_son:         text_control = each.GetChildren()[0]         print(text_control.Name)

輸出結果如下:

2021-07-08 星期四

特斯拉

105,777

成功獲取