I lost a URL in the safari history and I just couldn’t find it so I wrote a script to dump out all the info in the safari history plist file. I put comments in the script that explains how it works and what it does.
It does show how to find all the information in the Safari history items without using any kind of GUI scripting. I did use AppleScript to format the information to be more readable and that made the run time for from under a minute to about 22 minutes. So this script can be pretty fast if all the AppleScript formatting isn’t use.
I thought some people might be interested in this so I posting it.
Here’s the script:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
-- The script was used to get an actual Safari history. It got all 22,273 history items without an error. The Mac OSX was Sierra. It did take 22 minutws to process it.
-- It get all 7 pieces of information stored in the history list although some web pages do not generate all 7 items of informtion.
-- I used copy and paste to get the information from ScriptDebugger to Apple Numbers.
-- This example does not show any decent kind of information output such as writing the information to disk and then opeing the file in Apple numbers.
-- I wrote this to find a missing URL in the history list and I was about to find it using the script output so I did not finish it.
-- But this does show how to process the history list and different ways to process the list can be implemented from this example.
-- This example reads the browser history straight from Safari's history file at /Users/bill/Library/Safari/History.plist. All values from the history are eventually turned into strings
-- and each new value for the current history line has a tab placed in between all the items in the current InforString line. At the end of the script InforString (which contains all
-- the comipled info) is returned from script debugger.
-- The overall idea behind how this works is:
-- It reads the entire "History.plist" into an NSDictionary. The valueForKeyPath gets the property for the specified relationship for every every line in the history file.
-- This is why there is a repeat with a "from and to loop" in the script. I have to specify which line and which property to get the info for particular line in the history items.
-- I don't need to store the value of TheIndex for each line but I thought it might be helpful. But in the end I didn't need it.
-- To get the time for the last visit I created an NSDate using initWithTimeIntervalSinceReferenceDate and put the value in the history info for "lastVisitedDate" for
-- the input to the NSDate method just mentioned. This works because the history info stores the number of seconds from January 1, 2001 00:00:00 UTC.
property OriginalTextItemDelimiters : {""}
set OriginalTextItemDelimiters to AppleScript's text item delimiters
set SafariHistoryPath to ((POSIX path of (path to library folder from user domain)) & "Safari/History.plist") as text
set TheDictionary to current application's NSDictionary's dictionaryWithContentsOfFile:SafariHistoryPath
set TheArray to TheDictionary's valueForKeyPath:"WebHistoryDates"
set NumberOfArrayItems to TheArray's |count|()
set InforString to ""
repeat with TheIndex from 0 to NumberOfArrayItems - 1
set CurrentItem to (TheArray's objectAtIndex:TheIndex)
set TheURL to (CurrentItem's valueForKeyPath:"") as string
set TheTitle to (CurrentItem's valueForKeyPath:"title") as string
set TheDisplayTitle to (CurrentItem's valueForKeyPath:"displayTitle") as string
set TheVisitCount to (CurrentItem's valueForKeyPath:"visitCount") as integer as string
set TheSeconds to (CurrentItem's valueForKeyPath:"lastVisitedDate")
set TheLastVisitedDate to (current application's NSDate's alloc()'s initWithTimeIntervalSinceReferenceDate:TheSeconds) as date as string
set IndexStr to "Item number: " & (TheIndex as string)
set VisitCountList to (CurrentItem's valueForKeyPath:"D") as list
if (VisitCountList = {}) then
set URLRedirectsString to "Empty list"
else
set AppleScript's text item delimiters to {", "}
set VisitCountListListStr to ("{" & text items of VisitCountList as string) & "}"
set AppleScript's text item delimiters to OriginalTextItemDelimiters
end if
set URLRedirects to (CurrentItem's valueForKeyPath:"redirectURLs") as list
if (URLRedirects = missing value) then
set URLRedirectsString to "Empty list"
else
set AppleScript's text item delimiters to {", "}
set RedirectListStr to ("{" & text items of URLRedirects as string) & "}"
set AppleScript's text item delimiters to OriginalTextItemDelimiters
end if
set AppleScript's text item delimiters to OriginalTextItemDelimiters
if (TheDisplayTitle ≠ missing value) then
set InforString to InforString & ((TheIndex + 1) as string) & tab & TheDisplayTitle & tab & TheURL & tab & TheLastVisitedDate & tab & TheVisitCount & tab & VisitCountListListStr & tab & RedirectListStr & return
else
set InforString to InforString & ((TheIndex + 1) as string) & tab & TheTitle & tab & TheURL & tab & TheLastVisitedDate & tab & TheVisitCount & tab & VisitCountListListStr & tab & RedirectListStr & return
end if
end repeat
InforString
Bill