ब्लॉग / डेवलपर गाइड
सोशल मीडिया प्रोफ़ाइल URL को पार्स और नॉर्मलाइज़ कैसे करें (Instagram, TikTok, YouTube, X)
क्रिएटर अपने प्रोफ़ाइल लिंक हर सोचे जा सकने वाले रूप में पेस्ट करते हैं: www के साथ और बिना, मोबाइल ऐप से ट्रैकिंग पैरामीटर के साथ, शॉर्ट लिंक के रूप में, पुराने twitter.com URL के रूप में, या प्रोफ़ाइल की जगह किसी पोस्ट के लिंक के रूप में। अगर आपका प्रोडक्ट इन स्ट्रिंग को जैसे आती हैं वैसे ही सेव करता है, तो एक ही क्रिएटर तीन बार दिखता है और आपके join चुपचाप चूक जाते हैं। यह गाइड दिखाती है कि किसी भी Instagram, TikTok, YouTube या X प्रोफ़ाइल URL को एक प्लेटफ़ॉर्म, एक हैंडल या चैनल ID, और एक कैनोनिकल URL में कैसे बदलें, JavaScript और Python में टेस्ट किए कोड के साथ।
प्रोफ़ाइल URL नॉर्मलाइज़ करना क्यों ज़रूरी है
प्रोफ़ाइल URL एक पहचानकर्ता है, और पहचानकर्ता तभी काम करते हैं जब वे एक ही तरह लिखे जाएँ। https://www.instagram.com/natgeo/, instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA== और https://m.instagram.com/natgeo सब एक ही अकाउंट की ओर इशारा करते हैं, पर स्ट्रिंग के रूप में ये तीन अलग मान हैं।
- डुप्लिकेट हटाना। जब कोई क्रिएटर दो बार साइन अप करे, या टीम के दो सदस्य एक ही इन्फ़्लुएंसर को कैंपेन में जोड़ें, तो आपको एक रिकॉर्ड चाहिए, दो नहीं।
- Join। अपने CRM को किसी दूसरे टूल के एक्सपोर्ट से मिलाना तभी काम करता है जब दोनों तरफ़ एक ही key हो।
- ग़लत इनपुट जल्दी रोकना। किसी reel, सर्च पेज या लॉगिन स्क्रीन का लिंक प्रोफ़ाइल नहीं है। इसे इनपुट के समय पकड़ना बाद में साफ़ करने से सस्ता है।
- API कॉल करना। आधिकारिक API को हैंडल या ID चाहिए, ट्रैकिंग पैरामीटर लगा URL नहीं।
लक्ष्य एक छोटा, सख़्त फ़ंक्शन है: यह वही स्वीकार करता है जो यूज़र असल में पेस्ट करते हैं, असली प्रोफ़ाइल URL के लिए नॉर्मलाइज़्ड नतीजा लौटाता है, और बाकी सब के लिए null लौटाता है।
आपको दिखने वाले URL के रूप
नीचे के रूप अक्टूबर 2026 में लाइव साइटों पर जाँचे गए। प्लेटफ़ॉर्म बिना बताए अपनी routing बदलते हैं, इसलिए इसे एक स्नैपशॉट मानें और अपने टेस्ट केस अपडेट रखें।
- प्रोफ़ाइल
https://www.instagram.com/<handle>/पर होती हैं। सादाinstagram.comऔरm.instagram.comहोस्टwww.instagram.comपर रीडायरेक्ट करते हैं। - ऐप से शेयर किए लिंक में अक्सर
?igsh=पैरामीटर होता है। पूरी query string और fragment हटा दें। - पोस्ट
/p/<code>/हैं, reels/reel/<code>/हैं, और stories/stories/<handle>/<id>/हैं। इनमें से कोई भी प्रोफ़ाइल URL नहीं है, चाहे path में हैंडल दिखे। /explore/,/accounts/और/direct/जैसे ऐप route पहले path segment को हैंडल के साथ साझा करते हैं, इसलिए आरक्षित शब्दों की एक सूची चाहिए। नीचे के कोड की सूची पूरी नहीं है।
TikTok
- प्रोफ़ाइल
https://www.tiktok.com/@<handle>हैं। सादाtiktok.comहोस्टwwwपर रीडायरेक्ट करता है। - वीडियो
/@<handle>/video/<id>हैं। हैंडल लेखक का है, पर URL वीडियो का लिंक है, इसलिए नीचे का पार्सर इसे अस्वीकार करता है। vm.tiktok.com,vt.tiktok.comऔरwww.tiktok.com/t/<code>/पर शॉर्ट लिंक में कोई हैंडल नहीं होता। यह देखने के लिए कि वे कहाँ ले जाते हैं, आपको HTTP redirect फ़ॉलो करना होगा, फिर आख़िरी URL पार्स करना होगा।@के बिना path (जैसेtiktok.com/khaby.lame) प्रोफ़ाइल URL नहीं है।
YouTube
- हैंडल URL:
https://www.youtube.com/@<handle>। YouTube का Help Center कहता है कि हैंडल अपने आप चैनल का URL बन जाता है। - चैनल ID URL:
https://www.youtube.com/channel/UC...। यह स्थिर रूप है। व्यवहार में चैनल ID 24 अक्षर की होती हैं औरUCसे शुरू होती हैं। Google इस फ़ॉर्मैट का दस्तावेज़ नहीं देता, इसलिए नीचे की जाँच एक मोटी सीमा है, नियम नहीं। - पुराने रूप:
/user/<username>और/c/<customname>। दोनों आज भी काम करते हैं, और Help Center कहता है कि पुराने पर्सनलाइज़्ड URL काम करते रहेंगे। खोज किए बिना इनमें से कोई भी चैनल ID नहीं बताता। - कुछ चैनल के लिए सादा
youtube.com/<name>भी अभी काम करता है, पर यह साइट के route के साथ namespace साझा करता है, इसलिए नीचे का पार्सर इसे स्वीकार नहीं करता। /@handle/videosऔर/channel/UC.../featuredजैसे टैब चैनल के ही हैं और इन्हें स्वीकार करना सुरक्षित है।m.youtube.comwww.youtube.comपर रीडायरेक्ट करता है। वीडियो लिंक (/watch?v=,/shorts/,youtu.be/<id>) चैनल नहीं हैं।
X (पहले Twitter)
- प्रोफ़ाइल
https://x.com/<handle>हैं।twitter.com,www.twitter.com,www.x.com,mobile.twitter.comऔरmobile.x.comसबx.comयाtwitter.comकी प्रोफ़ाइल पर रीडायरेक्ट करते हैं, इसलिए इन्हें एक ही प्लेटफ़ॉर्म मानें। - पोस्ट
/<handle>/status/<id>हैं। TikTok वीडियो की तरह, ये लेखक का नाम बताते हैं पर प्रोफ़ाइल URL नहीं हैं। /home,/explore,/search,/settings,/notifications,/messagesजैसे ऐप route और/i/के नीचे का सब कुछ हैंडल नहीं हैं।- शेयर किए लिंक में अक्सर
?s=और?t=पैरामीटर जुड़ते हैं। इन्हें हटा दें।
हर प्लेटफ़ॉर्म पर हैंडल के अक्षरों के नियम
हैंडल की जाँच से टाइपो और ज़्यादातर नॉन-प्रोफ़ाइल path पकड़ में आते हैं। जहाँ प्लेटफ़ॉर्म अपने नियम प्रकाशित करते हैं वहाँ वही इस्तेमाल करें, और जहाँ नहीं करते वहाँ जाँच ढीली रखें, ताकि कोई असली अकाउंट कभी अस्वीकार न हो।
| प्लेटफ़ॉर्म | मान्य अक्षर | लंबाई | बड़े-छोटे अक्षर | स्रोत |
|---|---|---|---|---|
| अक्षर, अंक, पीरियड, अंडरस्कोर | 30 का अक्सर ज़िक्र होता है; Instagram के हेल्प पेज में नहीं मिला | case-insensitive मानें; छोटे अक्षरों में सेव करें | Instagram Help Center पीरियड, अंक और अंडरस्कोर का ज़िक्र करता है | |
| TikTok | अक्षर, अंक, अंडरस्कोर, पीरियड; पीरियड पर ख़त्म नहीं हो सकता | 2 से 24 | URL में case-insensitive (@TikTok tiktok पर पहुँचता है) | TikTok Support, username बदलना |
| YouTube | समर्थित भाषाओं के अक्षर या अंक, साथ में अंडरस्कोर, हाइफ़न, पीरियड और Latin middle dot (पहले या आख़िर में नहीं) | ज़्यादातर लिपियों के लिए 3 से 30; Han, Hangul और कुछ दूसरी लिपियों के लिए कम सीमा | case-sensitive नहीं | YouTube Help, हैंडल दिशानिर्देश |
| X | अक्षर, अंक और अंडरस्कोर | 15 तक; नए username 4 से लंबे होने चाहिए, पर पुराने छोटे हैंडल मौजूद हैं | case-sensitive नहीं (x.com/JACK का कैनोनिकल रूप x.com/jack है) | X Help Center, username नियम |
नॉर्मलाइज़ करने का एल्गोरिदम
- Step 1खाली जगह हटाएँ और scheme जोड़ें
whitespace और भटके हुए angle brackets हटाएँ। अगर इनपुट में scheme नहीं है, तो आगे
https://जोड़ें ताकिinstagram.com/natgeoपार्स हो सके। - Step 2असली URL पार्सर से पार्स करें
JavaScript में
new URL()या Python मेंurllib.parse.urlsplitइस्तेमाल करें, पूरी स्ट्रिंग पर regex कभी नहीं। पार्सर port, user info और एन्कोड किए अक्षरों को सँभालता है, औरhttps://instagram.com@evil.com/natgeoको Instagram के रूप में पास होने से रोकता है। - Step 3होस्ट नॉर्मलाइज़ करें
इसे छोटे अक्षरों में करें और आगे का एक
www.,m.याmobile.हटाएँ। फिर इसे होस्ट की एक सटीक allow-list में खोजें।includes("instagram.com")कभी इस्तेमाल न करें, जोinstagram.com.evil.comसे भी मेल खाता है। - Step 4Query string और fragment हटाएँ
igsh,s,tऔरlangजैसे ट्रैकिंग पैरामीटर कभी नहीं बदलते कि URL किस प्रोफ़ाइल की ओर इशारा करता है। - Step 5Path को बाँटें और डिकोड करें
/पर बाँटें, ख़ाली segment हटाएँ (इससे आख़िरी स्लैश हट जाते हैं) और हर एक को percent-decode करें। ग़लत एन्कोडिंग को अमान्य इनपुट मानें। - Step 6प्लेटफ़ॉर्म के हिसाब से रास्ता चुनें
हर प्लेटफ़ॉर्म का रूप लागू करें: Instagram और X पर एक segment, TikTok पर
@वाला segment, और YouTube पर@handle,channel/UC...,user/nameयाc/name। आरक्षित शब्द अस्वीकार करें। - Step 7हैंडल जाँचें और छोटे अक्षर करें
हैंडल को प्लेटफ़ॉर्म के अक्षर नियमों से जाँचें, फिर छोटे अक्षरों में करें। YouTube चैनल ID को छोटे अक्षरों में न करें: वे case-sensitive हैं।
- Step 8कैनोनिकल URL बनाएँ
हिस्सों से URL को एक तय होस्ट पर दोबारा बनाएँ, ताकि हर बराबर इनपुट से बिल्कुल एक ही स्ट्रिंग बने।
- Step 9शॉर्ट लिंक अलग से सँभालें
TikTok शॉर्ट लिंक पहचानें, HTTP अनुरोध से redirect फ़ॉलो करें, और आख़िरी URL को फिर से पार्सर से गुज़ारें। इसे शुद्ध फ़ंक्शन से बाहर रखें ताकि पार्सिंग तेज़ और टेस्ट करने लायक रहे।
JavaScript और Python में कोड
दोनों फ़ंक्शन एक ही इनपुट के लिए एक जैसे ऑब्जेक्ट लौटाते हैं: हैंडल URL के लिए { platform, handle, canonicalUrl }, YouTube चैनल ID के लिए { platform, channelId, canonicalUrl }, YouTube के दो पुराने रूपों के लिए username या customName, और जो भी प्रोफ़ाइल URL नहीं है उसके लिए null। किसी को भी dependency की ज़रूरत नहीं।
JavaScript (Node 18+)
const HOSTS = {
"instagram.com": "instagram",
"tiktok.com": "tiktok",
"youtube.com": "youtube",
"x.com": "x",
"twitter.com": "x",
};
const IG_RESERVED = new Set(["p", "reel", "reels", "tv", "stories", "explore", "accounts", "direct"]);
const X_RESERVED = new Set([
"home", "explore", "search", "i", "settings", "notifications", "messages",
"compose", "intent", "hashtag", "login", "signup", "logout", "tos", "privacy",
]);
const IG_HANDLE = /^[a-z0-9._]{1,30}$/;
const TIKTOK_HANDLE = /^[a-z0-9._]{2,24}$/;
const X_HANDLE = /^[a-z0-9_]{1,15}$/;
const YT_HANDLE = /^[\p{L}\p{M}\p{N}._\-·]{1,30}$/u;
const YT_CHANNEL_ID = /^UC[A-Za-z0-9_-]{22}$/;
const YT_LEGACY_NAME = /^[A-Za-z0-9._-]{1,100}$/;
export function parseProfileUrl(input) {
if (typeof input !== "string") return null;
let raw = input.trim().replace(/^<|>$/g, "");
if (!raw) return null;
if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) raw = "https://" + raw;
let url;
try {
url = new URL(raw);
} catch {
return null;
}
if (url.protocol !== "https:" && url.protocol !== "http:") return null;
const host = url.hostname.toLowerCase().replace(/^(www|m|mobile)\./, "");
const platform = HOSTS[host];
if (!platform) return null;
let segments;
try {
segments = url.pathname.split("/").filter(Boolean).map(decodeURIComponent);
} catch {
return null; // malformed percent-encoding
}
const [first = "", second] = segments;
if (platform === "instagram") {
const handle = first.toLowerCase();
if (segments.length !== 1 || IG_RESERVED.has(handle) || !IG_HANDLE.test(handle)) return null;
return { platform, handle, canonicalUrl: `https://www.instagram.com/${handle}/` };
}
if (platform === "tiktok") {
if (segments.length !== 1 || !first.startsWith("@")) return null;
const handle = first.slice(1).toLowerCase();
if (!TIKTOK_HANDLE.test(handle) || handle.endsWith(".")) return null;
return { platform, handle, canonicalUrl: `https://www.tiktok.com/@${handle}` };
}
if (platform === "x") {
const handle = first.toLowerCase();
if (segments.length !== 1 || X_RESERVED.has(handle) || !X_HANDLE.test(handle)) return null;
return { platform, handle, canonicalUrl: `https://x.com/${handle}` };
}
// YouTube: /@handle[/tab], /channel/UC...[/tab], /user/name, /c/name
if (first.startsWith("@")) {
const handle = first.slice(1).toLowerCase();
if (!YT_HANDLE.test(handle) || /^[._\-·]|[._\-·]$/.test(handle)) return null;
return { platform, handle, canonicalUrl: `https://www.youtube.com/@${encodeURIComponent(handle)}` };
}
if (first === "channel" && second && YT_CHANNEL_ID.test(second)) {
return { platform, channelId: second, canonicalUrl: `https://www.youtube.com/channel/${second}` };
}
if ((first === "user" || first === "c") && second && segments.length === 2 && YT_LEGACY_NAME.test(second)) {
const key = first === "user" ? "username" : "customName";
return { platform, [key]: second, canonicalUrl: `https://www.youtube.com/${first}/${second}` };
}
return null; // videos, shorts, playlists, search and anything else
}
const SHORT_HOSTS = new Set(["vm.tiktok.com", "vt.tiktok.com"]);
export function isShortLink(input) {
try {
const url = new URL(/^https?:\/\//i.test(input) ? input : "https://" + input);
const host = url.hostname.toLowerCase();
return SHORT_HOSTS.has(host) || (host.replace(/^www\./, "") === "tiktok.com" && url.pathname.startsWith("/t/"));
} catch {
return false;
}
}
export async function resolveShortLink(input) {
const res = await fetch(/^https?:\/\//i.test(input) ? input : "https://" + input, {
redirect: "follow",
signal: AbortSignal.timeout(10_000),
});
await res.body?.cancel();
return res.url; // the final URL after every redirect
}resolveShortLink बिल्ट-इन fetch इस्तेमाल करता है, जो redirect फ़ॉलो करता है और आख़िरी पता res.url के रूप में देता है। जब isShortLink(link) true हो तो parseProfileUrl(await resolveShortLink(link)) कॉल करें। शॉर्ट लिंक प्रोफ़ाइल के बजाय किसी वीडियो पर भी ले जा सकता है, उस हालत में पार्सर सही तरह null लौटाता है।
Python 3
import re
import unicodedata
import urllib.request
from urllib.parse import quote, unquote, urlsplit
HOSTS = {
"instagram.com": "instagram",
"tiktok.com": "tiktok",
"youtube.com": "youtube",
"x.com": "x",
"twitter.com": "x",
}
IG_RESERVED = {"p", "reel", "reels", "tv", "stories", "explore", "accounts", "direct"}
X_RESERVED = {
"home", "explore", "search", "i", "settings", "notifications", "messages",
"compose", "intent", "hashtag", "login", "signup", "logout", "tos", "privacy",
}
IG_HANDLE = re.compile(r"[a-z0-9._]{1,30}")
TIKTOK_HANDLE = re.compile(r"[a-z0-9._]{2,24}")
X_HANDLE = re.compile(r"[a-z0-9_]{1,15}")
YT_CHANNEL_ID = re.compile(r"UC[A-Za-z0-9_-]{22}")
YT_LEGACY_NAME = re.compile(r"[A-Za-z0-9._-]{1,100}")
YT_PUNCT = "._-·"
def _is_youtube_handle(handle):
if not 1 <= len(handle) <= 30 or handle[0] in YT_PUNCT or handle[-1] in YT_PUNCT:
return False
return all(
ch.isalnum() or ch in YT_PUNCT or unicodedata.category(ch).startswith("M")
for ch in handle
)
def parse_profile_url(value):
if not isinstance(value, str):
return None
raw = value.strip().strip("<>")
if not raw:
return None
if not re.match(r"^[a-z][a-z0-9+.-]*://", raw, re.I):
raw = "https://" + raw
try:
url = urlsplit(raw)
host = (url.hostname or "").lower()
except ValueError:
return None
if url.scheme.lower() not in ("http", "https"):
return None
host = re.sub(r"^(www|m|mobile)\.", "", host)
platform = HOSTS.get(host)
if not platform:
return None
try:
segments = [unquote(s, errors="strict") for s in url.path.split("/") if s]
except UnicodeDecodeError:
return None # malformed percent-encoding
first = segments[0] if segments else ""
second = segments[1] if len(segments) > 1 else None
if platform == "instagram":
handle = first.lower()
if len(segments) != 1 or handle in IG_RESERVED or not IG_HANDLE.fullmatch(handle):
return None
return {"platform": platform, "handle": handle,
"canonicalUrl": f"https://www.instagram.com/{handle}/"}
if platform == "tiktok":
if len(segments) != 1 or not first.startswith("@"):
return None
handle = first[1:].lower()
if not TIKTOK_HANDLE.fullmatch(handle) or handle.endswith("."):
return None
return {"platform": platform, "handle": handle,
"canonicalUrl": f"https://www.tiktok.com/@{handle}"}
if platform == "x":
handle = first.lower()
if len(segments) != 1 or handle in X_RESERVED or not X_HANDLE.fullmatch(handle):
return None
return {"platform": platform, "handle": handle, "canonicalUrl": f"https://x.com/{handle}"}
# YouTube: /@handle[/tab], /channel/UC...[/tab], /user/name, /c/name
if first.startswith("@"):
handle = first[1:].lower()
if not _is_youtube_handle(handle):
return None
return {"platform": platform, "handle": handle,
"canonicalUrl": f"https://www.youtube.com/@{quote(handle, safe='._-')}"}
if first == "channel" and second and YT_CHANNEL_ID.fullmatch(second):
return {"platform": platform, "channelId": second,
"canonicalUrl": f"https://www.youtube.com/channel/{second}"}
if first in ("user", "c") and second and len(segments) == 2 and YT_LEGACY_NAME.fullmatch(second):
key = "username" if first == "user" else "customName"
return {"platform": platform, key: second,
"canonicalUrl": f"https://www.youtube.com/{first}/{second}"}
return None # videos, shorts, playlists, search and anything else
SHORT_HOSTS = {"vm.tiktok.com", "vt.tiktok.com"}
def is_short_link(value):
url = urlsplit(value if re.match(r"^https?://", value, re.I) else "https://" + value)
host = (url.hostname or "").lower()
return host in SHORT_HOSTS or (
re.sub(r"^www\.", "", host) == "tiktok.com" and url.path.startswith("/t/")
)
def resolve_short_link(value, timeout=10):
if not re.match(r"^https?://", value, re.I):
value = "https://" + value
request = urllib.request.Request(value, headers={"User-Agent": "Mozilla/5.0"})
with urllib.request.urlopen(request, timeout=timeout) as response:
return response.geturl() # the final URL after every redirectPython के \w और str.isalnum() Unicode अक्षर और अंक कवर करते हैं, पर देवनागरी जैसी लिपियों में इस्तेमाल होने वाली मात्राएँ (combining marks) नहीं, इसीलिए YouTube वाली जाँच Unicode की M श्रेणियों के अक्षर भी स्वीकार करती है।
Edge cases और टेस्ट
नीचे की हर पंक्ति उस टेस्ट सूट का हिस्सा है जिसे दोनों implementation पास करते हैं।
| इनपुट | आउटपुट | क्यों |
|---|---|---|
instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA== | instagram, natgeo, https://www.instagram.com/natgeo/ | scheme नहीं, मिले-जुले अक्षर, शेयर पैरामीटर |
https://m.instagram.com/nat.geo_/#bio | instagram, nat.geo_ | मोबाइल होस्ट और fragment |
https://www.instagram.com/p/C9xYzAbCdEf/ | null | पोस्ट है, प्रोफ़ाइल नहीं |
https://www.instagram.com/stories/natgeo/1234567890/ | null | story है, भले ही path में हैंडल हो |
tiktok.com/@Khaby.Lame/ | tiktok, khaby.lame, https://www.tiktok.com/@khaby.lame | आख़िरी स्लैश और बड़े-छोटे अक्षर |
https://www.tiktok.com/@khaby.lame/video/7106594312292453675 | null | वीडियो URL |
https://vm.tiktok.com/ZMabc123/ | null (पहले redirect फ़ॉलो करें) | शॉर्ट लिंक जिसमें कोई हैंडल नहीं |
https://m.youtube.com/@GoogleDevelopers/videos?app=desktop | youtube, googledevelopers | मोबाइल होस्ट, चैनल टैब, query |
https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featured | youtube, channelId UC_x5XG1OV2P6uZZ5FSM9Ttw | चैनल ID के अक्षर जैसे थे वैसे रहते हैं |
https://www.youtube.com/c/GoogleDevelopers | youtube, customName GoogleDevelopers | पुराना कस्टम URL; ID के लिए खोज चाहिए |
https://www.youtube.com/@%E3%83%86%E3%82%B9%E3%83%88 | youtube, handle テスト | percent-encoded Unicode हैंडल |
https://youtu.be/dQw4w9WgXcQ | null | वीडियो है, चैनल नहीं |
https://mobile.twitter.com/jack?s=21&t=abc | x, jack, https://x.com/jack | पुराना डोमेन और शेयर पैरामीटर |
https://x.com/i/flow/login | null | ऐप route |
https://x.com/this_handle_is_too_long | null | 15 से ज़्यादा अक्षर |
https://instagram.com.evil.com/natgeo | null | मिलता-जुलता दिखने वाला होस्ट |
https://instagram.com@evil.com/natgeo | null | user info की चाल; असली होस्ट evil.com है |
@natgeo | null | सादे हैंडल का कोई प्लेटफ़ॉर्म नहीं |
केस अपनी repository में रखें और CI में चलाएँ। जब कोई प्लेटफ़ॉर्म नया route या शेयर पैरामीटर जोड़ता है, तो आप एक पंक्ति जोड़ते हैं और सुधार साफ़ दिख जाता है।
import assert from "node:assert/strict";
import { parseProfileUrl } from "./parse.mjs";
const cases = [
["instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA==", { platform: "instagram", handle: "natgeo", canonicalUrl: "https://www.instagram.com/natgeo/" }],
["https://www.instagram.com/reel/C9xYzAbCdEf/", null],
["https://www.instagram.com/explore/", null],
["tiktok.com/@Khaby.Lame/", { platform: "tiktok", handle: "khaby.lame", canonicalUrl: "https://www.tiktok.com/@khaby.lame" }],
["https://www.tiktok.com/@khaby.lame/video/7106594312292453675", null],
["https://vm.tiktok.com/ZMabc123/", null],
["https://m.youtube.com/@GoogleDevelopers/videos", { platform: "youtube", handle: "googledevelopers", canonicalUrl: "https://www.youtube.com/@googledevelopers" }],
["https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featured", { platform: "youtube", channelId: "UC_x5XG1OV2P6uZZ5FSM9Ttw", canonicalUrl: "https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw" }],
["https://www.youtube.com/user/GoogleDevelopers", { platform: "youtube", username: "GoogleDevelopers", canonicalUrl: "https://www.youtube.com/user/GoogleDevelopers" }],
["https://youtu.be/dQw4w9WgXcQ", null],
["https://twitter.com/Jack/", { platform: "x", handle: "jack", canonicalUrl: "https://x.com/jack" }],
["https://mobile.twitter.com/jack?s=21", { platform: "x", handle: "jack", canonicalUrl: "https://x.com/jack" }],
["https://x.com/jack/status/20", null],
["https://x.com/i/flow/login", null],
["https://instagram.com.evil.com/natgeo", null],
];
for (const [input, expected] of cases) {
assert.deepEqual(parseProfileUrl(input), expected, input);
}
console.log(`${cases.length} cases passed`);from parse_profile import parse_profile_url
CASES = [
("instagram.com/NatGeo?igsh=MWQ1ZGUxMzBkMA==", {"platform": "instagram", "handle": "natgeo", "canonicalUrl": "https://www.instagram.com/natgeo/"}),
("https://www.instagram.com/reel/C9xYzAbCdEf/", None),
("tiktok.com/@Khaby.Lame/", {"platform": "tiktok", "handle": "khaby.lame", "canonicalUrl": "https://www.tiktok.com/@khaby.lame"}),
("https://vm.tiktok.com/ZMabc123/", None),
("https://m.youtube.com/@GoogleDevelopers/videos", {"platform": "youtube", "handle": "googledevelopers", "canonicalUrl": "https://www.youtube.com/@googledevelopers"}),
("https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw/featured", {"platform": "youtube", "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw", "canonicalUrl": "https://www.youtube.com/channel/UC_x5XG1OV2P6uZZ5FSM9Ttw"}),
("https://youtu.be/dQw4w9WgXcQ", None),
("https://twitter.com/Jack/", {"platform": "x", "handle": "jack", "canonicalUrl": "https://x.com/jack"}),
("https://x.com/i/flow/login", None),
("https://instagram.com.evil.com/natgeo", None),
]
for value, expected in CASES:
assert parse_profile_url(value) == expected, value
print(f"{len(CASES)} cases passed")कच्चा इनपुट और कैनोनिकल रूप दोनों सेव करें
नॉर्मलाइज़ेशन जान-बूझकर कुछ जानकारी छोड़ता है, और आपके नियम समय के साथ बेहतर होंगे। दोनों मान सेव करें:
- `raw_url`: बिल्कुल वही जो यूज़र या इंपोर्ट ने दिया। इससे आप बाद में बेहतर पार्सर दोबारा चला सकते हैं, और यूज़र अपनी प्रोफ़ाइल एडिट करे तो यही उसे दिखाते हैं।
- `platform` और `handle` या `channel_id`: हिस्से,
(platform, handle)पर यूनिक इंडेक्स के साथ। यही आपकी डुप्लिकेट हटाने और join की key है। - `canonical_url`: दोबारा बना URL, दिखाने और प्लेटफ़ॉर्म को कॉल करने के लिए।
- `parsed_at` और पार्सर वर्शन: ताकि आप वे पंक्तियाँ खोज सकें जो आपके नियमों के पुराने वर्शन से नॉर्मलाइज़ हुई थीं।
हैंडल स्थायी नहीं हैं। क्रिएटर हर प्लेटफ़ॉर्म पर अकाउंट का नाम बदलते हैं, और पिछले साल सेव किया हैंडल अब किसी और का हो सकता है। जहाँ आधिकारिक API आपको स्थिर ID देती है, जैसे YouTube चैनल ID, उसे लंबे समय की key के रूप में सेव करें और हैंडल को डिस्प्ले मान मानें जिसे आप रिफ़्रेश करते हैं। साथ वाली गाइड, हैंडल से YouTube चैनल ID पाना, बताती है कैसे।
एक प्रोफ़ाइल से बाकी तक
प्रोफ़ाइल URL नॉर्मलाइज़ होने के बाद अगला सवाल आमतौर पर यह होता है कि उसी क्रिएटर के और कौन-से अकाउंट हैं। sociallinks.dev एक API है जो एक Instagram, TikTok, YouTube या X प्रोफ़ाइल URL लेकर दूसरे प्लेटफ़ॉर्म पर क्रिएटर के अकाउंट लौटाता है, हर मैच के लिए भरोसे के स्कोर और सबूत के साथ।
अक्सर पूछे जाने वाले सवाल
क्या हैंडल सेव करने से पहले छोटे अक्षरों में करने चाहिए?
लुकअप key के लिए हाँ। YouTube और X कहते हैं कि हैंडल case-sensitive नहीं हैं, और TikTok @TikTok को उसी अकाउंट पर ले जाता है जिस पर @tiktok। Instagram कोई case नियम नहीं बताता, पर username छोटे अक्षरों में दिखते हैं, इसलिए छोटे अक्षर करना सुरक्षित डिफ़ॉल्ट है। अगर दिखाना चाहें तो मूल अक्षर raw URL में रखें। YouTube चैनल ID को छोटे अक्षरों में न करें, वे case-sensitive हैं।
क्या किसी पोस्ट या वीडियो URL से हैंडल निकाल सकते हैं?
TikTok वीडियो (/@handle/video/id) और X पोस्ट (/handle/status/id) के path में हैंडल लेखक का है, इसलिए अगर आपको यही चाहिए तो निकाल सकते हैं। Instagram पोस्ट और reel URL (/p/ और /reel/) में हैंडल नहीं होता। इस गाइड के फ़ंक्शन इन सबके लिए null लौटाते हैं क्योंकि ये प्रोफ़ाइल लिंक नहीं हैं।
vm.tiktok.com लिंक कैसे सँभालें?
शॉर्ट लिंक में सिर्फ़ एक कोड होता है। HTTP अनुरोध करें, redirect फ़ॉलो करें, और आख़िरी URL पार्स करें। इसे timeout और कैश के साथ अलग कदम में करें, क्योंकि यह नेटवर्क कॉल है और कोड की मियाद ख़त्म हो सकती है।
क्या twitter.com अब भी मान्य प्रोफ़ाइल URL है?
हाँ। twitter.com प्रोफ़ाइल URL x.com पर रीडायरेक्ट करते हैं, इसलिए दोनों डोमेन को X प्लेटफ़ॉर्म मानें और x.com वाले रूप को कैनोनिकल के रूप में सेव करें।
एक बड़ा regular expression क्यों न इस्तेमाल करें?
पूरी स्ट्रिंग पर एक regex पढ़ने में मुश्किल है और मिलते-जुलते होस्ट, user info या एन्कोड किए अक्षरों से आसानी से धोखा खा जाता है। पहले standard library से URL पार्स करें, फिर सिर्फ़ हैंडल पर छोटे regex इस्तेमाल करें।
YouTube /c/ या /user/ URL को चैनल ID में कैसे बदलें?
/user/<name> URL YouTube Data API के forUsername फ़िल्टर से मेल खाते हैं। /c/ कस्टम नामों के लिए कोई API फ़िल्टर नहीं है। दोनों मामलों के लिए हैंडल से YouTube चैनल ID पाने वाली गाइड देखें।