فاز 5 · درس 7

برچسب‌گذاری نقش دستوری (POS Tagging) و تجزیه نحوی

نوع
ساختنی
زمان
حدود 45 دقیقه
زبان‌ها
Python
پیش‌نیاز
فاز 5 · درس 01 (پردازش متن)، فاز 2 · درس 14 (بیز ساده)
درخت چوبی با برچسب‌های رنگی متصل به شاخه‌ها روی میز کار چوبی
فهرست مطالب
  1. صورت مسئله
  2. مفهوم
  3. پیاده‌سازی از صفر
  4. گام 1: خط مبنا بر اساس پرتکرارترین برچسب
  5. گام 2: برچسب‌زن HMM دوتایی (bigram)
  6. گام 3: چرا برچسب‌زن‌های امروزی از این مدل‌ها بهترند؟
  7. گام 4: طرح کلی تجزیه‌ی وابستگی
  8. استفاده از ابزارهای واقعی
  9. چرا این مفاهیم در سال 2026 هنوز مهم هستند؟
  10. خروجی این درس
  11. تمرین‌ها
  12. اصطلاحات کلیدی
  13. برای مطالعه‌ی بیشتر

در نگاه اول، با ظهور مدل‌های زبانی بزرگ شاید تحلیل‌های گرامری کلاسیک قدیمی به نظر برسند؛ اما در عمل پایپ‌لاین‌های مدرن استخراج داده، اعتبارسنجی خروجی‌های ساختاریافته‌ی مدل‌ها و سیستم‌های پرسش‌وپاسخ متنی همچنان به درک دقیق نقش‌های دستوری و پیوندهای کلمات وابسته‌اند. بدون برچسب‌گذاری نقش دستوری (POS Tagging)، حتی الگوریتم‌های ریشه‌یابی کلمات (Lemmatization) نیز نمی‌توانند تفاوت میان اسم و فعل را تشخیص دهند.

در این درس ساختار گرامری متن را از دو زاویه بررسی می‌کنیم: برچسب‌گذاری نقش دستوری و تجزیه‌ی نحوی (Syntactic Parsing). کار را با پیاده‌سازی خطوط مبنای آماری مثل مدل مارکوف پنهان (HMM) و الگوریتم ویتربی شروع می‌کنیم و در نهایت به ابزارهای استاندارد صنعتی مانند spaCy می‌رسیم تا بتوانید روابط کلمات را به‌صورت ساختار درختی در پروژه‌های واقعی تحلیل کنید.

دستور زبان مدتی از مد افتاده بود. تا این‌که همه‌ی پایپ‌لاین‌های LLM برای اعتبارسنجی استخراج ساختاریافته به آن نیاز پیدا کردند و دوباره به صحنه برگشت.

صورت مسئله

در درس 01 قول دادیم که ریشه‌یابی به روش لماتیزاسیون (lemmatization) به برچسب نقش دستوری کلمات نیاز دارد. ریشه‌یاب بدون دانستن این‌که running فعل است، نمی‌تواند آن را به run تقلیل دهد. همچنین اگر نداند better صفت است، نمی‌تواند آن را به good برساند.

پشت آن وعده، یک حوزه‌ی علمی کامل پنهان شده بود. برچسب‌گذاری نقش دستوری (part-of-speech tagging یا POS tagging) دسته‌بندی‌های گرامری را به کلمات نسبت می‌دهد. تجزیه‌ی نحوی (syntactic parsing) ساختار درختی جمله را بازسازی می‌کند: این‌که کدام کلمه توصیف‌کننده‌ی کدام است، و کدام فعل چه متمم‌ها و شناسه‌هایی را هدایت می‌کند. پردازش زبان طبیعی کلاسیک بیست سال را صرف صیقل دادن این دو مفهوم کرد. سپس یادگیری عمیق (deep learning) هر دوی آن‌ها را به یک مسئله‌ی دسته‌بندی توکن (token) روی یک ترنسفورمر (transformer) پیش‌آموزش‌دیده تبدیل کرد و جامعه‌ی پژوهشی سراغ موضوعات بعدی رفت.

