Форум сайта python.su
Всем привет.
Уже 5 часов в питоне, пробую написать некоторые автоматизации, которые помогают в работе.
Код работал исправно, пока я не решил сделать его более гибким. Т.е. он сохраняет исходный код урла в файл. Всё круто.
В urls.txt - просто список урлов, каждый с новой строки.
Но, как только я захотел, чтобы он сохранял не в корень, а в {Domain}/{Date}/file.html - начались проблемы. По отдельности вроде работает и папки создает и файл кладет, но всё вместе - отказывается работать. Т.е. папка может быть уже создана (после взятия 1 url, а проверка на существование папки через try - раздувает код и всё равно не работает, уверен есть какой-то более явный способ).
Так же хотелось бы мнение специалистов - с for у меня 100% говнокод, который можно сделать лучше, т.е. чтобы он брал строку с удалением (но у меня в голове получается еще больший говнокод с получением line - удалением line и т.д.).
import requests import re import linecache import datetime import os from urllib.request import urlopen from bs4 import BeautifulSoup urls = open ('urls.txt') date = str(datetime.datetime.now().date().strftime('%d.%m.%Y')) numstr = 1 for url in urls.readlines(): url = linecache.getline('urls.txt', numstr).rstrip() page = urlopen(url) source = BeautifulSoup(page, "html.parser" ).encode('utf-8') domain = re.match(r'(?i)(?=http:\/\/|https:\/\/|ftp:\/\/)?([a-z0-9\-\.]+)?[a-z0-9\-]+(!?\.[a-z]{2,4})', url) filename = re.sub(r'(?i)(http:\/\/|https:\/\/|ftp:\/\/)?([a-z0-9\-\.]+)?[a-z0-9\-]+(!?\.[a-z]{2,4})', '', url) filename = re.sub(r'\/', '-', filename) os.mkdir(domain.group(0)) os.mkdir(date) file = open (filename + 'backup.html', 'wb') file.write (source) file.close numstr = numstr + 1
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-2-4fb49e3a7d5b> in <module>() 18 filename = re.sub(r'(?i)(http:\/\/|https:\/\/|ftp:\/\/)?([a-z0-9\-\.]+)?[a-z0-9\-]+(!?\.[a-z]{2,4})', '', url) 19 filename = re.sub(r'\/', '-', filename) ---> 20 os.mkdir(domain.group(0)) 21 os.mkdir(date) 22 # os.chdir(str(datetime.datetime.now().date().strftime('%d.%m.%Y')) AttributeError: 'NoneType' object has no attribute 'group'
Отредактировано Romanus (Июль 20, 2018 11:08:50)
Офлайн
> проверка на существование папки через try - раздувает код и всё равно не работает, уверен есть какой-то более явный способ
os.path.isdir
> Проблема
У тебя domain равен None. Это может произойти если например в файле есть неверные url, пустые строки или строки только из пробельных символов.
Офлайн
Никак не понимал, почему domain в одном случае None, а в другом - имя домена.
невнимательно использовал re.match, а нужно было re.search.
А за isdir - спасибо
Сейчас всё работает, еще освоил немного функции, крайне полезная штука.
Рабочий код прилагаю.
Вопросы:
1) Задача-то решена - но код на мой взгляд раздут и идет слишком “в лоб”, куда покопать и как сделать его логичнее, проще и чище?
2) Вариант с перебором строк в цикле for с добавлением +1 (чтобы брать след. строку) - есть какое-то более верное решение типа просто брать 1 строку с удалением взятой строки и пустой строки (т.к. останется пустота)?
3) После создания папки - скрипт сидит в ней, нормальный ли вариант с переходом в “начало” через явное указание начального пути?
4) Любые замечания и указание на косяки будут кстати
import requests import re import linecache import datetime import os from urllib.request import urlopen from bs4 import BeautifulSoup urls = open ('urls.txt') date = str(datetime.datetime.now().date().strftime('%d.%m.%Y')) numstr = 1 def writefile(filename, source): file = open (filename + 'backup.html', 'wb') file.write (source) file.close for url in urls.readlines(): os.chdir (r'C:\Users\maest\PYTHON') url = linecache.getline('urls.txt', numstr).rstrip() page = urlopen(url) source = BeautifulSoup(page, "html.parser" ).encode('utf-8') domain = re.search(r'(?i)(?=http:\/\/|https:\/\/|ftp:\/\/)?([a-z0-9\-\.]+)?[a-z0-9\-]+(!?\.[a-z]{2,4})', url) filename = re.sub(r'(?i)(http:\/\/|https:\/\/|ftp:\/\/)?([a-z0-9\-\.]+)?[a-z0-9\-]+(!?\.[a-z]{2,4})/', '', url) filename = re.sub(r'\/', '-', filename) if os.path.isdir (domain.group(0)): # print ("Global IF - Папка Домена существует - захожу") os.chdir (domain.group(0)) if os.path.isdir (date): # print ("Second IF - Папка Даты существует - захожу") os.chdir (date) writefile(filename, source) else: # print ("Second ELSE - Папка Даты не существует - Создаю") os.mkdir (date) os.chdir (date) writefile(filename, source) else: # print ("Global ELSE - Папка Домена не существует - Создаю") os.mkdir (domain.group(0)) os.chdir (domain.group(0)) if os.path.isdir (date): # print ("Global ELSE IF - Папка Даты существует - захожу") os.chdir (date) writefile(filename, source) else: # print ("Global ELSE ELSE - Папка Даты не существует - Создаю") os.mkdir (date) os.chdir (date) writefile(filename, source) numstr = numstr + 1
Офлайн
Должно быть типа такого. Регулярки явно нужно переписывать, как работает не проверял.
import re import os import datetime from bs4 import BeautifulSoup from urllib.request import urlopen RE_DOMAIN = re.compile(r"(?i)(?=http:\/\/|https:\/\/|ftp:\/\/)?([a-z0-9\-\.]+)?[a-z0-9\-]+(!?\.[a-z]{2,4})") RE_FILENAME = re.compile(r"(?i)(http:\/\/|https:\/\/|ftp:\/\/)?([a-z0-9\-\.]+)?[a-z0-9\-]+(!?\.[a-z]{2,4})/") DATE = str(datetime.datetime.now().date().strftime('%d.%m.%Y')) def processor(url): source = BeautifulSoup(urlopen(url), "html.parser" ).encode("utf-8") domain = re.search(RE_DOMAIN, url) if not os.path.isdir(domain): os.mkdir(domain) if not os.path.isdir(op.path.join([domain, DATE])): os.mkdir(op.path.join([domain, DATE])) filename = re.sub(r'\/', '-', re.sub(RE_FILENAME, '', url)) with open(os.path.join([domain, DATE, filename+".html"])) as fail: fail.write(source) for x in open ("urls.txt"): processor(x)
Офлайн
в 2 раза короче
Буду разбираться с кодом и новыми методами в нем, спасибо.
Офлайн
RomanusО, прям как я в 2008-м Я тогда C89 изучал, это первый язык был. Бейзик не считаю, который был до этого, так как серьёзного программирования там было не много. Хотя была прога у меня на Бейзике (знал я тогда где-то треть Бейзика), которая вытягивала текст из баз данных ICQ (которая тогда была, как сегодня Telegram), ориентируясь на знакомые байтовые последовательности. Но именно эта прога дала мне понимание кайфа от собственной программы, которая за секунду делала то, что руками не сделаешь и за неделю, и которой больше ни у кого в мире не было. Так что всё имело смысл, даже Бейзик.
Сейчас всё работает, еще освоил немного функции, крайне полезная штука.
RomanusЭти данные должны формироваться внутри функции и возвращаться наружу. При этом сама эта функция может также вызывать функцию для формирования имени файла. А функция формирования имени файла может вызывать функцию для формирования расширения файла. При этом функция создания всего пути не знает, что существует функция формирования расширения файла.
Но, как только я захотел, чтобы он сохранял не в корень, а в {Domain}/{Date}/file.html - начались проблемы.
RomanusВот, например, оно будет так работать неделю, а потом тебе надо будет поменять backup.html на другую строку, что ты будешь делать?def writefile(filename, source): file = open (filename + 'backup.html', 'wb') file.write (source) file.close
def get_filename(): today = get_today() if today == 'monday': return 'backup.html' else: return 'backup.txt' def get_today(): return 'monday' def writefile(filename, source): file = open(filename, 'wb') file.write(source) file.close() ... writefile(get_filename(), get_source())
Отредактировано py.user.next (Июль 21, 2018 01:55:57)
Офлайн