google-chrome - 如何将 URL 列表批量保存为 PDF?
问题描述
我有一个食谱的 URL 列表,我想在我对该站点的订阅用完之前将其保存为 PDF。这些 URL 是使用 Xenu Link Sleuth 收集的,它们被保存到 Excel 电子表格中,经过调整以进行清理,删除重复项,并导出到制表符分隔的 txt 文件。
一位朋友编写了一个 AutoHotKey 脚本,该脚本将获取 URL 并使用 Chrome 中的 Print to PDF 选项,但这样做存在问题。除了由于脚本需要控制鼠标而使我的计算机在运行时无法使用之外,它通常会通过以某种方式尝试保存相同的 URL 两次而停止正常工作,即使没有重复的链接,或者只是不保存任何内容。
下面是我朋友写的脚本。它似乎主要对他有用,但对我来说,在这种状态下它不会保存任何东西。在 Sleep 7000 之后,我添加了另一个 Send {Enter},以便激活 Save As 对话框中用于保存 PDF 的 Save 按钮,以及另一个较短的 Sleep。
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn ; Enable warnings to assist with detecting common errors.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
Loop, read, %A_ScriptDir%\CookSpread.txt
{
StringSplit, LineArray, A_LoopReadLine, %A_Tab%
URL := LineArray1
Run, %URL%
Sleep 7000
Click 3407, 241
Sleep 3000
Send {Enter}
Sleep 7000
Send ^{F4}
Sleep 4000
}
我做了一些修改。一是我减少了每一步之间的时间(也许这就是问题所在)。我还添加了单击以选择要与食谱一起打印的营养信息。您还可以在接近尾声时看到我的第二次 Enter。
Sleep 6000
Click 1500, 550
Sleep 500
Click 1480, 220
Sleep 3000
Send {Enter}
Sleep 1000
Send {Enter}
Sleep 1000
Send ^{F4}
Sleep 2000
}
我希望它能够运行,从文本文件中获取一个链接,在浏览器中打开它,将鼠标移到打印按钮(单击)上,这将打开打印界面。然后按 Enter 键单击 Save 按钮,然后按 Enter 键单击 Save 按钮,保存文件,然后关闭当前的 Chrome 选项卡,然后重新开始。
发生的情况是它适用于 20 或 30 个 URL,但是当它保存时会发生一些事情,它说文件已经存在并询问我是否要覆盖它。当脚本继续尝试执行其余步骤时,此窗口保持打开状态,因此没有其他任何事情可以完成。最终发生的事情是打开了数百个选项卡,因为 URL 仍在浏览器中打开。
我想知道是否有人知道如何纠正这个问题,或者他们是否知道另一种方法来完成这个。一个独立的 GUI 应用程序或可以使用我的登录凭据并在后台执行此操作的东西将是理想的,因为 AutoHotKey 脚本使我的计算机在运行时无法使用。但是,如果有人能弄清楚如何让这个工作,那对我来说已经足够好了。
解决方案
尝试:
全部替换
此代码中的“ D:\Downloads ”与程序保存打印的 URL 的文件夹的路径
在Print -settings 中,“ Destination ”必须是“ Save as PDF ”
#NoEnv
#SingleInstance Force
SetWorkingDir %A_ScriptDir%
ModernBrowsers := "Chrome_WidgetWin_0,Chrome_WidgetWin_1,MozillaWindowClass"
LegacyBrowsers := "IEFrame,OperaWindowClass"
FileCreateDir, D:\Downloads\Newly created
FileMove, D:\Downloads\*.pdf, D:\Downloads\Newly created\, 1
F1::
If !WinExist("ahk_exe chrome.exe")
Run, chrome.exe
WinWait, ahk_exe chrome.exe
Sleep, 500
Loop, read, %A_ScriptDir%\CookSpread.txt
{
StringSplit, LineArray, A_LoopReadLine, %A_Tab%
URL := LineArray1
Run, chrome.exe "%URL%"
Sleep, 500
Loop
{
WinActivate, ahk_exe chrome.exe
WinWaitActive, ahk_exe chrome.exe, , 1
If !(ErrorLevel)
break
}
Loop
{
OutputURL := GetActiveBrowserURL()
Sleep, 500
If (OutputURL = "")
continue
If (OutputURL = URL)
break
}
Sleep, 500
Loop
{
WinActivate, ahk_exe chrome.exe
WinWaitActive, ahk_exe chrome.exe, , 1
If !(ErrorLevel)
break
}
Send, ^p
Sleep, 500
Loop
{
WinActivate, ahk_exe chrome.exe
WinWaitActive, ahk_exe chrome.exe, , 1
If !(ErrorLevel)
break
}
Sleep, 300
Send, {Enter}
Sleep, 500
WinWait, Save As ahk_exe chrome.exe
Loop
{
WinActivate, Save As ahk_exe chrome.exe
WinWaitActive, Save As ahk_exe chrome.exe, , 1
If !(ErrorLevel)
{
Send, !s
break
}
}
Sleep, 500
Loop
{
FileMove, D:\Downloads\*.pdf, D:\Downloads\Newly created\, 1
Sleep, 500
If !FileExist("D:\Downloads\*.pdf")
{
WinActivate, ahk_exe chrome.exe
WinWaitActive, ahk_exe chrome.exe, , 1
If !(ErrorLevel)
{
Send, ^w
break
}
}
}
Sleep, 500
}
Run D:\Downloads\Newly created
return
; https://www.autohotkey.com/boards/viewtopic.php?t=3702
; Get the URL of the current (active) browser tab
GetActiveBrowserURL(){
global ModernBrowsers, LegacyBrowsers
WinGetClass, sClass, A
If sClass In % ModernBrowsers ; %
Return GetBrowserURL_ACC(sClass)
Else If sClass In % LegacyBrowsers ; %
Return GetBrowserURL_DDE(sClass) ; empty string if DDE not supported (or not a browser)
Else
Return ""
}
; "GetBrowserURL_DDE" adapted from DDE code by Sean, (AHK_L version by maraskan_user)
; Found at
; http://autohotkey.com/board/topic/17633-/?p=434518
GetBrowserURL_DDE(sClass) {
WinGet, sServer, ProcessName, % "ahk_class " sClass ; %
StringTrimRight, sServer, sServer, 4
iCodePage := A_IsUnicode ? 0x04B0 : 0x03EC ; 0x04B0 = CP_WINUNICODE, 0x03EC = CP_WINANSI
DllCall("DdeInitialize", "UPtrP", idInst, "Uint", 0, "Uint", 0, "Uint", 0)
hServer := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", sServer, "int", iCodePage)
hTopic := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", "WWW_GetWindowInfo", "int", iCodePage)
hItem := DllCall("DdeCreateStringHandle", "UPtr", idInst, "Str", "0xFFFFFFFF", "int", iCodePage)
hConv := DllCall("DdeConnect", "UPtr", idInst, "UPtr", hServer, "UPtr", hTopic, "Uint", 0)
hData := DllCall("DdeClientTransaction", "Uint", 0, "Uint", 0, "UPtr", hConv, "UPtr", hItem, "UInt", 1, "Uint", 0x20B0, "Uint", 10000, "UPtrP", nResult) ; 0x20B0 = XTYP_REQUEST, 10000 = 10s timeout
sData := DllCall("DdeAccessData", "Uint", hData, "Uint", 0, "Str")
DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hServer)
DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hTopic)
DllCall("DdeFreeStringHandle", "UPtr", idInst, "UPtr", hItem)
DllCall("DdeUnaccessData", "UPtr", hData)
DllCall("DdeFreeDataHandle", "UPtr", hData)
DllCall("DdeDisconnect", "UPtr", hConv)
DllCall("DdeUninitialize", "UPtr", idInst)
csvWindowInfo := StrGet(&sData, "CP0")
StringSplit, sWindowInfo, csvWindowInfo, `" ;"; comment to avoid a syntax highlighting issue in autohotkey.com/boards
Return sWindowInfo2
}
GetBrowserURL_ACC(sClass) {
global nWindow, accAddressBar
If (nWindow != WinExist("ahk_class " sClass)) ; reuses accAddressBar if it's the same window
{
nWindow := WinExist("ahk_class " sClass)
accAddressBar := GetAddressBar(Acc_ObjectFromWindow(nWindow))
}
Try sURL := accAddressBar.accValue(0)
If (sURL == "") {
WinGet, nWindows, List, % "ahk_class " sClass ; ; % In case of a nested browser window as in the old CoolNovo (TO DO: check if still needed)
If (nWindows > 1) {
accAddressBar := GetAddressBar(Acc_ObjectFromWindow(nWindows2))
Try sURL := accAddressBar.accValue(0)
}
}
If ((sURL != "") and (SubStr(sURL, 1, 4) != "http")) ; Modern browsers omit "http://"
sURL := "http://" sURL
If (sURL == "")
nWindow := -1 ; Don't remember the window if there is no URL
Return sURL
}
; "GetAddressBar" based in code by uname
; Found at http://autohotkey.com/board/topic/103178-/?p=637687
GetAddressBar(accObj) {
Try If ((accObj.accRole(0) == 42) and IsURL(accObj.accValue(0)))
Return accObj
Try If ((accObj.accRole(0) == 42) and IsURL("http://" accObj.accValue(0))) ; Modern browsers omit "http://"
Return accObj
For nChild, accChild in Acc_Children(accObj)
If IsObject(accAddressBar := GetAddressBar(accChild))
Return accAddressBar
}
IsURL(sURL) {
Return RegExMatch(sURL, "^(?<Protocol>https?|ftp)://(?<Domain>(?:[\w-]+\.)+\w\w+)(?::(?<Port>\d+))?/?(?<Path>(?:[^:/?# ]*/?)+)(?:\?(?<Query>[^#]+)?)?(?:\#(?<Hash>.+)?)?$")
}
; The code below is part of the Acc.ahk Standard Library by Sean (updated by jethrow)
; Found at http://autohotkey.com/board/topic/77303-/?p=491516
Acc_Init()
{
static h
If Not h
h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_ObjectFromWindow(hWnd, idObject = 0)
{
Acc_Init()
If DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
Return ComObjEnwrap(9,pacc,1)
}
Acc_Query(Acc) {
Try Return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Children(Acc) {
If ComObjType(Acc,"Name") != "IAccessible"
ErrorLevel := "Invalid IAccessible Object"
Else {
Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
If DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
Loop %cChildren%
i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child):
Return Children.MaxIndex()?Children:
} Else
ErrorLevel := "AccessibleChildren DllCall Failed"
}
}
推荐阅读
- javascript - JavaScript Toggle 不适用于具有相同类属性的许多元素
- c# - How to rotate around an object without using unity's built-in functions?
- regex - 正则表达式 - 分隔符后的字符,限制为数字
- javascript - 如何更改 jQuery UI 范围滑块宽度
- java - java循环不会结束
- java - 从垃圾回收的角度看 Java 不可变类
- xml - 空值的 XSD 断言测试
- pandas - 了解 scikit-learn ValueError:由于数据形状而设置具有序列的数组元素
- python - Pandas:删除另一个数据框中的行,比较列的子集
- javascript - 新的编程和尝试制作登录表单