Как сделать уникальный короткий URL с помощью Python?

Как сделать уникальный URL-адрес в Python а-ля https://imgur.com/gM19g или http://tumblr.com/xzh3bi25y При использовании uuid из Python я получаю очень большой. Я хочу что-то более короткое для URL.

11 ответов

Редактировать: Здесь я написал модуль для вас. Используй это. http://code.activestate.com/recipes/576918/


Подсчет от 1 гарантирует короткие уникальные URL. /1, /2, /3 ... и т. Д.

Добавление заглавных и строчных букв в ваш алфавит даст URL-адреса, подобные тем, которые указаны в вашем вопросе. И ты просто считаешь в базе 62 вместо базы 10.

Теперь единственная проблема заключается в том, что URL приходят последовательно. Чтобы это исправить, прочитайте мой ответ на этот вопрос здесь:

Увеличение целочисленного диапазона карты до шестизначного 26 макс., Но непредсказуемо

В основном, подход заключается в том, чтобы просто поменять местами инкрементное значение, чтобы создать впечатление случайности, сохраняя при этом детерминизм и гарантируя отсутствие коллизий.

Я не уверен, что большинство сокращателей URL используют случайную строку. У меня сложилось впечатление, что они записывают URL-адрес в базу данных, а затем используют целочисленный идентификатор новой записи в качестве короткого URL-адреса, закодированный в виде базы 36 или 62 (буквы + цифры).

Python код для преобразования int в строку в произвольных базах здесь.

Short_url Python - это круто.

Вот пример:

import short_url

id = 20  # your object id
domain = 'mytiny.domain' 

shortened_url = "http://{}/{}".format(
                                     domain,
                                     short_url.encode_url(id)
                               )

И декодировать код:

decoded_id = short_url.decode_url(param)

Это оно:)

Надеюсь, это поможет.

Хашидс - отличный инструмент для этого.

Редактировать:

Вот как использовать Hashids для создания уникального короткого URL с помощью Python:

from hashids import Hashids

pk = 123 # Your object's id
domain = 'imgur.com' # Your domain

hashids = Hashids(salt='this is my salt', min_length=6)
link_id = hashids.encode(pk)
url = 'http://{domain}/{link_id}'.format(domain=domain, link_id=link_id)

Я знаю, что этот ответ приходит довольно поздно, но я наткнулся на этот вопрос, когда планировал создать проект сокращения URL. Теперь, когда я реализовал полностью функциональный проект сокращения URL-адресов (исходный код на amitt001 / pygmy, он на Python 3), я добавляю ответ, как это делается. Так что это может помочь кому-то еще:

Основной принцип, используемый для сокращения URL-адресов, состоит в том, чтобы получить int из длинного URL-адреса, а затем использовать кодировку base62 (base32 и т. Д.) Для преобразования этого int в более читаемый короткий URL-адрес.

Как генерируется этот int? Большинство средств сокращения URL-адресов используют некоторое автоинкрементное хранилище данных для добавления URL-адреса в хранилище данных и используют идентификатор автоинкремента для получения кодировки base62 для int.

Пример кодировки base62 из строковой программы:

# Base-62 hash

import string
import time

_BASE = 62


class HashDigest:
    """Base base 62 hash library."""

    def __init__(self):
        self.base = string.ascii_letters + string.digits
        self.short_str = ''

    def encode(self, j):
        """Returns the repeated div mod of the number.
        :param j: int
        :return: list
        """
        if j == 0:
            return [j]
        r = []
        dividend = j
        while dividend > 0:
            dividend, remainder = divmod(dividend, _BASE)
            r.append(remainder)
        r = list(reversed(r))
        return r

    def shorten(self, i):
        """
        :param i:
        :return: str
        """
        self.short_str = ""
        encoded_list = self.encode(i)
        for val in encoded_list:
            self.short_str += self.base[val]
        return self.short_str

Это всего лишь частичный код, и он не показывает, как декодируется base62. Ознакомьтесь с полным кодом кодировки base62 в core / hashdigest.py

Все ссылки в этом ответе сокращены из проекта, который я создал

Этот модуль будет делать то, что вы хотите, гарантируя, что строка глобально уникальна (это UUID):

