Форум сайта python.su
Доброй ночи, форумчане!
Прошу помощи в написании регулярного выражения для отбора ссылок.
Выражение должно начинаться на /catalog/, далее может следовать последовательность буквенных символов и /, но если в конце встречается запись ?page=12, ссылку нужно игнорировать.
Например, ссылки удовлетворяющие условию:
/catalog/
/catalog/fdff/df
и не удовлетворяющие:
/catalog/fdff/df/?page=3
google.com/dfdf/
Вот что я пытался сделать, но результат не тот
'(^(\/catalog\/)[a-z\/]*)(?!\?page=\d+)'
Отредактировано Romissevd (Март 28, 2017 22:27:31)
Офлайн
Попробуйте так
'\/catalog\/[a-z\/]*[^\?page=?\d+]$'
Офлайн
>>> import re >>> >>> pat = r'^/catalog/[a-zA-Z/]*(?!\?page=\d+)$' >>> >>> lst = ["/catalog/", ... "/catalog/fdff/df", ... "/catalog/fdff/df/?page=3", ... "google.com/dfdf/"] >>> >>> list(filter(re.compile(pat).search, lst)) ['/catalog/', '/catalog/fdff/df'] >>>
Офлайн
Можно также использовать функцию urllib.parse.urlparse (встроенный модуль python), она позволяет разбить url на компоненты, а потом уже можно и условия проверять.
Офлайн
scidamА потом склеивать обратно, если подошло. Лучше с текстом работать. Максимум, что можно посоветовать при подобных проблемах (когда сложно составить регулярку), - разделить задачу на этапы.
она позволяет разбить url на компоненты, а потом уже можно и условия проверять
Отредактировано py.user.next (Март 29, 2017 17:21:57)
Офлайн
py.user.nextСпасибо большое за помощь. Понимал, что кручусь где-то возле, но каша в голове не дала дойти до результата.
py.user.nextтак и поступил приблизительно, до момента получения подходящего паттерна.
Для данной задачи будет:
1) Выбрать всё, что начинается на /catalog/.
2) Из полученного выбрать всё, что не заканчивается на ?page=число .
Офлайн
py.user.nextСклеить там не сложно – для этого специальный метод есть – parsed_instance.geturl().
А потом склеивать обратно, если подошло
from urllib import parse list(map(lambda x: x.geturl(), filter(lambda x: x.path.startswith('/catalog/') and 'page' not in parse.parse_qs(x.query), map(parse.urlparse, lst))))
Отредактировано scidam (Март 30, 2017 04:48:41)
Офлайн
scidamДа совсем не читабельно, что уж там говорить. А по операциям - тем более завал, представь просто миллион ссылок так обработать (разрезать-искать-искать-искать-склеить). Регулярка моментально найдёт, так как оптимизирована на базовом уровне.
Извиняюсь, что может быть не совсем читабельно
scidamЕсли у тебя варианты появляются, ты можешь просто добавить вторую регулярку. А потом с ней можно что сделать? Правильно, объединить с первой через дизъюнкцию | , получится снова одна регулярка, которая будет быстро проверяться. Да и регулярки можно вынести в такую как бы базу данных (в таблицу), которую пополнять потом. Если Dive Into Python 3 почитаешь, там увидишь пример на языковых правилах, как это делается, - правила заносятся в список, а потом в коде подцепляются из него постепенно.
Но вот вдруг кроме page, будет какой-нибудь еще GET параметер, т.е.
?page=10&theme='blue' или еще что, а еще после catalog/ могут быть отличные от a-zA-Z символы – их придется добавить в re…
Отредактировано py.user.next (Март 30, 2017 05:12:18)
Офлайн
py.user.nextДа, регулярка быстрей, конечно…
Регулярка моментально найдёт, так как оптимизирована на базовом уровне.
import random, string, re import timeit from urllib import parse def gen_urls(n=1000): choices= ['/catalog/%s/?page=12', '/catalog/%s/someurl'] res = [] for i in range(n): m = random.randrange(20,30) intermediate = ''.join(random.choice(string.ascii_uppercase + '/') for _ in range(m)) res.append(random.choice(choices)%intermediate) return res data = gen_urls(n=10000) pat = re.compile(r'^/catalog/[a-zA-Z/]*(?!\?page=\d+)$') def code1(): return list(filter(pat.search, data)) def code2(): return list(map(lambda x: x.geturl(), filter(lambda x: x.path.startswith('/catalog/') and 'page' not in parse.parse_qs(x.query), map(parse.urlparse, data)))) print(timeit.timeit("code1()", setup="from __main__ import code1", number=100)/100) #0,01. print(timeit.timeit("code2()", setup="from __main__ import code2", number=100)/100) #0.16
Офлайн
scidamЧто-то ты намастрячил фикстуру, можно просто десять ссылок взять и результат тот же будет. Главное, чтобы разные коды получали одинаковые данные.
Вот, на скорую руку, подтверждение:
Офлайн