В далёком 2009, я был постоянным читателем Ars Technica. Они иногда постили статьи о Python, и я заметил одну из них, в которой говорилось об использовании PyGTK для сокращения ссылок. PyGTK было довольно сложно установить на Windows, а так как Windows в тот момент был моей основной средой программирования, я решил использовать wxPython. Так что, в этой статье, мы сделаем действительно простое приложение для сокращения ссылок, а затем создадим более сложное для тех же целей.
Создание простого укорачивателя
Этот простой укорачиватель полностью основан на материалах, которые я прочёл в той статье. Это код прекрасен и лаконичен. Давайте взглянем на версию этого кода для Python 2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import re import urllib import urllib2 import wx class ArsShortener(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, wx.ID_ANY, 'wxArsShortener', size=(300,70)) # Добавляем панель таким образом, чтобы она корректно отображалась на всех платформах panel = wx.Panel(self, wx.ID_ANY) self.txt = wx.TextCtrl(panel, wx.ID_ANY, "", size=(300, -1)) self.txt.Bind(wx.EVT_TEXT, self.onTextChange) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.txt, 0, wx.EXPAND, 5) panel.SetSizer(sizer) def onTextChange(self, event): """""" text = self.txt.GetValue() textLength = len(text) if re.match("^https?://[^ ]+", text) and textLength > 20: apiURL = "http://is.gd/api.php?" + urllib.urlencode(dict(longURL=text)) shortened_URL = urllib2.urlopen(apiURL).read() self.txt.SetValue(shortened_URL) if __name__ == '__main__': app = wx.App(False) frame = ArsShortener() frame.Show() app.MainLoop() |
Это достаточно короткий фрагмент кода. Всё, что вам нужно это рамка, панель и TextCtrl. BoxSizer не требуется, но он может быть полезен в случаях, когда нужно растянуть TextCtrl на всю ширину рамки. Основное внимание стоит уделить нашему хэндлеру событий, который называется onTextChange.
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Здесь мы захватываем текст, который был вставлен в TextCtrl, а затем используем Regular Expression, чтобы определить валидная это ссылка или же нет. Мы также убеждаемся в том, что длина исходной ссылки больше, чем 20 символов. Если оба чека были пройдены, то мы укорачиваем ссылку, используя веб-сайт https://is.gd/.
Примечание: Этот пример в первозданном виде работает только на Windows. В других случаях вы получите SSL-ошибку. Если вы столкнулись с данной проблемой, это значит, что вам нужно обновить и/или настроить ваш пакет openSSL. Вам также стоит проверить свои биндинги Python к openSSL.
В Python 3, библиотеки urllib были объединены в одну, так что код нужно будет переработать, принимая во внимание данное изменение. Вот обновлённый вариант:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# Python 3 import re import urllib.parse import urllib.request import wx class ArsShortener(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, wx.ID_ANY, 'wxArsShortener', size=(300,70)) # Добавляем панель таким образом, чтобы она корректно отображалась на всех платформах panel = wx.Panel(self, wx.ID_ANY) self.txt = wx.TextCtrl(panel, wx.ID_ANY, "", size=(300, -1)) self.txt.Bind(wx.EVT_TEXT, self.onTextChange) sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.txt, 0, wx.EXPAND, 5) panel.SetSizer(sizer) def onTextChange(self, event): """""" text = self.txt.GetValue() textLength = len(text) if re.match("^https?://[^ ]+", text) and textLength > 20: apiURL = "http://is.gd/api.php?" + urllib.parse.urlencode(dict(longURL=text)) shortened_URL = urllib.request.urlopen(apiURL).read() self.txt.SetValue(shortened_URL) if __name__ == '__main__': app = wx.App(False) frame = ArsShortener() frame.Show() app.MainLoop() |
Укорачиваем ссылку, используя другие укорачиватели
В интернете существует масса других укорачивателей ссылок. Например, вы можете предпочитать использовать Bit.ly или tinyURL. Для большинства этих сервисов существую Python-врапперы. В следующем нашем примере мы будем использовать пакеты tinyurl и bitly. Вы можете установить оба, с помощью pip.
1 |
pip install tinyurl bitly |
Учтите, что для корректной работы Bit.ly, вам нужно будет получить ключ его API. Также есть ещё один пакет, который, как по мне, также заслуживает внимания. Он называется pyshorteners. Он поддерживает сразу несколько протоколов в одном пакете. Так что pyshorteners наверняка достоит вашего внимания.
А теперь давайте двигаться дальше и разбираться с кодом. Учтите, что данный код использует urllib из Python 2, так что, если у вас вдруг установлен Python 3, вам нужно будет обновить данный код также, как я сделал это в предыдущей части статьи.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
import re import urllib import urllib2 import wx bitlyFlag = True tinyURLFlag = True try: import bitly except ImportError: bitlyFlag = False try: import tinyurl except ImportError: tinyURLFlag = False class MainPanel(wx.Panel): """ """ def __init__(self, parent): """Constructor""" wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY) self.frame = parent # Создаём виджеты self.createLayout() def createLayout(self): """ Создаём виджеты и размещаем их """ choices = ["is.gd"] if bitlyFlag: choices.append("bit.ly") if tinyURLFlag: choices.append("tinyURL") choices.sort() # Создаём виджеты self.URLCbo = wx.ComboBox(self, wx.ID_ANY, "is.gd", choices=choices, size=wx.DefaultSize, style=wx.CB_DROPDOWN) self.inputURLTxt = wx.TextCtrl(self, value="Paste long URL here") self.inputURLTxt.Bind(wx.EVT_SET_FOCUS, self.onFocus) self.outputURLTxt = wx.TextCtrl(self, style=wx.TE_READONLY) shortenBtn = wx.Button(self, label="Shorten URL") shortenBtn.Bind(wx.EVT_BUTTON, self.onShorten) copyBtn = wx.Button(self, label="Copy to Clipboard") copyBtn.Bind(wx.EVT_BUTTON, self.onCopy) # Создаём сайзеры mainSizer = wx.BoxSizer(wx.VERTICAL) btnSizer = wx.BoxSizer(wx.HORIZONTAL) # Размещаем виджеты mainSizer.Add(self.URLCbo, 0, wx.ALL, 5) mainSizer.Add(self.inputURLTxt, 0, wx.ALL|wx.EXPAND, 5) mainSizer.Add(self.outputURLTxt, 0, wx.ALL|wx.EXPAND, 5) btnSizer.Add(shortenBtn, 0, wx.ALL|wx.CENTER, 5) btnSizer.Add(copyBtn, 0, wx.ALL|wx.CENTER, 5) mainSizer.Add(btnSizer, 0, wx.ALL|wx.CENTER, 5) self.SetSizer(mainSizer) def onCopy(self, event): """ Копирует данные в буфе обмена или выдаёт сообщение об ошибке, если буфер обмена недоступен. """ text = self.outputURLTxt.GetValue() self.do = wx.TextDataObject() self.do.SetText(text) if wx.TheClipboard.Open(): wx.TheClipboard.SetData(self.do) wx.TheClipboard.Close() status = "Copied %s to clipboard" % text self.frame.statusbar.SetStatusText(status) else: wx.MessageBox("Unable to open the clipboard", "Error") def onFocus(self, event): """ Очищается, когда контроль получает фокус """ self.inputURLTxt.SetValue("") def onShorten(self, event): """ Укорачивает ссылку, используя определённый сервис а затем поставляет новую ссылку в текстовый контроль """ text = self.inputURLTxt.GetValue() textLength = len(text) if re.match("^https?://[^ ]+", text) and textLength > 20: pass else: wx.MessageBox("URL is already tiny!", "Error") return URL = self.URLCbo.GetValue() if URL == "is.gd": self.shortenWithIsGd(text) elif URL == "bit.ly": self.shortenWithBitly(text) elif URL == "tinyurl": self.shortenWithTinyURL(text) def shortenWithBitly(self, text): """ Укорачивает ссылку в текстовом контроле, используя bit.ly Запрашивает аккаунт и ключ API для bit.ly """ bitly.API_LOGIN = "username" bitly.API_KEY = "api_key" URL = bitly.shorten(text) self.outputURLTxt.SetValue(URL) def shortenWithIsGd(self, text): """ Сокращает ссылку посредством is.gd, используя URLlib и URLlib2 """ apiURL = "http://is.gd/api.php?" + urllib.urlencode(dict(longURL=text)) shortURL = urllib2.urlopen(apiURL).read() self.outputURLTxt.SetValue(shortURL) def shortenWithTinyURL(self, text): """ Сокращает ссылку с помощью tinyURL """ print "in tinyurl" URL = tinyurl.create_one(text) self.outputURLTxt.SetValue(URL) class URLFrame(wx.Frame): """ wx.Frame class """ def __init__(self): """Constructor""" title = "URL Shortener" wx.Frame.__init__(self, None, wx.ID_ANY, title=title, size=(650, 220)) panel = MainPanel(self) self.statusbar = self.CreateStatusBar() self.SetMinSize((650, 220)) if __name__ == "__main__": app = wx.App(False) frame = URLFrame() frame.Show() app.MainLoop() |
Данный фрагмент кода немного длиннее чем тот, что был в моём простом примере, но в него встроено гораздо больше логики. Сначала я занялся внедрением некоторых исключений, которые понадобятся в случае, если у программиста не установлены модули pyshorteners.
Если их действительно нет, то запускается флаг, который предотвращает добавление данных опций. Вы увидите это в действии в классе MainPanel, а именно в его методе createLayout. Именно здесь мы добавляем опции к списку выбранных для использования в нашем комбо-боксе. В зависимости от того, что вы устанавливали, вы увидите от одной до трёх опций в вашем выпадающем списке.
Следующий интересный фрагмент тот, в котором ввод ссылки в текстовый контроль привязывается к фокус-событию. Мы используем его, чтобы текстовый контроль мог очистится перед вставкой в него следующей ссылки.
Кстати, учтите, что на выходе текстовый контроль доступен только в режиме чтения, то есть вы не сможете отредактировать укороченную ссылку в самом приложении. Это не даёт пользователю повредить только что созданную ссылку. Наконец, мы добрались до двух последних виджетов: кнопок сокращения ссылки и буфера обмена.
Давайте быстренько взглянем, что будет с методом onCopy, если сделать следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def onCopy(self, event): """ Copies data to the clipboard or displays an error dialog if the clipboard is inaccessible. """ text = self.outputURLTxt.GetValue() self.do = wx.TextDataObject() self.do.SetText(text) if wx.TheClipboard.Open(): wx.TheClipboard.SetData(self.do) wx.TheClipboard.Close() status = "Copied %s to clipboard" % text self.frame.statusbar.SetStatusText(status) else: wx.MessageBox("Unable to open the clipboard", "Error") |
Как вы видите, он захватывает текущий текст из текстового контроля для ввода и создаёт из него отдельный TextDataObject. Затем мы пытаемся открыть буфер обмена, и, если у нас получилось, мы вставляем в него данные, используя метод буфера обмена под названием SetData. Наконец, мы сообщаем пользователю о том, что сделали посредством изменения строки статуса рамки.
В методе onShorten, я снова использую обычные выражения, которые взял с программы, найденной мной на Ars, чтобы проверить вставил ли пользователь валидную ссылку, её длину, тем самым убеждаясь, что вставленная ссылка нуждается в укорачивании. Вы получаем тип короткой ссылки из комбо-бокса, а затем используем условия для её укорачивания в соответствии с выбранным методом сокращения.
Метод shortenWithIsGd делает всё то же, что описано в первом примере, так что его мы пропустим. Метод shortenWithBitly показывает, что нам нужно установить свойства LOGIN и API_KEY для того, чтобы мы смогли укоротить ссылку. После того, как мы это сделали, мы просто вызываем метод bitly, который называется shorten(). В методе shortenWithTinyURL всё даже проще: всё что вам нужно будет сделать – вызвать метод tinyURL под названием create_one().
Итоги
Теперь вы знаете несколько способов укорачивания ваших длинных ссылок. Не стесняйтесь добавлять ваши собственные наработки или же добавлять в приложение пакеты от других сервисом по укорачиванию ссылок. В общем, делайте всё, чтобы сделать приложение максимально удобным для вас, и не забывайте получать удовольствие от кодинга!
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»