اما جامعه‌ی مهندسی کاربردی کنار نکشید. زیر کاپوتِ تک‌تک پایپ‌لاین‌های استخراج ساختاریافته، هنوز از برچسب‌های دستوری و درخت‌های وابستگی استفاده می‌شود. خروجی‌های JSON تولیدشده توسط LLM در برابر قیود گرامری اعتبارسنجی می‌شوند. سیستم‌های پرسش و پاسخ، پرسمان‌ها را با تجزیه‌ی وابستگی تفکیک می‌کنند. ابزارهای ارزیابی کیفیت ترجمه‌ی ماشینی نیز هم‌ترازی درخت‌های تجزیه را می‌سنجند.

دانستن این مفاهیم ارزشمند است. در این درس با مجموعه‌برچسب‌ها، خطوط مبنا و نقطه‌ای که دیگر نباید از صفر کد بزنید و باید سراغ spaCy بروید، آشنا می‌شوید.

مفهوم

برچسب‌گذاری نقش دستوری (POS tagging) به هر توکن یک دسته‌بندی گرامری اختصاص می‌دهد. مجموعه‌برچسب Penn Treebank (PTB) گزینه‌ی پیش‌فرض در زبان انگلیسی است؛ شامل 36 برچسب با تمایزهایی که شاید برای خواننده‌ی عادی بیش‌ازحد جزئی به نظر برسد: NN برای اسم مفرد، NNS برای اسم جمع، NNP برای اسم خاص مفرد، VBD برای فعل زمان گذشته، VBZ برای فعل سوم‌شخص مفرد حال، و مواردی از این دست. در مقابل، مجموعه‌برچسب Universal Dependencies (UD) کلی‌تر است (17 برچسب) و به زبان خاصی وابسته نیست؛ به همین دلیل به گزینه‌ی پیش‌فرض در کارهای چندزبانه تبدیل شده است.

The/DET cats/NOUN were/AUX running/VERB at/ADP 3pm/NOUN ./PUNCT

تجزیه‌ی نحوی یک ساختار درختی تولید می‌کند. برای این کار دو شیوه‌ی اصلی وجود دارد:

  • تجزیه‌ی سازه‌ای (Constituency parsing). عبارت‌های اسمی، فعلی و حرف‌اضافه‌ای درون یکدیگر لانه می‌گزینند. خروجی این روش، درختی از دسته‌بندی‌های غیرپایانه‌ای (NP، VP، PP) است که کلمات، برگ‌های آن هستند.
  • تجزیه‌ی وابستگی (Dependency parsing). هر کلمه دقیقاً یک کلمه‌ی هسته (head) دارد که به آن وابسته است و نوع این رابطه با یک برچسب گرامری مشخص می‌شود. خروجی این روش، درختی است که هر یال آن یک سه‌تایی به‌صورت (هسته، وابسته، رابطه) است.

در دهه‌ی 2010 تجزیه‌ی وابستگی پیروز میدان شد، چرا که به‌خوبی روی زبان‌های گوناگون—به‌ویژه زبان‌هایی با ترتیب آزاد کلمات—تعمیم می‌یابد.

running is ROOT
cats is nsubj of running
were is aux of running
at is prep of running
3pm is pobj of at
برچسب‌زن POSتخصیص برچسب‌ها به توکن‌ها
POS TAGGEREach token gets one grammatical category. A tagger sweeps the sentence left to right, dropping a label onto every word: determiner, noun, auxiliary, verb, adverb. Those tags are what a lemmatizer and a dependency parser read next.TheDETcatsNOUNwereAUXrunningVERBfastADV
هر توکن یک نقش دستوری می‌گیرد. برچسب‌زن جمله را از چپ به راست پیمایش کرده و به هر کلمه یک برچسب اختصاص می‌دهد: حرف تعریف، اسم، فعل کمکی، فعل، قید. این برچسب‌ها ورودی بعدی ریشه‌یاب و تحلیل‌گر وابستگی هستند.
تحلیل وابستگیرسم کمان‌های وابستگی
DEPENDENCY PARSEDependency parsing draws one labeled arc from each word to its head. The verb "running" is the root; "cats" is its subject, "were" its auxiliary, and the prepositional phrase hangs off it. Every edge is a (head, dependent, relation) triple.catswererunningatdawnnsubjauxpreppobj
تحلیل وابستگی یک کمان برچسب‌دار از هر کلمه به هسته (head) آن رسم می‌کند. فعل «running» ریشه است؛ «cats» فاعل آن، «were» فعل کمکی و عبارت حرف اضافه‌ای وابسته به آن است. هر یال یک سه‌تایی (هسته، وابسته، رابطه) است.

پیاده‌سازی از صفر

گام 1: خط مبنا بر اساس پرتکرارترین برچسب

ساده‌ترین برچسب‌زن کارآمد: برای هر کلمه، همان برچسبی را پیش‌بینی کنید که در داده‌های آموزشی بیشترین تکرار را داشته است.

from collections import Counter, defaultdict


def train_mft(train_examples):
    word_tag_counts = defaultdict(Counter)
    all_tags = Counter()
    for tokens, tags in train_examples:
        for token, tag in zip(tokens, tags):
            word_tag_counts[token.lower()][tag] += 1
            all_tags[tag] += 1
    word_best = {w: c.most_common(1)[0][0] for w, c in word_tag_counts.items()}
    default_tag = all_tags.most_common(1)[0][0]
    return word_best, default_tag


def predict_mft(tokens, word_best, default_tag):
    return [word_best.get(t.lower(), default_tag) for t in tokens]

این خط مبنا روی پیکره‌ی Brown به دقت حدود 85% می‌رسد. عالی نیست، اما کف دقتی است که هیچ مدل جدی‌ای نباید پایین‌تر از آن بیاید.

گام 2: برچسب‌زن HMM دوتایی (bigram)

احتمال توأم توالی را مدل‌سازی کنید:

P(tags,words)=∏iP(tagi∣tagi−1)⋅P(wordi∣tagi)P(\text{tags}, \text{words}) = \prod_i P(\text{tag}_i \mid \text{tag}_{i-1}) \cdot P(\text{word}_i \mid \text{tag}_i)

دو جدول داریم: احتمال‌های انتقال (احتمال یک برچسب به شرط برچسب قبلی) و احتمال‌های انتشار (احتمال یک کلمه به شرط برچسب آن). هر دو جدول را از روی شمارش‌ها و با هموارسازی لاپلاس (Laplace smoothing) تخمین می‌زنیم. سپس رمزگشایی را با الگوریتم ویتربی (Viterbi؛ برنامه‌نویسی پویا روی شبکه‌ی حالت‌های برچسب) انجام می‌دهیم.

import math


def train_hmm(train_examples, alpha=0.01):
    transitions = defaultdict(Counter)
    emissions = defaultdict(Counter)
    tags = set()
    vocab = set()

    for tokens, ts in train_examples:
        prev = "<BOS>"
        for token, tag in zip(tokens, ts):
            transitions[prev][tag] += 1
            emissions[tag][token.lower()] += 1
            tags.add(tag)
            vocab.add(token.lower())
            prev = tag
        transitions[prev]["<EOS>"] += 1

    return transitions, emissions, tags, vocab


def log_prob(table, given, key, smooth_denom, alpha):
    return math.log((table[given].get(key, 0) + alpha) / smooth_denom)


def viterbi(tokens, transitions, emissions, tags, vocab, alpha=0.01):
    tags_list = list(tags)
    n = len(tokens)
    V = [[0.0] * len(tags_list) for _ in range(n)]
    back = [[0] * len(tags_list) for _ in range(n)]

    for j, tag in enumerate(tags_list):
        em_denom = sum(emissions[tag].values()) + alpha * (len(vocab) + 1)
        tr_denom = sum(transitions["<BOS>"].values()) + alpha * (len(tags_list) + 1)
        tr = log_prob(transitions, "<BOS>", tag, tr_denom, alpha)
        em = log_prob(emissions, tag, tokens[0].lower(), em_denom, alpha)
        V[0][j] = tr + em
        back[0][j] = 0

    for i in range(1, n):
        for j, tag in enumerate(tags_list):
            em_denom = sum(emissions[tag].values()) + alpha * (len(vocab) + 1)
            em = log_prob(emissions, tag, tokens[i].lower(), em_denom, alpha)
            best_prev = 0
            best_score = -1e30
            for k, prev_tag in enumerate(tags_list):
                tr_denom = sum(transitions[prev_tag].values()) + alpha * (len(tags_list) + 1)
                tr = log_prob(transitions, prev_tag, tag, tr_denom, alpha)
                score = V[i - 1][k] + tr + em
                if score > best_score:
                    best_score = score
                    best_prev = k
            V[i][j] = best_score
            back[i][j] = best_prev

    last_best = max(range(len(tags_list)), key=lambda j: V[n - 1][j])
    path = [last_best]
    for i in range(n - 1, 0, -1):
        path.append(back[i][path[-1]])
    return [tags_list[j] for j in reversed(path)]

مدل HMM دوتایی روی پیکره‌ی Brown به دقت حدود 93% می‌رسد. جهش از 85% به 93% عمدتاً ناشی از احتمال‌های انتقال است؛ مدل یاد می‌گیرد که توالی DET NOUN بسیار رایج و NOUN DET نادر است.

گام 3: چرا برچسب‌زن‌های امروزی از این مدل‌ها بهترند؟

احتمال‌های انتقال و انتشار ماهیتی محلی دارند. آن‌ها نمی‌توانند درک کنند که کلمه‌ی saw در جمله‌ی «I bought a saw» اسم است، اما در «I saw the movie» نقش فعل دارد. مدل میدان تصادفی شرطی (CRF) با ویژگی‌های دلخواه (پسوند، شکل ظاهری کلمه، کلمات قبل و بعد، و خود کلمه) به دقت حدود 97% می‌رسد. یک مدل BiLSTM-CRF یا ترنسفورمر هم دقت را به بالای 98% می‌رساند.

سقف دقت در این وظیفه را میزان عدم‌توافق میان ارزیاب‌های انسانی تعیین می‌کند. تحلیل‌گران انسانی روی مجموعه‌داده‌ی Penn Treebank در حدود 97% مواقع با یکدیگر توافق دارند. مدل‌هایی که از 98% عبور می‌کنند، به احتمال زیاد دچار بیش‌برازش (overfitting) روی مجموعه‌ی آزمون شده‌اند.

گام 4: طرح کلی تجزیه‌ی وابستگی

پیاده‌سازی کامل تجزیه‌ی وابستگی از صفر خارج از دامنه (scope) این درس است؛ مرجع استاندارد آن در کتاب Jurafsky and Martin آمده است. دو خانواده‌ی کلاسیک و اصلی که باید بشناسید:

  • تجزیه‌کننده‌های مبتنی بر انتقال (Transition-based) (مانند arc-eager و arc-standard) شبیه یک تجزیه‌کننده‌ی انتقال-کاهش (shift-reduce) عمل می‌کنند: توکن‌ها را می‌خوانند، آن‌ها را داخل یک پشته (stack) می‌گذارند (عمل shift)، و با اجرای عملیات کاهش (reduce)، یال‌های وابستگی را می‌سازند. رمزگشایی حریصانه در این روش بسیار سریع است. پیاده‌سازی کلاسیک آن ابزار MaltParser است و نسخه‌ی مدرن مبتنی بر شبکه عصبی آن را چن و منینگ (Chen and Manning) ارائه دادند.
  • تجزیه‌کننده‌های مبتنی بر گراف (Graph-based) (مانند الگوریتم آیزنر و روش دوجفت‌خطی Dozat-Manning) به هر یالِ ممکن میان هسته و وابسته امتیاز می‌دهند و درخت پوشای بیشینه را انتخاب می‌کنند. این شیوه کندتر اما دقیق‌تر است.

در بیشتر کارهای کاربردی، کافی است spaCy را فراخوانی کنید:

import spacy

nlp = spacy.load("en_core_web_sm")
doc = nlp("The cats were running at 3pm.")
for token in doc:
    print(f"{token.text:10s} tag={token.tag_:5s} pos={token.pos_:6s} dep={token.dep_:10s} head={token.head.text}")
The        tag=DT    pos=DET    dep=det        head=cats
cats       tag=NNS   pos=NOUN   dep=nsubj      head=running
were       tag=VBD   pos=AUX    dep=aux        head=running
running    tag=VBG   pos=VERB   dep=ROOT       head=running
at         tag=IN    pos=ADP    dep=prep       head=running
3pm        tag=NN    pos=NOUN   dep=pobj       head=at
.          tag=.     pos=PUNCT  dep=punct      head=running

اگر ستون dep را از پایین به بالا بخوانید، ساختار دستوری جمله به‌روشنی نمایان می‌شود.

استفاده از ابزارهای واقعی

همه‌ی کتابخانه‌های تجاری NLP، ابزارهای برچسب‌گذاری POS و تجزیه‌ی وابستگی را به‌صورت بخشی از پایپ‌لاین استاندارد خود ارائه می‌دهند.

  • spaCy (مدل‌های en_core_web_sm / md / lg / trf). سریع، دقیق و یکپارچه‌شده با توکن‌سازی، بازشناسی هویت‌های نام‌دار (NER) و ریشه‌یابی. ویژگی‌ها: token.tag_ (برچسب‌های Penn)، token.pos_ (برچسب‌های UD) و token.dep_ (رابطه‌ی وابستگی).
  • Stanford NLP (stanza). جانشین استنفورد برای CoreNLP؛ پیشرو در ارائه‌ی بهترین نتایج روی بیش از 60 زبان.
  • trankit. مبتنی بر ترنسفورمر، با دقت بسیار خوب در برچسب‌های UD.
  • NLTK. تابع pos_tag. کار را راه می‌اندازد، اما کندتر و قدیمی‌تر است. برای مقاصد آموزشی گزینه‌ی خوبی به شمار می‌رود.

چرا این مفاهیم در سال 2026 هنوز مهم هستند؟

  • ریشه‌یابی (Lemmatization). طبق درس 01، برای لماتیزاسیون درست همیشه به برچسب POS نیاز دارید؛ بدون استثنا.
  • استخراج ساختاریافته از خروجی‌های LLM. برای بررسی این‌که آیا جمله‌ی تولیدشده قیود گرامری را رعایت کرده است یا نه (مثل مطابقت فاعل و فعل، یا وجود وابسته‌های ضروری).
  • تحلیل احساسات مبتنی بر جنبه (Aspect-based sentiment). درخت‌های وابستگی مشخص می‌کنند کدام صفت در حال توصیف کدام اسم است.
  • درک پرسمان (Query understanding). عبارتی مثل «movies directed by Wes Anderson starring Bill Murray» از طریق تجزیه‌ی نحوی به قیود ساختاریافته تجزیه می‌شود.
  • انتقال بین‌زبانی (Cross-lingual transfer). برچسب‌ها و روابط وابستگی UD مستقل از زبان هستند و امکان تحلیل ساختاریافته‌ی صفر-داده (zero-shot) را روی زبان‌های جدید فراهم می‌کنند.
  • پایپ‌لاین‌های کم‌مصرف و سبک. اگر نمی‌توانید یک مدل ترنسفورمر را مستقر کنید، ترکیب برچسب‌های POS، تجزیه‌ی وابستگی و فهرست واژگان (gazetteer) کار را به‌طرز چشمگیری پیش می‌برد.

خروجی این درس

محتوای زیر را در فایل outputs/skill-grammar-pipeline.md ذخیره کنید:

---
name: grammar-pipeline
description: Design a classical POS + dependency pipeline for a downstream NLP task.
version: 1.0.0
phase: 5
lesson: 07
tags: [nlp, pos, parsing]
---

Given a downstream task (information extraction, rewrite validation, query decomposition, lemmatization), you output:

1. Tagset to use. Penn Treebank for English-only legacy pipelines, Universal Dependencies for multilingual or cross-lingual.
2. Library. spaCy for most production, stanza for academic-grade multilingual, trankit for highest UD accuracy. Name the specific model ID.
3. Integration pattern. Show the 3-5 lines that call the library and consume the needed attributes (`.pos_`, `.dep_`, `.head`).
4. Failure mode to test. Noun-verb ambiguity (`saw`, `book`, `can`) and PP-attachment ambiguity are the classical traps. Sample 20 outputs and eyeball.

Refuse to recommend rolling your own parser. Building parsers from scratch is a research project, not an application task. Flag any pipeline that consumes POS tags without handling lowercase/uppercase variants as fragile.

تمرین‌ها

  1. ساده. با استفاده از خط مبنای پرتکرارترین برچسب روی یک پیکره‌ی برچسب‌خورده‌ی کوچک (مثل زیرمجموعه‌ی Brown در NLTK)، دقت مدل را روی جملات ارزیابی (held-out) بسنجید. بررسی کنید که آیا به نتیجه‌ی حدود 85% می‌رسید یا خیر.
  2. متوسط. مدل HMM دوتایی بالا را آموزش دهید و دقت (Precision) و بازخوانی (Recall) را به تفکیک برچسب‌ها گزارش کنید. مدل HMM بیشترین خطا را روی کدام برچسب‌ها دارد؟
  3. سخت. با استفاده از تجزیه‌ی وابستگی spaCy، سه‌گانه‌های فاعل-فعل-مفعول (SVO) را از یک نمونه‌ی 1000 جمله‌ای استخراج کنید. صحت خروجی را روی 50 سه‌گانه‌ی برچسب‌خورده‌ی دستی ارزیابی کنید. مواردی را که استخراج در آن‌ها شکست می‌خورد ثبت کنید (معمولاً جملات مجهول، عبارات عطفی و فاعل‌های محذوف).

اصطلاحات کلیدی

اصطلاح در گفت‌وگوهای عامیانه معنای دقیق فنی
POS tag نوع کلمه دسته‌بندی گرامری کلمه. مجموعه‌برچسب PTB دارای 36 برچسب و UD دارای 17 برچسب است.
Penn Treebank مجموعه‌برچسب استاندارد ویژه‌ی زبان انگلیسی. تفکیک بسیار دقیق زمان‌های افعال و مفرد یا جمع بودن اسامی.
Universal Dependencies مجموعه‌برچسب چندزبانه کلی‌تر از PTB؛ مستقل از زبان و گزینه‌ی پیش‌فرض برای کارهای چندزبانه.
Dependency parse درخت جمله هر کلمه یک هسته دارد و هر یال نشان‌دهنده‌ی یک رابطه‌ی گرامری است.
Viterbi برنامه‌نویسی پویا یافتن محتمل‌ترین توالی برچسب‌ها بر اساس مقادیر انتشار و انتقال.

برای مطالعه‌ی بیشتر

خودآزمایی

به سؤال‌ها جواب بدهید تا ببینید چقدر از درس در ذهنتان مانده است.

  1. پیش از درسهدف از برچسب‌گذاری نقش کلمات (POS tagging) چیست؟
  2. پیش از درسکدام مجموعه برچسب حالت پیش‌فرض برای کارهای چندزبانه است؟
  3. حین درسیک برچسب‌زن POS با مدل HMM دوتایی (bigram) چه چیزی را مدل‌سازی می‌کند؟
  4. حین درسالگوریتم Viterbi چه چیزی را برای یک برچسب‌زن HMM محاسبه می‌کند؟
  5. حین درستحلیل وابستگی چه خروجی‌ای تولید می‌کند؟
  6. پس از درسچرا سقف دقت برچسب‌گذاری POS در PTB حدود 97 تا 98 درصد است؟
  7. پس از درسچرا برچسب‌گذاری POS همچنان در پایپ‌لاین‌های LLM سال 2026 اهمیت دارد؟
  8. پس از درسبرای اکثر کارهای پروداکشن POS یا تجزیه نحوی باید به سراغ کدام کتابخانه رفت؟

سؤالات متداول

تفاوت مجموعه‌برچسب Penn Treebank با Universal Dependencies چیست؟

مجموعه‌برچسب Penn Treebank مختص زبان انگلیسی بوده و با 36 برچسب جزییاتی مانند زمان افعال و نوع اسامی را دقیق مشخص می‌کند، اما Universal Dependencies دارای 17 برچسب کلی‌تر است که مستقل از زبان بوده و برای کارهای چندزبانه استاندارد شده است.

چرا تجزیه وابستگی (Dependency Parsing) بر تجزیه سازه‌ای ترجیح داده شد؟

تجزیه‌ی وابستگی به دلیل تعریف روابط مستقیم میان کلمات (هسته و وابسته)، در زبان‌های گوناگون به‌ویژه زبان‌هایی که ترتیب قرارگیری کلمات در آن‌ها آزادتر است تعمیم‌پذیری و کارایی بسیار بهتری نشان می‌دهد.

چرا مدل HMM دقت کمتری نسبت به CRF یا ترنسفورمرها در POS Tagging دارد؟

احتمالات انتقال و انتشار در مدل HMM محلی هستند و نمی‌توانند زمینه و بافت وسیع‌تر جمله یا ویژگی‌های ظاهری کلمه را برای رفع ابهام نقش واژه‌ها به‌خوبی در نظر بگیرند.

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.