Я использую сценарий Python для разделения домена из соответствующих электронных писем и затем группировки электронных писем согласно их соответствующему домену. Следующий сценарий работает на меня:
#!/usr/bin/env python3
from operator import itemgetter
from itertools import groupby
import os
import sys
dr = sys.argv[1]
for f in os.listdir(dr):
write = []
file = os.path.join(dr, f)
lines = [[l.strip(), l.split("@")[-1].strip()] for l in open(file).readlines()]
lines.sort(key=itemgetter(1))
for item, occurrence in groupby(lines, itemgetter(1)):
func = [s[0] for s in list(occurrence)]
write.append(item+","+",".join(func))
open(os.path.join(dr, "grouped_"+f), "wt").write("\n".join(write))
Я использовал: python3 script.py /path/to/input files
Вход, который я дал, был списком электронных писем и добрался как:
domain1.com,gemail1@domain1.com,email2@domain.com
domain2.com,email1@domain2.com,email2@domain2.com,email3@domain2.com
Но то, с чем стоит проблема, из-за предела MongoDB. Поскольку MongoDB имеет предел 16 МБ размера документа, и одну строку в моем выходном файле рассматривает как 1 документ MongoDB, и размер строки не должен идти вне 16 МБ.
Таким образом, то, что я хочу иметь, является результатом, должен быть ограничен 21 электронным письмом на домен и если домен имеет больше электронных писем затем, он должен быть распечатан на новой строке с остальными электронные письма (снова, если электронные письма превышают 21 затем новую строку с тем же доменным именем). Я бегунок храню дублирующиеся данные в mongoDB.
Таким образом, окончательный результат должен быть чем-то как следующее:
domain1.com,email1@domain1.com,email2@domain1.com,... email21@domain1.com
domain1.com,email22@domain1.com,.....
domain2.com,email1@domain2.com,....
Точка (.) в вышеупомянутом примере представляет многих текст, который я прервал для создания простым понять.
Надежда это разъясняет мою проблему и надеющийся получить решение для него.
Сценарий, который Вы отправили действительно, группирует электронные письма доменом без предела в числе. Ниже версии, которая сгруппирует электронные письма доменом, но разделит найденный список на произвольные блоки. Каждый блок будет распечатан в строку, начиная с соответствующего домена.
#!/usr/bin/env python3
from operator import itemgetter
from itertools import groupby, islice
import os
import sys
dr = sys.argv[1]
size = 3
def chunk(it, size):
it = iter(it); return iter(lambda: tuple(islice(it, size)), ())
for f in os.listdir(dr):
# list the files
with open(os.path.join(dr, "chunked_"+f), "wt") as report:
file = os.path.join(dr, f)
# create a list of email addresses and domains, sort by domain
lines = [[l.strip(), l.split("@")[-1].strip()] for l in open(file).readlines()]
lines.sort(key=itemgetter(1))
# group by domain, split into chunks
for domain, occurrence in groupby(lines, itemgetter(1)):
adr = list(chunk([s[0] for s in occurrence], size))
# write lines to output file
for a in adr:
report.write(domain+","+",".join(a)+"\n")
chunked_list.py
В главном разделе, набор размер блока:
size = 5
Запустите скрипт с каталогом как аргумент:
python3 /path/to/chunked_list.py /path/to/files
Это wil затем создает отредактированный файл каждого из файлов, названных chunked_filename
, с (разделенными на блоки) сгруппированными электронными письмами.
Сценарий берет в качестве входа каталог с файлами как:
email1@domain1
email2@domain1
email3@domain2
email4@domain1
email5@domain1
email6@domain2
email7@domain1
email8@domain2
email9@domain1
email10@domain2
email11@domain1
Из каждого файла это создает копию, как:
domain1,email1@domain1,email2@domain1,email4@domain1
domain1,email5@domain1,email7@domain1,email9@domain1
domain1,email11@domain1
domain2,email3@domain2,email6@domain2,email8@domain2
domain2,email10@domain2
(набор cunksize = 3)
Для поддержки произвольных больших каталогов и файлов Вы могли использовать os.scandir()
получение файлов один за другим и обработка файлов линию за линией:
#!/usr/bin/env python3
import os
def emails_with_domain(dirpath):
for entry in os.scandir(dirpath):
if not entry.is_file():
continue # skip non-files
with open(entry.path) as file:
for line in file:
email = line.strip()
if email: # skip blank lines
yield email.rpartition('@')[-1], email # domain, email
На адреса электронной почты группы доменом, не больше, чем 21 электронное письмо на строку, Вы могли использовать collections.defaultdict()
:
import sys
from collections import defaultdict
dirpath = sys.argv[1]
with open('grouped_emails.txt', 'w') as output_file:
emails = defaultdict(list) # domain -> emails
for domain, email in emails_with_domain(dirpath):
domain_emails = emails[domain]
domain_emails.append(email)
if len(domain_emails) == 21:
print(domain, *domain_emails, sep=',', file=output_file)
del domain_emails[:] # clear
for domain, domain_emails in emails.items():
print(domain, *domain_emails, sep=',', file=output_file)
Примечание:
Посмотрите то, Чего большая часть "pythonic" пути состоит в том, чтобы выполнить итерации по списку в блоках?