パスワードを忘れた? アカウント作成
15778244 journal
Windows

route127の日記: キャーのび太さんのEdge履歴をPerlで抽出する 1

日記 by route127

自分のブラウザ履歴を眺めるのが好きでIE時代はWin32::OLEで履歴を抽出するスクリプトを見つけて利用していたのだがedge移行でそれが出来なくなっていた。
chromeがsqliteを利用しているのは知っていたのでなんとかなるんじゃないかと手を付けてひとまず形にはなった。
visitsテーブルのfrom_visitを使って遷移の様子をgraphvizとかで描けたら面白いなと思ったが時刻の処理に手間取ってそこまで至らなかった。

今検索したらpythonでchromeを対象に履歴を抽出してる人が既にいた。
SQLよく分からず今回は

select * from (table)

で引き出してからごちゃごちゃ処理してるがSQLのクエリ工夫すればこれだけすっきりするのか。

use strict;
use warnings;
use DBI;
use Encode;
use Time::Piece;
use DateTime;
use DateTime::Format::Strptime qw(strptime);
#use Data::Dumper;
use utf8;
 
my %url;
my %title;
my $origin = DateTime::Format::Strptime->new(pattern => '%Y-%m-%d')->parse_datetime('1601-01-01');
my $dbname = 'C:\Users\hogehoge\AppData\Local\Microsoft\Edge\User Data\Default\History';
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname");
 
my $sth=$dbh->prepare("select * from urls");
$sth->execute;
while (my @row = $sth->fetchrow_array){
  #print "@row\n";
  my ($id, $url, $title) = @row;
  $url{$id} = $url;
  $title{$id} = $title || '(無題)';
}
$sth->finish;
undef $sth;
 
#die Dumper \%title;
#die Dumper \%url;
 
$sth = $dbh->prepare("select * from visits");
$sth->execute;
while (my @row = $sth->fetchrow_array){
  #print "@row\n";
  my $id = $row[0];
  my $url = $row[1];
  my $visit_time = $row[2];
  my $from_visit = $row[3];
  my $transition = $row[4];
  my $segment_id = $row[5];
  my $visit_duration = $row[6];
  my $incremented_omnibox_typed_score = $row[7];
  my $opener_visit = $row[8];
 
  my $epoch = int($visit_time*1e-6 + $origin->epoch);
  $epoch = 0 if $epoch < 0;
  $epoch += 32400; #UTC+9
  my $time = Time::Piece->strptime($epoch, '%s');
  print $time->ymd, ' ', $time->hms, "\t", "<a href=\"$url{$url}\">$title{$url}</a></br>", "\n";
}
$sth->finish;
undef $sth;
 
$dbh->disconnect;
print STDERR "OK\n";

今回スクリプトを書くに当たってひとまず

まずchrome化したedgeの閲覧履歴データの格納場所を確認しておいた。

C:\Users\hogehoge\AppData\Local\Microsoft\Edge\User Data\Default\History

chrome化する前のedgeだと格納場所が違う。

C:\Users\hogehoge\AppData\Local\Microsoft\Windows\WebCache\WebCacheV01.dat

この閲覧履歴ファイルの構造をDB Browser for SQLiteで確認して、perlでのDBIモジュールの使い方もおさらいしてやっとスクリプトを書き始める前の準備が出来た。

書き始めればvisitsテーブルのvisit_time値とurl値を読みだしてurl値からurlsテーブルを引いてURL文字列を求めるところまで特に悩まなかったが時刻表示が見たことのない形式だった。

Yahoo頭陀袋でも質問している人がいたが結論が出ておらず、更に探すと機械翻訳っぽいページに1601年1月1日からのマイクロ秒とあった。
Windowでもレジストリ周りActive Directory等でも1601年元日起源の経過時間が時刻表示に使われているようだが、こちらは100ナノ秒単位で今回のedgeの閲覧履歴の時刻より1桁大きい。
またTime::Pieceはどうやら1601年元日を扱えないようだ。
これはミルキィホームズの人が先のActiveDirectoryの件でDateTimeを利用して突破しているのを参考にした。
DateTimeはTime::Pieceほど簡便にはstrptimeを使えないのだな。

my $origin = DateTime::Format::Strptime->new(pattern => '%Y-%m-%d')->parse_datetime('1601-01-01');
my $epoch = int(13306506096492497*1e-6+ $origin->epoch);
print Time::Piece->strptime($epoch, '%s');

後々の自分のコピペ用に一行で書くと

perl -MDateTime -MDateTime::Format::Strptime -MTime::Piece -e "print Time::Piece->strptime(int(13306506096492497*1e-6+ DateTime::Format::Strptime->new(pattern => '%Y-%m-%d')->parse_datetime('1601-01-01')->epoch), '%s');"

Thu Sep 1 11:41:36 2022

途中epoch秒のフィールドディスクリプタ%sが分からなくてマンPman頁のこと)を眺めていた。

これで閲覧時刻を人間に理解しやすい形で表示できるようになった。

冒頭のpythonの例では11644473600秒で決め打ちしてるがこれは

(1970/01/01)(UNIX紀元)-(1601/01/01)
0-(-11644473600)

perl -MDateTime -MDateTime::Format::Strptime -e "print 0-DateTime::Format::Strptime->new(pattern => '%Y-%m-%d')->parse_datetime('1601-01-01')->epoch;"

11644473600

で確かめられる。

またタイトルが空欄のページはひとまず(無題)と表示することとしたがbingの検索結果ページなんかが軒並み(無題)になってしまった。
ブラウザの問題なのかbingの問題なのか。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
typodupeerror

192.168.0.1は、私が使っている IPアドレスですので勝手に使わないでください --- ある通りすがり

読み込み中...