繁体   English   中英

从非常大(密码)列表聚合和删除重复项的有效方法

[英]Efficient way to aggregate and remove duplicates from very large (password) lists

语境:

  • 我试图将大量单独的密码列表文本文件合并到一个文件中,以用于基于字典的密码破解。

  • 每个文本文件都以行分隔(每行一个密码),目前有82个单独的文件。 大多数(66)文件在1-100Mb文件大小范围内,12个是100-700Mb,3个是2Gb,1(最有问题的)是11.2Gb。

  • 总的来说,我估计有17.5亿个非唯一密码需要处理; 其中我估计约4.5亿(%25)将是重复的,最终需要丢弃。

  • 我试图在一个可以免费使用6Gb以上RAM的设备上进行此操作(即已经消耗2Gb的8Gb)。

问题:

我需要一种方法来a)将所有这些密码聚合在一起并且b)删除精确的副本,在我的RAM内存约束内并且在一个合理的范围内(约7天,理想情况下要少得多,但实际上我不在乎是否需要数周然后我永远不需要再次运行它了。时间窗口。

我是一名称职的Python程序员,因此已经多次给它一个破解。 我最成功的尝试是使用sqlite3将处理过的密码存储在硬盘上。 然而,这意味着通过对每个已完成的文件进行散列并在每次打开新文件时维护/比较这些文件,来跟踪处理实例之间已经完成哪些文件(我已经多次取消并重新启动以进行更改)是非常繁琐的。 但是对于非常大的文件,任何进度都将丢失。

我一次处理大约10亿(最多)行的文本文件,以防止内存耗尽,而不会在很长一段时间内没有反馈。 我知道我可以,因为我在24小时的运行时间内实现了大约4.5Gb的数据库文件大小,所以我可以充分填充我的数据库所以我估计剩下运行它最多需要4天才能完成所有工作,但我不知道是否/如何最有效地读/写它也没有任何关于如何解决重复删除的好主意(这样做,因为我填充数据库或后来进行额外的传递......?有没有更快的方法来查找我不知道的数据库配置中的唯一性?)。


我今天的请求是关于如何实现我的巨大,唯一的密码列表(理想情况下使用Python)的编程和优化方法的建议/解决方案。 如果我已经脱离了标记,我完全愿意采取完全不同的方法。


两个不错的有:

  • 一种在将来添加更多密码而无需重建整个列表的方法;

  • 一个数据库<20Gb在所有这些结束时,所以移动并不是一个巨大的痛苦。


基于CL的解决方案,最终比我想象的更优雅,我提出了一个稍微修改过的方法。

根据CL的建议,我设置了一个sqlite3数据库,并将文本文件送入Python脚本,然后输出命令将它们插入到数据库中。 直接蝙蝠这个〜做了〜工作但非常(不可行)慢。

我通过一些简单的数据库优化解决了这个问题,这些优化更容易实现,而且从下面包含的基于CL的框架代码构建的核心Python脚本中完成所有操作更加坦率。 该原代码生成sooooooo许多I / O操作是导致我(的Win7)OS造成BSODS和数据丢失一些有趣的事实。 我通过将整个密码文件插入一个SQL事务加上几个pragma更改来解决这个问题。 最后,代码以大约30,000次插入/秒运行,这不是最好的,但对于我的目的肯定是可以接受的。

可能会出现这种情况,但在最大的文件中仍然会失败,但如果/在这种情况下,我只需将文件缩小为较小的1Gb部分并单独使用它们。

import sys
import apsw

i = 0
con = apsw.Connection("passwords_test.db")
cur = con.cursor()

cur.execute("CREATE TABLE IF NOT EXISTS Passwords(password TEXT PRIMARY KEY) WITHOUT ROWID;")
cur.execute("PRAGMA journal_mode = MEMORY;")
cur.execute("PRAGMA synchronous = OFF;")

cur.execute("BEGIN TRANSACTION")
for line in sys.stdin:
    escaped = line.rstrip().replace("'", "''")
    cur.execute("INSERT OR IGNORE INTO Passwords VALUES(?);", (escaped,))
    i += 1
    if i % 100000 == 0: # Simple line counter to show how far through a file we are
        print i

cur.execute("COMMIT")
con.close(True)

然后从命令行运行此代码:

insert_passwords.py < passwordfile1.txt

并自动化:

for %%f in (*.txt) do (
insert_passwords.py < %%f
)

总而言之,数据库文件本身并没有增长得太快,插入速率已经足够,我可以在一塌糊涂的情况下中断/恢复操作,正确地丢弃重复值,并且当前限制因素是查找速度DB不是CPU或磁盘空间。

将密码存储在SQL数据库中时,能够检测重复项需要索引。 这意味着密码存储在表中和索引中两次。

但是,SQLite 3.8.2或更高版本支持WITHOUT ROWID表 (在其他数据库中称为“聚簇索引”或“索引组织表”),这避免了主键的单独索引。

没有包含SQLite 3.8.2的Python版本。 如果您不使用APSW ,您仍然可以使用Python来创建SQL命令:

  1. 安装最新的sqlite3命令行shell( 下载页面 )。
  2. 创建数据库表:

     $ sqlite3 passwords.db SQLite version 3.8.5 2014-06-02 21:00:34 Enter ".help" for usage hints. sqlite> CREATE TABLE MyTable(password TEXT PRIMARY KEY) WITHOUT ROWID; sqlite> .exit 
  3. 创建一个Python脚本来创建INSERT语句:

     import sys print "BEGIN;" for line in sys.stdin: escaped = line.rstrip().replace("'", "''") print "INSERT OR IGNORE INTO MyTable VALUES('%s');" % escaped print "COMMIT;" 

    (如果重复项违反主键的唯一约束,则INSERT OR IGNORE语句不会插入行。)

  4. 通过将命令传递到数据库shell来插入密码:

     $ python insert_passwords.py < passwords.txt | sqlite3 passwords.db 

无需拆分输入文件; 更少的事务处理开销更少。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM