از گوگل،‌ برای گوگل!

من محمد‌علی‌ قهاری هستم. مدرک کارشناسی مهندسی کامپیوترم رو از دانشگاه علم‌وفرهنگ گرفتم و خیلی شانسی با موضوع پر رمز و راز SEO آشنا شدم. حالا از اون اتفاق شانسی نزدیک به چهار سال گذشته و من از شهریور ۹۹ کارشناس SEO شرکت دیوارم. و تو این مقاله قراره یکی از کارهایی که اخیرا باهاش دست و پنجه نرم کردم رو توضیح بدم.خوشه‌بندی کلمات کلیدی به کمک گوگلحدود یک ماه پیش بود که حجت مسگری در مقاله پیش‌بینی سئو راجع به موضوع جذاب forecasting in SEO صحبت کرد که حتما پیشنهاد می‌کنم بخونیدش. اما در انتهای اون مقاله حجت دو تا پیشنهاد داشت. یکی از اون‌ها این بود:«ما همچنان در کلاسترینگ و دسته‌بندی عبارات در زبان فارسی به روش، ابزار و یا الگوریتم ایده‌آلی نرسیدیم. ابزارهای فعلی هم محدودیت در تعداد عبارات کلیدی دارن و هم با توجه به اینکه برای زبان انگلیسی طراحی شدن کاربری ایده‌آلی در زبان فارسی ندارن. اگر از این حوزه سر درمیارید می‌تونید به پیشرفت علم سئو در زبان فارسی کمک کنید.»پس آستین‌ها رو بالا زدم تا این مشکل دسته‌بندی کلمات کلیدی در زبان فارسی رو حل کنم.حالا که رو لینک این مقاله کلیک کردی و داری مطالعه‌اش می‌کنی، احتمالا تو هم مثل من از این فرایند طاقت فرسای تحقیق کلمات کلیدی یا همون کیورد ریسرچ خودمون خسته شدی. همه می‌دونیم که کیورد ریسرچ بخش‌های مختلفی داره از شناخت حوزه کسب و کار، ایده‌پردازی برای کلمه کلیدی هسته (seed keywords) شروع میشه و تا طراحی ساختار سایت و چیدن جزئیات صفحات‌مون ادامه پیدا می‌کنه. حالا تو این فرایند از نظر من سخت ترین بخشش، دسته‌بندی این کلمات یا همون کلاسترینگه. مخصوصا اگر تعداد زیادی کلمه باشه که مجبوریم دونه‌ به‌ دونه اون‌ها رو نگاه کنیم و با یه خطای حداقلی، اون‌ها رو تو دسته‌بندی مناسب خودش قرار بدیم اونم در حالی که قراره حسابی از ما وقت بگیره. خب اینجاست که ماشین، ربات یا هر چیزی که اسمش رو میذاریم به کمک ما میاد.پس ما قراره کاری کنیم که این کلاسترینگ خسته‌کننده و بعضا پر اشتباهی که انجام می‌دادیم رو به عهده کامپیوتر بذاریم و از زمانی که صرفه‌جویی میشه تو کار‌های دیگه‌ای مثل انجام دادن یه تسک دیگه، خوندن مقاله یا یکی دو دست فیفا بازی کردن استفاده کنیم :)اگر دوست داشتید بدونید چه جوری میشه بیشتر تو زمان‌تون صرفه‌جویی کنید بهتره وبینار میلاد شولی که در مورد Automation در سئو هست رو نگاه کنید.حالا چرا کلاسترینگ؟دیگه گذشت اون زمون که مجبور بودیم به ازای هر کلمه کلیدی، یک صفحه مجزا براش ایجاد کنیم و کل محتوای اون صفحه رو بر اساس کلمه‌ای که داشتیم بهینه‌سازی کنیم. امروزه (تقریبا چند سالی میشه D: ) دیگه گوگل خیلی خیلی باهوش شده و می‌فهمه هم کاربری که داره سرچ می‌کنه دقیقا دنبال چیه هم محتوایی که ما ایجاد کردیم داره راجع به چه موضوعی (Topic) حرف می‌زنه. پس لازم نیست که ما تو دیوار بیایم و یه صفحه به ازای خرید خانه در تهران و یه صفحه جداگونه برای خانه در تهران درست کنیم. چون گوگل تشخیص داده که قصد کاربر از سرچ (Search intent) خانه در تهران، همون خرید خانه در تهرانه و این دو رو یه تاپیک می‌دونه. بنابراین تفکیک موضوعی و ایجاد یه ارتباط معنایی مناسب بین موضوع‌ها میتونه درک گوگل رو از حرف‌هایی که ما داریم تو سایت‌مون می‌زنیم بالاتر ببره. پس حالا می‌بینیم که کلاسترینگ و گذاشتن هر کلمه کلیدی در موضوع مرتبطش چقدر می‌تونه کار ما رو آسون‌تر و گوگل رو خوشحال‌تر کنه.روش‌های کلاسترینگ کدام‌اند؟ هر مورد را مختصرا توضیح دهید.۱ـ دستی (Manual)در این شیوه شما به عنوان کارشناس سئو، دیجیتال مارکتر یا کارشناس محتوا موظفی دونه به دونه کلمات رو در کلاستر‌هایی قرار بدی که حتی از قبل مشخص نیست. چون اگر مشخص بود که دیگه خیلی دشواری نداشتیم :)۲ـ ماشینیتو این روش ما به کمک کامپیوتر و پردازش زبان طبیعی (NLP)، این کیورد‌ها رو کلاستر می‌کنیم. که خود این روش ماشینی به دو دسته معنایی و غیر‌معنایی تقسیم میشه.۱ـ۲ غیر‌معنایی (Non-Semantic)به اون دست از روش‌هایی که به کلمات به چشم یک سری حروف پشت سرهم اومده نگاه می‌کنن، و هیچ چیز دیگه‌ای براشون مهم نیست، غیر معنایی می‌گن. تو این روش چیزی مثل "ربصضخ" یه کلمه کلیدی به حساب میاد. حالا تو این دسته‌بندی طرق زیادی هست که میشه پیاده سازی کرد که من اینجا صرفا دو موردش رو میگم.TF-IDFN-gram frequencyکه توضیح این دو در این مقال نگنجد. اما اگر علاقه دارید که راجع بهشون بیشتر بدونید، پیشنهاد می‌کنم مقاله‌های لینک شده رو بخونید.البته ابزار هایی هستند که در حال حاضر این نوع دسته‌بندی رو برای شما انجام می‌دن که حجت مسگری تو همون مقاله پیش‌بینی سئو به اون اشاره کرده.۲ـ۲ معنایی (Semantic)دقیقا عکس غیر‌معنایی، یعنی جایی که ماشین متوجه معنی کلمات میشه و این کار رو با کمک گرفتن از مدل های از پیش آموزش دیده (Pre-trained) انجام میده. مثل BERT و T5 ( که خود MUM گوگل قراره کلی ازش استفاده کنه).البته ذکر این نکته خالی از لطف نیست که هر مدل NLP توانایی انجام چندین تسک رو داره برای مثال همین مدل T5 کار های زیر رو می‌تونه انجام بده:خلاصه سازی متنجواب دادن به سوالاتترجمهتحلیل حسی ( یعنی سمت و سوی جمله مثبته یا منفی؟ ناراحت‌کننده است یا خوشحال‌کننده؟)کامل کردن جمله ها…اگر دوست دارید راجع به مدل‌های NLP و تسک‌هایی که قادرن انجام بدن بیشتر آشنا بشید، پیشنهاد می‌کنم به سایت https://huggingface.co یه سر بزنید.خب تا اینجای کار با حالات مختلف کلاسترینگ آشنا شدیم. اما چرا از این‌ها استفاده نمی‌کنیم؟ من تمامی این روش‌هایی که بالاتر بهش اشاره کردم رو امتحان کردم اما نتیجه رضایت بخش نبود. چون مثلا در مورد غیر‌معنایی‌ها یکی از بزرگترین باگ‌ها، کلاستر نکردن کلمات هم معنی بود که قصد کاربر از جستجوی اون‌ها یکسان بود اما املای متفاوتی داشتن. مثال : خرید ماشین - خرید خودرو.در بخش معنایی هم بعد از تست و بررسی مدل‌های مختلف، به دو مدل ParsBERT و LaBSE رسیدم که نسبتا نتایج خوبی می دادن اما دقت یا کاربرد‌‌شون جواب کار ما رو نمی داد.1- LaBSE(Language-Agnostic BERT Sentence Embedding)این مدل دقیقا برای تسک Sentence Similarity و چند زبانی (multilingual) طراحی شده بود که خب تو نگاه اول می‌تونست خیلی به ما کمک کنه.همون طور که تو عکس مشخصه، خرید آپارتمان در تهران با اجاره آپارتمان در تهران، بیشترین شباهت رو داره.اما حالا سوال اینجاست که آیا این مدل در انجام وظیفه‌اش خوب عمل نمی‌کنه؟از نظر من که خوبه.سوال بعدی اینه که آیا برای هدفی که داشتم مناسب بود؟ جواب نه هست. چرا؟ چون چیزی که این مدل و مشابه‌های اون در نظر نمی‌گیرن، search intent، رفتار کاربر تو سرچ و … است. چون اگر همین الان خرید آپارتمان در تهران و اجاره آپارتمان در تهران رو سرچ کنید می‌بینید که نتایج متفاوتی بهتون نشون داده میشه.2- ParsBERTParsBERT یکی از مدل‌های pre-trained ایرانیه که اساسش همون BERT گوگله منتها روی corpus فارسی ویکی پدیا، سایت چطور و … Train شده.ParsBERT هم در بعضی از تست‌ها نتیجه خوبی داشت و تو یه سری جا‌ها نه. به صورت کلی این مدل نیاز به fine-tune شدن روی dataset ما داشت و از جایی که داده‌های ما زیاد بود، زمان زیادی طول می کشید که این فرایند انجام بشه.تصویر sentence embedding هر کلمه کلیدی مدل ParsBERT روی کیورد‌های موقعیت‌های شغلیدر نهایت با کلاستر کردن کیورد هامون با الگوریتم هایی مثل k-means، hierarchical و یا HDBSCAN دقت این مدل هم نتونست ما رو راضی کنه.پس بهترین روش در زبان فارسی، استفاده از خود گوگل برای کلاسترینگه.دسته‌بندی کلمات کلیدی بر اساس نتایج SERPشاید کمتر کسی رو بشه پیدا کرد که از نتایجی که گوگل بهش نشون میده ابراز نارضایتی کنه. پس ما هم در دیوار تصمیم گرفتیم به قدرت بالای گوگل در درک موضوعات متون و کیورد‌ها اعتماد کنیم و کلاسترینگ کلمات کلیدی‌مون رو بر این اساس انجام بدیم.منطق استفاده از این نتایج هم به این صورته که اگر تعداد مشخصی URL‌های یکسان برای یک سری کیورد در ۱۰ نتیجه اول گوگل دیده شد، اون دسته از کلمات کلیدی در یک Cluster قرار می‌گیرن. که مشخص کردن این تعداد URL‌های یکسان دست شماست. یعنی هر چقدر عدد پایین تر باشه منطقا اندازه کلاستر‌ها خیلی بزرگ و با دقت کمتری ایجاد می‌شن در مقابل اگر عدد انتخابی شما زیاد باشه دسته‌ها خیلی کوچک و تعداد کلاستر‌ها خیلی زیاد میشه. حالت ایده‌آل برای تعداد URL‌های یکسان عدد ۴ یا ۵ می‌تونه باشه.حالا چه جوری نتایج گوگل رو به دست بیاریم؟۱ـ Crawl کردناولین راهی که به ذهنم رسید این بود که بیام و نتایج صفحه SERP رو کراول کنم اما خب برای تعداد زیاد، روش قابل اطمینانی نیست چون بعد از ریکوئست‌های زیاد، DDoS protection فعال میشه و استتوس کد 429 برمی‌گردونه و به معنای اینه که بیش از اندازه ریکوئست زدی. البته می شد با حرکت‌هایی مثل عوض کردن user-agent یا proxy rotation و … این قضیه رو دور زد اما برای این اندازه از داده خیلی کار منطقی نبود.در هر صورت نشد که بشه.در ضمن برای این کار از کتابخونه google search در پایتون استفاده کردم.۲ـ استفاده از Custom search engine APIوقتی از راه اول به بن بست خوردم، گفتم بهتره تا از API خود گوگل استفاده کنم. اما دیدم گوگل فقط اجازه می‌ده روزانه 100 تا کوئری رایگان ریکوئست بدم و خب با این حجم از دیتایی که ما داریم، این کار نشدنی بود.چون هزینه‌ای که پلن پولی این API روی دست ما می‌ذاشت سرسام آور بود. ( البته که استفاده از این API به صورت رایگان و با محدودیت بیشتر از 100 تا در روز هم راهکار داره که قول میدم بعدا حتما به اشتراک بذارم).۳ـ استفاده از API های Third-partyبعد از امتحان کردن دو مورد بالا و جواب نگرفتن ازشون روی دیتای زیاد، رفتم سراغ API‌های Third-party که نتایج صفحه گوگل رو برام مهیا می‌کردن. ما از API سایت serpstack برای پیشبرد کارمون استفاده کردیم اما شما می‌تونید با سرچ کردن google serp api یه لیست از سایت‌هایی رو ببینید که این کار رو براتون انجام می‌دن و با توجه نیاز‌تون از اون‌ها استفاده کنید.ما برای اجرای کد‌مون به کتابخونه‌های زیر نیاز داریم:Requests برای call کردن APIPandas برای data manipulation یا همون دستکاری کردن دادهNetworkx برای ایجاد گراف و ارتباط بین کلمات کلیدیimport requests import pandas as pd import networkx as nx from networkx.algorithms import communityاینجا فایل csv‌مون رو با استفاده از pandas می‌خونیم و ستون Keyword اون رو داخل لیست کیورد‌هامون به اسم Keyword_list ذخیره می‌کنیم:keyword_data_frame=pd.read_csv(filepath_or_buffer=&quotkwfinder-apartment.csv”) keyword_list = keyword_data_frame['Keyword'].to_list()در قسمت بعدی پارامتر‌های ریکوئست‌مون رو تنظیم می‌کنیم و API رو call می‌کنیم و در نهایت نتایج SEPR رو داخل لیستی از دیکشنری resultList ذخیره می‌کنیم. هر آیتم از resultList یه دیکشنری شامل کلمه کلیدی و لیست نتایج گوگله:resultList = [] for kw in keyword_list: params = { 'access_key': [YOUR_API_KEY], 'query': kw, 'engine': 'google', 'type' : 'web', 'device' : &quotmobile&quot, 'google_domain' : 'google.com', 'gl' : 'ir', 'hl' :'fa', 'page': '1', 'num':'10', 'output' : 'json' } api_result = requests.get('https://api.serpstack.com/search', params) api_response = api_result.json() if (api_response[&quotsuccess&quot]): organic_result = api_response['organic_results'] google_links = [] for result in organic_result: google_links.append(result[&quoturl&quot]) resultList.append({&quotKeyword&quot:kw,&quotLinks&quot: google_links}) else: message = api_response['error']['info'] print(message) breakخب حالا که نتایج SERP برای هر کیورد رو داریم می‌ریم سراغ کلاسترینگ. برای این کار من اول اومدم یه دیتا فریم از کلمات کلیدی و لیست URL هاشون درست کردم بعد این دیتافریم رو ستون URL با خودش join زدم تا ترکیب Keyowrd 1,Keyword 2 ,URL ساخته بشه. در نهایت با group کردن کیورد اول و دوم، تعداد URL‌های مشترک بین اون‌ها رو در آوردم و لیست اون کلماتی که بیشتر از n تا URL مشترک دارن رو داخل grouped_df ذخیره کردم:sameUrl = 5 url_list = [] for i in resultList: for url in i['Links']: url_list.append({&quotKeyword&quot:i['Keyword'],&quotURL&quot:url}) url_df = pd.DataFrame(data=url_list) join_df = pd.merge(url_df,url_df,on=&quotURL&quot,how=&quotinner&quot) grouped_df = join_df.groupby(['Keyword_x', 'Keyword_y']).nunique() grouped_df = grouped_df[grouped_df.URL>sameUrl] group_dict = grouped_df.to_dict()مرحله بعدی، ساخت یه گراف برای ایجاد ارتباط بین node (کلمات کلیدی)‌هایی که با هم به تعداد sameURL آدرس یکسان دارن:G = nx.Graph() nodes = tuple(keyword_list) G.add_nodes_from(nodes) edge_list = [] for i in group_dict['URL']: edge_list.append(i) G.add_edges_from(edge_list)بعد از ساخت گراف، کافیه تا community‌ها رو داخل گراف تشخیص بدیم تا کلاستر‌های ما مشخص بشه که اون‌ها رو در یک لیست ذخیره کنیم:com = community.greedy_modularity_communities(G) clusters_dict_list = [] for i in com: temp_cluster = list(i) temp_cluster = sorted(temp_cluster,reverse=True) for j in temp_cluster: clusters_dict_list.append({'Keyword':j,'Cluster':temp_cluster[0]})حالا کافیه که ستون Cluster رو به انتهای فایل ابتدایی اضافه کنیم و دیتافریم نهایی‌مون رو داخل final.csv ذخیره کنیم:cluster_data_frame = pd.DataFrame(clusters_dict_list) final_df=pd.merge(keyword_data_frame,cluster_data_frame,on='Keyword' ,how=inner) final_df.to_csv('final.csv',index=False)همه‌ی کد‌های بالا رو می‌تونید به صورت یکجا در colab google ببینید.سخن پایانیتو فضای رقابتی امروز که همه چیز به سرعت داره اتفاق میفته شاید بد نباشه که ما هم خودمون رو مجهز‌تر کنیم و از راه‌های بهینه‌تری برای رسیدن به اهداف‌مون استفاده کنیم. تو حوزه SEO هم تا دل‌تون بخواد کلی فرایند هست برای بهبود دادن که از ما وقت و انرژی کمتری بگیره و در عین حال، موثر باشه. در آخر اگر شما مسیر بهتری رو برای کلاسترینگ در سئو می‌دونید ممنون میشم تو قسمت کامنت همین جا توضیحش بدید و با ما به اشتراک بذاریدش.