http://pypi.python.org/pypi/shortuuid/0.1

Если вам нужно что-то более короткое, вы сможете укоротить его до желаемой длины и при этом получить что-то, что, вероятно, позволит избежать столкновений.

Причина, по которой UUID являются длинными, заключается в том, что они содержат много информации, так что они могут быть гарантированно глобально уникальными.

Если вы хотите что-то более короткое, то вам нужно сделать что-то вроде генерации случайной строки, проверить, находится ли она во вселенной уже сгенерированных строк, и повторять до тех пор, пока не получите неиспользованную строку. Вам также необходимо следить за параллелизмом (что, если эта же строка будет сгенерирована отдельным процессом до того, как вы вставите ее в набор строк?).

Если вам нужна помощь в генерации случайных строк в Python, этот другой вопрос может помочь.

На самом деле не имеет значения, что это Python, но вам просто нужна хеш-функция, которая отображается на желаемую длину. Например, может быть, использовать MD5, а затем взять только первый n персонажи. В этом случае вам придется следить за коллизиями, поэтому вы можете выбрать что-то более надежное с точки зрения обнаружения коллизий (например, использование простых чисел для циклического перемещения по пространству хеш-строк).

Вы можете сгенерировать случайную строку N:

import string
import random

def short_random_string(N:int) -> str:

    return ''.join(random.SystemRandom().choice(
                    string.ascii_uppercase + \
                    string.ascii_lowercase + \
                    string.digits) for _ in range(N))

так,

print (short_random_string(10) )
#'G1ZRbouk2U'

все в нижнем регистре

print (short_random_string(10).lower() )
#'pljh6kp328'

Я не знаю, можете ли вы использовать это, но мы генерируем объекты содержимого в Zope, которые получают уникальные числовые идентификаторы, основанные на строках текущего времени, в миллисекундах (например, 1254298969501)

Может быть, вы можете угадать остальное. Используя рецепт, описанный здесь: Как преобразовать целое число в самую короткую URL-безопасную строку в Python?, мы кодируем и декодируем реальный идентификатор на лету, без необходимости хранения. Например, целое число из 13 цифр сокращено до 7 буквенно-цифровых символов в базе 62.

Чтобы завершить реализацию, мы зарегистрировали короткое (xxx.yy) имя домена, которое декодирует и выполняет перенаправление 301 для "не найденных" URL,

Если бы я начинал заново, я бы вычел время "в начале" (в миллис) из числового идентификатора до кодирования, а затем снова добавил бы его при декодировании. Или еще при создании объектов. Без разницы. Это было бы намного короче..

Попробуйте это http://code.google.com/p/tiny4py/... Это все еще в стадии разработки, но очень полезно!!

Моя цель: создать уникальный идентификатор указанной фиксированной длины, состоящий из символов 0-9 а также a-z, Например:

zcgst5od
9x2zgn0l
qa44sp0z
61vv1nl5
umpprkbt
ylg4lmcy
dec0lu1t
38mhd8i5
rx00yf0e
kc2qdc07

Вот мое решение. (Адаптировано из этого ответа kmkaplan.)

import random

class IDGenerator(object):
    ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz"

    def __init__(self, length=8):
        self._alphabet_length = len(self.ALPHABET)
        self._id_length = length

    def _encode_int(self, n):
        # Adapted from:
        #   Source: https://stackru.com/a/561809/1497596
        #   Author: https://stackoverflow.com/users/50902/kmkaplan

        encoded = ''
        while n > 0:
            n, r = divmod(n, self._alphabet_length)
            encoded = self.ALPHABET[r] + encoded
        return encoded

    def generate_id(self):
        """Generate an ID without leading zeros.

        For example, for an ID that is eight characters in length, the
        returned values will range from '10000000' to 'zzzzzzzz'.
        """

        start = self._alphabet_length**(self._id_length - 1)
        end = self._alphabet_length**self._id_length - 1
        return self._encode_int(random.randint(start, end))

if __name__ == "__main__":
    # Sample usage: Generate ten IDs each eight characters in length.
    idgen = IDGenerator(8)

    for i in range(10):
        print idgen.generate_id()
Другие вопросы по тегам