探秘Chrome浏览器历史记录的存储与查询

Chrome浏览器的历史记录对于用户来说是一个重要的功能,它可以帮助用户快速找到之前访问过的网页。然而,对于开发者来说,了解Chrome是如何存储这些历史记录的,以及如何通过编程方式查询这些记录,同样具有重要意义。本文将详细介绍Chrome浏览器历史记录的存储方式,以及如何使用SQL查询来检索这些记录。

Chrome浏览器将历史记录存储在一个名为"history"的SQLite数据库中。这个数据库的位置会根据操作系统的不同而有所变化。在Windows系统中,它位于%APPDATA%文件夹中。此外,还有一个"Archived History",它包含了比"History"文件更早的访问记录。值得注意的是,"Archived History"仅包含访问记录。

SQL查询语句

为了检索最近访问的(或所有)历史记录,或者在历史记录数据库中执行搜索,需要准备一些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数据库使用不同的时间戳格式来存储每次访问网站的时间。以下是将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; }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485