web-dev-qa-db-ja.com

Pythonで一意の短いURLを作成するにはどうすればよいですか?

Python a la http://imgur.com/gM19g または http://tumblr.com/xzh3bi25y pythonからuuidを使用する場合、非常に大きなものを取得します。 URL。

35
Esteban Feldman

編集:ここで、私はあなたのためにモジュールを書きました。これを使って。 http://code.activestate.com/recipes/576918/


1からカウントアップすると、短い一意のURLが保証されます。/1、/ 2、/ 3 ...など.

アルファベットに大文字と小文字を追加すると、質問のようなURLが表示されます。そして、あなたは単にbase-10ではなくbase-62を数えているだけです。

唯一の問題は、URLが連続して来ることです。それを修正するには、この質問に対する私の答えをここで読んでください:

増分する整数範囲を最大6桁の基数26にマップしますが、予測できません

基本的に、アプローチはインクリメントする値のビットを単純に入れ替えて、決定性を維持し、衝突がないことを保証しながら、ランダムに見えるようにします。

24
FogleBird

ほとんどのURL短縮機能でランダムな文字列が使用されているかどうかはわかりません。私の印象は、彼らがURLをデータベースに書き込んでから、新しいレコードの整数IDをショートURLとして使用し、36または62のエンコードされたベース(文字+数字)を使用することです。

Intを任意のベースの文字列に変換するPythonコードは here です。

17
Ned Batchelder

このモジュールはあなたが望むことをし、文字列がグローバルに一意であることを保証します(それはUUIDです):

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

もっと短いものが必要な場合は、それを希望の長さに切り詰めても、おそらく衝突を合理的に回避できるものを取得できるはずです。

この回答はかなり遅くなりますが、URL短縮プロジェクトを作成することを計画していたときに、この質問に遭遇しました。これで、完全に機能するURL短縮プログラム(ソースコード amitt0​​01/pygmy )を実装したので、他の人のためにここに回答を追加します。

URL短縮の背後にある基本原則は、長いURLからintを取得し、base62(base32など)エンコーディングを使用して、このintをより読みやすい短いURLに変換することです。

このintはどのように生成されますか?

ほとんどのURL短縮ツールは、自動インクリメントデータストアを使用してURLをデータストアに追加し、自動インクリメントIDを使用してintのbase62エンコーディングを取得します。

文字列プログラムからのサンプル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エンコーディングを示す部分的なコードです。 core/hashdigest.py で完全なbase62エンコード/デコードコードを確認してください。

この回答のすべてのリンクは、私が作成したプロジェクトから短縮されています

4
Amit Tripathi

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)

それでおしまい :)

これがお役に立てば幸いです。

4
Hasan Agha

Hashids は、このための素晴らしいツールです。

編集:

Hashidsを使用してPythonで一意の短いURLを生成する方法は次のとおりです。

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)
3
yndolok

UUIDが長いのは、グローバルに一意であることを保証できるように多くの情報が含まれているためです。

もっと短いものが必要な場合は、ランダムな文字列を生成し、それがすでに生成された文字列の中にあるかどうかを確認し、未使用の文字列が得られるまで繰り返す必要があります。ここで同時実行性に注意する必要もあります(同じ文字列が文字列のセットに挿入される前に別のプロセスによって生成された場合はどうなるでしょうか?)。

Pythonでランダムな文字列を生成するのに助けが必要な場合は、この その他の質問 が役立つことがあります。

2
Dominic Rodger

これを使用できるかどうかはわかりませんが、ミリ秒単位の現在の時間文字列に基づいて一意の数値IDを取得するコンテンツオブジェクトをZopeで生成します(例:1254298969501)

多分あなたは残りを推測することができます。ここで説明するレシピを使用して: 整数をPythonで最短のURLセーフ文字列に変換する方法 、実際のIDをオンザフライでエンコードおよびデコードします、ストレージは必要ありません。たとえば、13桁の整数は、基数62で7文字の英数字に削減されます。

実装を完了するために、短い(xxx.yy)ドメイン名を登録しました。これは、「見つからない」URLをデコードして301リダイレクトを行います。

やり直す場合は、エンコードする前に数値IDから「やり直し」時間(ミリ秒単位)を差し引き、デコード時に再度追加します。または、オブジェクトを生成するとき。なんでも。それはずっと短いでしょう。

1
Ken

これがPythonであることは重要ではありませんが、必要な長さにマップするハッシュ関数が必要です。たとえば、MD5を使用して、最初のn文字だけを取る場合があります。ただし、その場合は衝突に注意する必要があります。そのため、衝突検出に関してもう少し堅牢なものを選択したい場合があります(素数を使用してハッシュ文字列のスペースを循環するなど)。

1

My Goal:文字0-9およびa-zで構成される指定された固定長の一意の識別子を生成します。例えば:

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

これが私の解決策です。 this answer から転載 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://stackoverflow.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()
0
DavidRR

これを試してください http://code.google.com/p/tiny4py/ ...まだ開発中ですが、非常に便利です!!

0
Erenwoid

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」

0
sandes