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

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

Ответ 1

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


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

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

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

Карта, увеличивающая целочисленный диапазон до шестизначной базы 26 макс, но непредсказуемо

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

Основной принцип, используемый для сокращения 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

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

Ответ 5

Python short_url является удивительным.

Вот пример:

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)

Что это:)

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

Ответ 6

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

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

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

Ответ 7

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

Edit:

Здесь, как использовать Hashids для создания уникального короткого URL-адреса с Python:

from hashids import Hashids

pk = 123 # Your object 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)

Ответ 8

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

Ответ 9

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

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

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

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

Ответ 10

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

Ответ 11

Моя цель: Создать уникальный идентификатор указанной фиксированной длины, состоящий из символов 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: /questions/41819/how-to-convert-an-integer-to-the-shortest-url-safe-string-in-python/301594#301594
        #   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()

Ответ 12

Вы можете сгенерировать 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))

вывод для N = 10:

'G1ZRbouk2U'