AutoIT 脚本以某种方式未检测到网站上的下载按钮

AutoIT script somehow not detecting download button on website

我正在尝试编写一个 AutoIT 脚本,它会通过 Internet Explorer 自动导航到 URL (https://www.macrotrends.net/1476/copper-prices-historical-chart-data),然后单击一个按钮(红色,标记为 'Download Historical Data') 将下载 excel 数据文件。通过检查这个按钮,我发现它有一个 id(“dataDownload”),但是我在 AutoIT 中使用 _IEGetObjById 函数的尝试没有成功。 这是我的脚本:

#include <IE.au3>

Local $oIE = _IECreate("https://www.macrotrends.net/1476/copper-prices-historical-chart-data", 1)
Local $oButton = _IEGetObjById($oIE, "dataDownload")
_IEAction($oButton, "click")

脚本正在打开 Internet Explorer,但我认为它没有按预期检测按钮。 我怀疑这可能是因为按钮位于框架或容器内或您可能称之为什么?

此外,我打算让批处理文件在 Windows 上调用此 AutoIT 脚本,以便按计划 运行 进行。如果您有其他推荐的自动网页抓取方法,请不吝赐教。

感谢所有能提供的帮助。

Download historical data 按钮位于指向此 URL 的 iframe 内。

https://www.macrotrends.net/assets/php/chart_iframe_comp.php?id=1476&url=copper-prices-historical-chart-data

但它需要 Javascript 才能工作,也就是说,您必须 在浏览器中加载页面 (执行 javascript)才能单击该按钮[^1].

幸运的是,有一些工具可以使浏览器交互自动化。 Playwright 是一个支持多种语言的库,但我们将在 Python 中使用它。

  1. Install the latest version of Python.
  2. pip(Python 包管理器)更新到最新版本:
    python -m pip install --user --upgrade pip
    
  3. 安装playright
    python -m pip install --user playwright
    
  4. 使用playwright安装浏览器。它将仅供剧作家使用。
    python -m playwright install chromium
    
  5. 打开URL与编剧督察:
    python -m playwright open 'https://www.macrotrends.net/1476/copper-prices-historical-chart-data'
    

应该会弹出一个浏览器 window。将 Target 更改为 python 并单击 Playwright inspector 中的 Record 按钮 window.

然后执行您需要执行的操作,从页面单击并下载文件。

Playwright 会为我们生成一些代码。

停止录制并复制脚本。

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    with p.chromium.launch(headless=False) as browser:
        page = browser.new_page(accept_downloads=True)
        page.goto('https://www.macrotrends.net/1476/copper-prices-historical-chart-data')
        
        # paste the script here

在我的 运行 年代,剧作家为我生成了这个脚本:

# Click button:has-text("Download Historical Data")
with page.expect_download() as download_info:
    page.frame(name="chart_iframe").click("button:has-text(\"Download Historical Data\")")

结合两者并添加保存文件的代码,我们有:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    print('launching the browser')
    with p.chromium.launch(headless=False) as browser:
        page = browser.new_page(accept_downloads=True)
        print('visiting the page')
        page.goto('https://www.macrotrends.net/1476/copper-prices-historical-chart-data')
        
        print('clicking download button')
        # Click button:has-text("Download Historical Data")
        with page.expect_download() as download_info:
            page.frame(name="chart_iframe").click("button:has-text(\"Download Historical Data\")")
        download = download_info.value
        
        print('saving the file')
        download.save_as('prices.csv')

您应该注意的一个重点是 Python 是一种对空格敏感的语言,这意味着您必须正确对齐代码缩进以使其成为 运行.

将此文件另存为download_copper_prices.py,当我们运行脚本时,

python download_copper_prices.py

应该会弹出一个浏览器,访问该页面,下载价格并将其另存为 prices.csv 在工作目录中。


[^1]:实际上,我们可以直接从页面上抓取价格,因为它们被序列化为 JSON。通过一些正则表达式,我们可以从 HTML 中提取 JSON。但在我看来,这个解决方案有点过于针对特定工作,所以我选择了一个更实用的解决方案,他可以在其他场合应用。编写浏览器交互脚本是每个高级用户都应该学习的重要工具。

就是说,我对 AutoIt 不了解,但假设它有强大的 Regex 工具,完全有可能通过下载 URL 的 HTML 在 AutoIt 中获得相同的结果iframe 指向 (https://www.macrotrends.net/assets/php/chart_iframe_comp.php?id=1476&url=copper-prices-historical-chart-data) 然后使用此正则表达式提取 JSON:

var originalData = (.*);

运行 浏览器控制台上的这段代码 returns 15k+ 条目的数组:

JSON.parse(document.body.innerHTML.match('var originalData = (.*);')[1])

由日期和收盘价组成:

[{
    "date": "1959-07-02",
    "close": "0.2930"
}, {...}, ...]

然后将此 JSON 转换为 CSV 应该很容易。

参考资料

这是一个使用 https://www.autoitscript.com/forum/topic/153520-iuiautomation-ms-framework-automate-chrome-ff-ie/ 的工作示例 您可以忽略大部分全局变量。我将其用作我编写的另一个脚本的模板。

```
#include <GUIConstantsEx.au3>
#include <TabConstants.au3>
#include <WindowsConstants.au3>
#include <MsgBoxConstants.au3>
#include <EditConstants.au3>
#include <WinAPIGdi.au3>
#include <WinAPIGdiDC.au3>
#include <WinAPIHObj.au3>
#include <WinAPISysWin.au3>
#include <AD.au3>
#include <Array.au3>
#include "UIAWrappers.au3"
#include <FileConstants.au3>
#include <WinAPIFiles.au3>
#include <GuiListBox.au3>
#include <Word.au3>
#include <File.au3>
#include <Excel.au3>


Opt("WinWaitDelay", 150)
Opt("WinTitleMatchMode", 2)
Opt("WinDetectHiddenText", 1)
Opt("MouseCoordMode", 2)
Opt("SendKeyDelay", 10)
Opt("GUIResizeMode", 1)
HotKeySet("^!x", "MyExit")
Global $ver = "1.0.2.7"
Global $__goError = ObjEvent("AutoIt.Error", "__Excel_COMErrFunc") ; At the top of your script
Global $oCOMErrorHandler = ObjEvent("AutoIt.Error", "_User_ErrFunc")
Global $Guih, $MAINTab, $MAIN, $button1, $button2, $button3, $button4, $idListBox1, $inputEmployeeUsername, $inputSAName, $ADusername, $iLastTab, $editOU
Global $inputSAPassword, $editEmail, $editEmployeeID, $editLastName, $editCity, $editRegion, $editTitle, $editManager, $ADpassword, $editState, $DF
Global $C9, $hWnd, $g_szVersion, $msg, $employeeName, $aResult, $aManager, $aProperties1, $aProperties2, $aString, $aString1, $aString2, $iCurrTab, $editFirstName
Global $ManagerUN, $OU, $Line_Split, $iIndex, $GulfCoast, $SouthEast, $MountainWest, $MidAtlantic, $SouthTexas, $NorthTexas, $MidWest, $MidEast, $editZip
Global $file1, $OU_Name_Return_R, $OU_Name_Trim_L, $OU_Name_Split, $OU_Name_Trim_R, $Search, $State, $TD, $hWnd2, $oWord1, $button11, $editStreet, $CSVName, $Web

$Web = "https://www.macrotrends.net/1476/copper-prices-historical-chart-data"

ShellExecute("C:\Program Files (x86)\Google\Chrome\Application\chrome.exe", "--new-window --force-renderer-accessibility " & $Web, "", "")
WinWait("Copper Prices - 45 Year Historical Chart | MacroTrends - Google Chrome", "", 4)
$hWnd = WinGetHandle("Copper Prices - 45 Year Historical Chart | MacroTrends - Google Chrome")
WinActivate($hWnd)
WinSetState($hWnd, "", @SW_MAXIMIZE)

Local $oP8=_UIA_getObjectByFindAll($UIA_oDesktop, "Title:=Copper Prices - 45 Year Historical Chart | MacroTrends - Google Chrome;controltype:=UIA_PaneControlTypeId;class:=Chrome_WidgetWin_1", $treescope_children)
_UIA_Action($oP8,"setfocus")
Local $oP7=_UIA_getObjectByFindAll($oP8, "Title:=Copper Prices - 45 Year Historical Chart | MacroTrends;controltype:=UIA_DocumentControlTypeId;class:=Chrome_RenderWidgetHostHWND", $treescope_children)
_UIA_Action($oP7,"setfocus")

;~ First find the object in the parent before you can do something
Local $oUIElement=_UIA_getObjectByFindAll("  DownloadHistoricalData.mainwindow", "title:=  Download Historical Data;ControlType:=UIA_ButtonControlTypeId", $treescope_subtree)
Local $oUIElement=_UIA_getObjectByFindAll($oP7, "title:=  Download Historical Data;ControlType:=UIA_ButtonControlTypeId", $treescope_subtree)
_UIA_Action($oUIElement, "setfocus")
_UIA_Action($oUIElement, "highlight")
_UIA_Action($oUIElement, "activate")
_UIA_Action($oUIElement, "leftclick")

Func MyExit()
    Exit
EndFunc   ;==>MyExit

````