Перейти к контенту

Python 3

  • Скачать Python
  • IDE
  • Скачать PyCharm
  • Django
  • Tkinter
  • Книги

Создаём укорачиватель ссылок — wxPython #34

В далёком 2009, я был постоянным читателем Ars Technica. Они иногда постили статьи о Python, и я заметил одну из них, в которой говорилось об использовании PyGTK для сокращения ссылок. PyGTK было довольно сложно установить на Windows, а так как Windows в тот момент был моей основной средой программирования, я решил использовать wxPython. Так что, в этой статье, мы сделаем действительно простое приложение для сокращения ссылок, а затем создадим более сложное для тех же целей.

Создание простого укорачивателя

Создаём укорачиватель ссылок - wxPython #34

Этот простой укорачиватель полностью основан на материалах, которые я прочёл в той статье. Это код прекрасен и лаконичен. Давайте взглянем на версию этого кода для Python 2.

Python 2 version
Python
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?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Python Форум Помощи

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Чат
Канал

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Подписаться

Здесь мы захватываем текст, который был вставлен в TextCtrl, а затем используем Regular Expression, чтобы определить валидная это ссылка или же нет. Мы также убеждаемся в том, что длина исходной ссылки больше, чем 20 символов. Если оба чека были пройдены, то мы укорачиваем ссылку, используя веб-сайт https://is.gd/.

Примечание: Этот пример в первозданном виде работает только на Windows. В других случаях вы получите SSL-ошибку. Если вы столкнулись с данной проблемой, это значит, что вам нужно обновить и/или настроить ваш пакет openSSL. Вам также стоит проверить свои биндинги Python к openSSL.

В Python 3, библиотеки urllib были объединены в одну, так что код нужно будет переработать, принимая во внимание данное изменение. Вот обновлённый вариант:

Python
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()

Укорачиваем ссылку, используя другие укорачиватели

Создаём укорачиватель ссылок - wxPython #34

В интернете существует масса других укорачивателей ссылок. Например, вы можете предпочитать использовать Bit.ly или tinyURL. Для большинства этих сервисов существую Python-врапперы. В следующем нашем примере мы будем использовать пакеты tinyurl и bitly. Вы можете установить оба, с помощью pip.

Shell
1
pip install tinyurl bitly

 

Учтите, что для корректной работы Bit.ly, вам нужно будет получить ключ его API. Также есть ещё один пакет, который, как по мне, также заслуживает внимания. Он называется pyshorteners. Он поддерживает сразу несколько протоколов в одном пакете. Так что pyshorteners наверняка достоит вашего внимания.

А теперь давайте двигаться дальше и разбираться с кодом. Учтите, что данный код использует urllib из Python 2, так что, если у вас вдруг установлен Python 3, вам нужно будет обновить данный код также, как я сделал это в предыдущей части статьи.

Python
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, если сделать следующее:

Python
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().

Итоги

Теперь вы знаете несколько способов укорачивания ваших длинных ссылок. Не стесняйтесь добавлять ваши собственные наработки или же добавлять в приложение пакеты от других сервисом по укорачиванию ссылок. В общем, делайте всё, чтобы сделать приложение максимально удобным для вас, и не забывайте получать удовольствие от кодинга!

Vasile Buldumac

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: vasile.buldumac@ati.utm.md

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»
Учебники по Python
  • Django для начинающих
  • Flask уроки для начинающих
  • PyCairo
  • Python 3 для начинающих
  • Python Новости
  • REST API
  • Tkinter
  • wxPython
  • Алгоритмы
  • Анализ кода
  • Асинхронное программирование
  • Базы данных
  • Веб-программирование
  • Видеоуроки
  • Графический Интерфейс
  • Декораторы
  • Нейронные сети
  • Обработка данных
  • Продвинутый
  • Работа с PDF
  • Работа с изображениями
  • Разное из мира IT
  • Создание ботов
  • Создание игр на PyGame
  • Создание игр на Python
  • Создание сайта
  • Сравнение с языками программирования
  • Установка и настройка
  • Хакинг
Изучаем Python 3 на примерах
  • Декораторы
  • Уроки Tkinter
  • Уроки PyCairo
  • Установка Python 3 на Linux
  • Контакты
  • Форум
  • Разное из мира IT