Chrome浏览器的历史记录对于用户来说是一个重要的功能,它可以帮助用户快速找到之前访问过的网页。然而,对于开发者来说,了解Chrome是如何存储这些历史记录的,以及如何通过编程方式查询这些记录,同样具有重要意义。本文将详细介绍Chrome浏览器历史记录的存储方式,以及如何使用SQL查询来检索这些记录。
Chrome浏览器将历史记录存储在一个名为"history"的SQLite数据库中。这个数据库的位置会根据操作系统的不同而有所变化。在Windows系统中,它位于%APPDATA%文件夹中。此外,还有一个"Archived History",它包含了比"History"文件更早的访问记录。值得注意的是,"Archived History"仅包含访问记录。
为了检索最近访问的(或所有)历史记录,或者在历史记录数据库中执行搜索,需要准备一些SQL查询语句。以下是一些基本的SQL查询语句示例:
SELECT last_visit_time, datetime(last_visit_time / 1000000 - 11644473600, 'unixepoch', 'localtime'), url, title FROM urls ORDER BY last_visit_time DESC
在C++中,可以定义一个宏来简化查询语句的编写:
#define CHROME_HISTORY_SQL_QUERY "SELECT last_visit_time, datetime(last_visit_time / 1000000 - 11644473600, 'unixepoch', 'localtime'), url, title FROM urls ORDER BY last_visit_time DESC"
如果想要基于一个搜索词来检索历史记录,例如搜索词为"child",可以使用如下的查询语句:
#define CHROME_HISTORY_SQL_QUERY2_LEFT "SELECT last_visit_time, datetime(last_visit_time / 1000000 - 11644473600, 'unixepoch', 'localtime'), url, title FROM urls WHERE title like '%child%'"
#define CHROME_HISTORY_SQL_QUERY2_RIGHT " ORDER BY last_visit_time DESC"
如果想要添加一个查询条件,例如"Where last_visit_time >
#define CHROME_HISTORY_SQL_QUERY_LEFT "SELECT last_visit_time, datetime(last_visit_time / 1000000 - 11644473600, 'unixepoch', 'localtime'), url, title FROM urls"
#define CHROME_HISTORY_SQL_QUERY_RIGHT " WHERE last_visit_time > ORDER BY last_visit_time DESC"
为了支持所有浏览器的历史记录,定义了一个通用的数据结构。以下是在Google Chrome的范围内演示的数据结构定义:
typedef struct _SGBrowserHistory {
int Browser; // 1 = chrome, 2 = firefox, 3 = ie
WCHAR SiteURL[URL_MAXSIZE];
WCHAR SiteName[1024];
WCHAR LastVisitDate[256];
} SGBrowserHistory;
还定义了一个新的类型SGBrowserHistoryArray,它将被用来存储SGBrowserHistory数据结构的动态数组。
typedef CSimpleArray SGBrowserHistoryArray;
创建了一个小程序,它使用为多个产品开发的类库。以下是使用类的最简单方式,即检索所有存储的历史记录。这可能需要一些时间,不想在Chrome使用时阻塞或被阻塞(当它被使用时,其数据库被访问和修改),因此首先创建自己的备份数据库,并将其命名为temp.db。
bool SGBrowsingHistory::GetChromeHistory(SGBrowserHistoryArray *history, CString FileName, CString SearchString) {
bool result = false;
WCHAR szPath[MAX_PATH];
utils::SG_GetSpecialFolderPath(szPath, CSIDL_LOCAL_APPDATA);
StrCat(szPath, CHROMEHISTORY);
WCHAR filename[MAX_PATH + 1] = { TEMP_DB_NAME };
if (CopyFile(szPath, filename, FALSE)) {
if (GetFileAttributes(filename) != 0xFFFFFFFF) {
} else {
wprintf(L"Error: Cannot find login data for Google Chrome browser\r\n");
}
bool result = db->GetChromeHistoryRecords(filename, history, SearchString);
}
return result;
}
程序不仅与Chrome的数据库接口,还创建了自己的数据库,以便可以按需存储数据。以下是创建ChromeHistory表的代码:
#define createTableChromeHistory L"CREATE TABLE IF NOT EXISTS ChromeHistory(\
id INTEGER PRIMARY KEY AUTOINCREMENT,\
created TIMESTAMP not null default CURRENT_TIMESTAMP,\
date_last_visited TEXT not null default '',\
site_name TEXT not null default '',\
size_url TEXT not null default ''\
);"
在之前的文章中,已经讨论了很多关于记录错误日志的话题。在这种情况下,这里是一个非常简单的函数,用于记录SQL错误。
#define STR_ERROR_RUNNING_QEURY L"Error running query: %s. Error message: %s. Function = %s\n"
void CSGDatabase::LogSqlError(CppSQLite3Exception &e, CString Function, CString sql) {
wprintf(STR_ERROR_RUNNING_QEURY, sql.GetBuffer(), e.errorMessage(), Function.GetBuffer());
}
然后创建一个宏:
#define LOGSQLERROR(e,sql) LogSqlError(e, (CString)__FUNCTION__, sql);
以便在调用LogSqlError函数时已经包含了当前函数的名称。
Chrome数据库使用不同的时间戳格式来存储每次访问网站的时间。以下是将Chrome时间转换为系统时间的函数:
// convert chrome time (as long long integer) to system time
SYSTEMTIME intChromeTimeToSysTime(long long int UnixTime) {
time_t dosTime(UnixTime);
SYSTEMTIME systemTime;
LARGE_INTEGER utcFT = {0};
utcFT.QuadPart = ((unsigned __int64)dosTime) * 10000000;
FileTimeToSystemTime((FILETIME*)&utcFT, &systemTime);
return systemTime;
}