好友
阅读权限 30
听众
最后登录 1970-1-1
本帖最后由 Vvvvvoid 于 2023-8-7 20:27 编辑
众所周知,有一些社区是需要邀请注册的, 也就是会员可以生成邀请码, 来分享给为注册的朋友来使用.
但是很多时候, 别人分享出来的邀请码都是带有掩码的, 比如 “cp2iv*qpz*y*q*12” 这种.
同时 * 号可能是任意的字母或者数字.
我们可以简单分析一下,
任意的字母或者数字为 , “abcdefghijklmnopqrstuvwxyz0123456789” , 长度为 36
假如有4位掩码的话 , 一共有 36*36*36*36 = 1679616 组合
聪明的同学可能想到了使用递归来遍历每一位来生成, 具体实现如下:
[Python] 纯文本查看 复制代码
str_mask = "cp2iv*qpz*y*q*12"
def generate_real_codes():
real_codes = []
mask_length = len(str_mask)
def generate_codes_helper(current_code, index):
if index == mask_length:
real_codes.append(current_code)
return
if str_mask[index] == '*':
for char in "abcdefghijklmnopqrstuvwxyz0123456789":
generate_codes_helper(current_code + char, index + 1)
else:
generate_codes_helper(current_code + str_mask[index], index + 1)
generate_codes_helper('', 0)
print(len(real_codes)) # 1679616
return real_codes
输出:
1679616
Time taken: 1.39秒
有没有更高效的方法呢? 当然有的
[Python] 纯文本查看 复制代码
def generate_real_codes_v2():
real_codes = []
possible_chars = []
for ch in str_mask:
if ch == '*':
possible_chars.append("abcdefghijklmnopqrstuvwxyz0123456789")
else:
possible_chars.append(ch)
for code in product(*possible_chars):
real_codes.append(''.join(code))
print(len(real_codes))
return real_codes
输出:
1679616
Time taken: 0.60秒
可以看到, 速度快了一倍.
这段改进后的代码之所以更高效,主要有以下几个原因:
1. 使用了itertools.product函数:在原始代码中,使用嵌套的循环来生成所有可能的解码结果。而在改进后的代码中,我们利用了itertools.product()函数,它接受多个可迭代对象作为参数,并返回它们的笛卡尔积。这样一来,我们可以将多个可迭代对象(包括包含掩码字符和实际字符的字符串)传递给product()函数,它会自动为我们生成所有可能的组合结果。这种方式避免了嵌套循环的使用,简化了代码结构,并且在性能上更为高效。
2. 减少了字符串拼接的次数:在原始代码中,每次生成一个解码结果时,都会使用''.join(code)来进行字符串拼接。而在改进后的代码中,我们将字符串拼接的操作移动到了最后。通过将每个解码结果存储为字符列表code,然后在生成完所有解码结果后,再一次性地进行字符串拼接,可以减少了字符串拼接的次数,提高了效率。
综上所述,通过优化字符集构建、使用itertools.product()函数和减少字符串拼接次数,改进后的代码在生成所有实际代码的过程中更高效。这使得我们能够更快地处理包含多种掩码规则的字符串,节省时间和资源。
到现在, 看似问题解决了, 但是还是不行
因为有些同学可能比较皮, 掩码很个性, 比如这种 “cp2iv★qpz ★y ★q *12 ”
而且这个同学还说 ★ 是随机数字, 而 * 是随机字母+数字.
因为我们脚本需要稍作优化.需要把具体的匹配规则抽出来, 当成可以配置变更的.,如下:
[Python] 纯文本查看 复制代码
mask_rule = {
'*': "abcdefghijklmnopqrstuvwxyz0123456789",
'★': "0123456789",
}
def generate_real_codes_v2_plu():
invite_codes = []
possible_chars = []
for ch in str_mask:
if ch in list(mask_rule.keys()):
possible_chars.append(mask_rule.get(ch))
else:
possible_chars.append(ch)
for code in product(*possible_chars):
invite_codes.append(''.join(code))
return invite_codes
------
感谢@ hrh123 提供优化建议:
确实,如果生成的 invite codes 数量非常大,将它们全部存储在列表中可能会消耗大量的内存。
使用生成器(generator)可以避免这个问题,因为生成器会逐个生成 invite code,而不是一次性生成所有代码并存储在内存中。有点像是 懒加载.
代码如下:
[Python] 纯文本查看 复制代码
def generate_real_codes_v2_plu_plu():
possible_chars = []
for ch in str_mask:
if ch in mask_rule:
possible_chars.append(mask_rule[ch])
else:
possible_chars.append(ch)
for code in product(*possible_chars):
yield ''.join(code)
生成器对象本身并不直接支持获取长度,因为生成器是一种惰性计算的机制,它并不实际生成所有的元素。
为了获取生成器对象的长度,你可以使用一个辅助函数或技巧来实现。下面是一种可能的方法,使用生成器对象的元素逐个迭代,并计数它们的数量:
[Python] 纯文本查看 复制代码
invite_codes = generate_real_codes_v2_plu_plu()
# 使用计数器来获取生成器对象的长度
count = sum(1 for _ in invite_codes)
-----------
至此, 就基本结束了,
在搭配一些 爬虫脚本, 就可以实现某些社区 自动扫码 + 自动注册机制了
免费评分
查看全部评分
发帖前要善用【论坛搜索 】 功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。