На этом шаге мы приведем текст примера, решающего указанную задачу, и разберем его.
Представьте, что начальник попросил вас создать маленький веб-бот для сканирования веб-страниц и проверки того, содержится ли на них ссылка на домен finxter.com. Кроме того, он попросил вас убедиться, содержат ли описания гиперссылок строку символов 'test' или 'puzzle'. В HTML гиперссылки заключены в теги <a></a>. Сама гиперссылка задается в виде значения атрибута href. Поэтому точная формулировка задачи (отраженной в примере 5.3) звучит так: по заданному строковому значению найти все гиперссылки, указывающие на домен finxter.com и содержащие строки символов 'test' или 'puzzle' в описании ссылки.
## Зависимости import re ## Данные page = ''' <!DOCTYPE html> <html> <body> <h1>My Programming Links</h1> <a href="https://app.finxter.com/">test your Python skills</a> <a href="https://blog.finxter.com/recursion/">Learn recursion</a> <a href="https://nostarch.com/">Great books from NoStarchPress</a> <a href="http://finxter.com/">Solve more Python puzzles</a> </body> </html> ''' ## Однострочник practice_tests = re.findall("(<a.*?finxter.*?(test|puzzle).*?>)", page) ## Результат print(practice_tests)
Этот код находит два вхождения, соответствующих регулярному выражению. Какие?
Наши данные состоят из простой веб-страницы (в виде многострочного строкового значения) на HTML, содержащей набор гиперссылок (теги <a href="">текст ссылки</a>). В нашем однострочном решении для поиска соответствий регулярному выражению (<a.*?finxter.*?(test| puzzle).*?>) используется функция re.findall(). Благодаря этому регулярное выражение возвращает все вхождения в тегах <a...> со следующими ограничениями.
После открывающего тега мы ищем произвольное количество символов ("нежадным" образом, чтобы регулярное выражение не захватывало несколько тегов HTML), за которым следует строка символов 'finxter'. Далее ищем произвольное количество символов ("нежадным" образом), за которым следует одно вхождение строки символов 'test' либо строки символов 'puzzle'. И снова ищем произвольное количество символов ("нежадным" образом), за которым следует закрывающий тег. Таким образом мы находим все теги гиперссылок, содержащие интересующие нас строки символов. Обратите внимание, что данному регулярному выражению соответствуют и теги, в которых строка символов 'test' или 'puzzle' встречается внутри самой ссылки. Учтите также, что мы используем только "нежадные" операторы "звездочка" '.*?', чтобы всегда искать лишь минимальные соответствующие строки символов, вместо, например, очень длинной строки символов, заключенной во множество вложенных тегов.
Результат нашего однострочника:
## Результат print(practice_tests) # [('<a href="https://app.finxter.com/">test your Python skills</a>', 'test'), # ('<a href="http://finxter.com/">Solve more Python puzzles</a>', 'puzzle')]
Нашему регулярному выражению соответствуют две гиперссылки - результат однострочника представляет собой список из двух элементов. Однако каждый из этих элементов не просто строковое значение, а кортеж строковых значений, что отличается от результатов findall(), обсуждавшихся в предыдущих фрагментах кода. В чем тут дело? Возвращаемый тип - список кортежей, по одному значению кортежа для каждой заключенной в скобки группы. Например, скобочная нотация служит для создания группы в регулярном выражении (test|puzzle). При использовании скобочных групп в регулярном выражении функция re.findall() добавляет по одному значению кортежа для каждой найденной группы. Значение кортежа представляет собой подстроку, соответствующую этой конкретной группе. Например, в нашем случае группе (test|puzzle) удовлетворяет подстрока 'puzzle'. Посмотрим внимательнее на скобочные группы, чтобы лучше разобраться с этим понятием.
На следующем шаге мы рассмотрим выделение сумм в долларах из строковых значений.