6 اسفند 1402
تهران، خیابان آزادی، تقاطع قریب
هوش مصنوعی GPT
برنامه نویسی نرم افزار

آموزش پروژه محور پایتون | رایگان با سورس کد

آموزش پروژه محور پایتون | رایگان و همراه با سورس کد

مطلب امروز ما به آموزش پروژه محور پایتون می‌پردازد که در آن از سورس کد چند پروژه استفاده شده و به صورت قدم به قدم، در طول این آموزش کدنویسی می‌شوند. این مطلب به مرور با پروژه‌های جدیدتر به روز خواهد شد و می‌توانید هر از گاهی برای دریافت پروژه‌های جدید، به آن سر بزنید. برای این کار پیشنهاد می‌کنیم لینک آن را به bookmarkهای مرورگر خود اضافه کنید.

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

حالا بیایید آموزش را آغاز کنیم!

آموزش پروژه محور پایتون: تشخیص چهره (Face Detection)

در این بخش از آموزش پروژه محور پایتون، به شما نشان خواهیم داد که چگونه با استفاده از پایتون یک Face Detector ساده بسازید. ساختن برنامه‌ای که چهره‌ها را شناسایی می‌کند، یک راه عالی برای شروع کار با تسک‌های Computer Vision در یادگیری ماشین است. به همین دلیل، ما در اینجا یک راه بسیار آسان برای تشخیص چهره با پایتون به شما معرفی می‌کنیم.

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

بهترین راه برای یادگیری هر چیزی، آموزش دیدن است. بنابراین، در حالی که به ماشینی برای تشخیص چهره آموزش می‌دهیم، خودمان نیز در حال یادگیری هستیم. اما قبل از شروع این کار، می‌خواهم تفاوت بین تشخیص چهره (Face Detection) و شناسایی چهره (Face Recognition) را با شما به اشتراک بگذارم.

Face Detection Vs Face Recognition

Face Detection و Face Recognition ممکن است بسیار شبیه به هم به نظر برسند، اما در واقعیت این دو یکی نیستند. بیایید تفاوت بین این‌ها را درک کنیم تا هیچ نکته‌ای از زیر دستمان در نرود.

Face Detection ، فرآیند تشخیص دادن چهره‌ها در تصاویر و ویدیوها است. این برنامه کاری جز یافتن چهره‌ها انجام نمی‌دهد. اما در Face Recognition ، برنامه چهره‌ها را پیدا می‌کند و می‌تواند تشخیص دهد که کدام چهره متعلق به کدام شخص است. بنابراین، کار بیشتری انجام می‌دهد. به عبارت دیگر، برنامه نویسی بیشتر و آموزش بیشتری در این فرآیند وجود دارد.

فرض کنید به خیابان نگاه می‌کنید و ماشین‌ها در حال عبور هستند. Face Detection مانند این است که بگوییم جسم عبوری ماشین است. و Face Recognition مانند این است که بتوانیم مدل ماشین عبوری را تشخیص دهیم. در این‌جا یک تصویر زیبا وجود دارد که تفاوت بین این دو را در عمل نشان می‌دهد.

آموزش پروژه محور پایتون - تشخیص چهره (Face Detection) با پایتون

در این مقاله، به آموزش پروژه محور پایتون در پروژه Face Detection ادامه خواهیم داد. اگر می‌خواهید Face Recognition را هم یاد بگیرید، در بخش نظرات کامنت بگذارید.

Face Recognition با پایتون

من از کتابخانه OpenCV در پایتون استفاده می‌کنم که به عنوان ابزار اصلی برای تسک‌های Computer Vision در پایتون استفاده می‌شود. اگر در کار با OpenCV تازه کار هستید، این بهترین مورد برای شروع است.

کتابخانه OpenCV به راحتی و با استفاده از دستور pip قابل نصب است:

				
					pip install opencv-python
				
			

پس از نصب این کتابخانه، باید به سادگی و با استفاده از دستور زیر آن را import کنید:

				
					import cv2

				
			

کتابخانه OpenCV در پایتون دارای classifier های از پیش آموزش‌دیده بسیاری برای صورت، چشم‌ها، لبخند و غیره است. این فایل‌های XML در یک پوشه ذخیره می‌شوند. ما از مدل Face Detection استفاده خواهیم کرد. مدل classifier از قبل آموزش دیده را می‌توانید از این‌جا دانلود کنید.

پس از دانلود و ذخیره فایل در دایرکتوری، اجازه دهید آن را در برنامه Face Detection بارگذاری کنیم:

				
					face_cascade = cv2.CascadeClassifier('face_detector.xml')
				
			

مرحله بعدی انتخاب تصویری است که می‌خواهید کد خود را روی آن آزمایش کنید. مطمئن شوید که حداقل یک چهره در تصویرتان وجود داشته باشد تا برنامه Face Detection بتواند حداقل یک چهره پیدا کند.

پس از انتخاب یک تصویر، اجازه دهید آن را در برنامه خود تعریف کنیم. مطمئن شوید که تصویر در همان دایرکتوری است که در آن کار می‌کنید:

				
					img = cv2.imread('image.jpg')

				
			

تشخیص چهره‌ها (Detect Faces)

از کوتاه بودن کد Face Detection در این آموزش پروژه محور پایتون، شگفت زده خواهید شد. با تشکر از کتابخانه OpenCV ، این کدی است که چهره‌ها را در یک تصویر تشخیص می‌دهد:

				
					faces = face_cascade.detectMultiScale(img, 1.1, 4)

				
			

آخرین مرحله، کشیدن مستطیل در اطراف چهره‌های شناسایی‌شده است که به راحتی با کد زیر قابل انجام است:

				
					for (x, y, w, h) in faces: 
  cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
cv2.imwrite("face_detected.png", img) 
print('Successfully saved')
				
			

به این ترتیب می‌توانیم به راحتی چهره یا چهره‌های موجود در تصویر را تشخیص دهیم. امیدوارم این پروژه در مورد Face Detection با پایتون به کار شما آمده باشد.

Face Detection Sample

آموزش پروژه محور پایتون: تبدیل فایل PDF به متن

در این بخش از این آموزش پروژه محور پایتون، شما را با نحوه استخراج متن از فایل‌های PDF  با پایتون آشنا می‌کنم. استخراج متن از PDF کار آسانی نیست، و برای کدنویسی آن با پایتون کارهای زیادی باید انجام دهید. اما من برای تسهیل کار، از یک پکیج پایتون به نام pdf2image استفاده می‌کنم که به راحتی با استفاده از دستور pip قابل نصب است:

				
					pip install pdf2image
				
			

بزرگترین چالشی که در هنگام استخراج متن از فایل PDF با آن روبرو هستیم، این است که فایل‌های PDF در فرمت‌های مختلفی وجود دارند. بنابراین، ابتدا باید تابعی را آماده کنیم تا بتوانیم هر فرمتی از یک فایل PDF را به فرمت مورد نظر خود تبدیل کنیم.

استخراج متن از PDF با استفاده از پایتون چگونه است؟

در ابتدای این پروژه از آموزش پروژه محور پایتون، باید تمام پکیج‌ها را وارد کنیم. برای تبدیل فایل‌های PDF به فایل‌های تصویری ppm به pdf2image نیاز دارید.

همچنین باید مسیرهای پیوستگی (Paths to Join) را دستکاری کنیم و نام فایل‌های متنی را تغییر دهیم. برای این کار، پکیج‌های os و sys را وارد می‌کنیم. قسمت زیر یک کتابخانه PIL را فراخوانی می‌کند و تصویر را با pytesseract وارد می‌کند:

				
					import pdf2image
import os, sys
try:
    from PIL import Image
except ImportError:
    import Image
import pytesseract
				
			

اکنون باید مسیر اسناد (Path of Documents) شما و شمارنده (Counter) را مقداردهی کنیم تا بعداً در تابع pdf extract برای شمارش اسناد شما در پوشه استفاده شود:

				
					PATH = 'Enter your path'

#initialize the counter that you will use later in your pdf extraction function
i = 1
				
			

اکنون ما باید برخی از فایل‌های غیر ضروری را از فایل‌های pdf خود حذف کنیم. برای این کار، من یک تابع جدید ایجاد می‌کنم:

				
					def delete_ppms():
  for file in os.listdir(PATH):
    if '.ppm' in file or '.DS_Store' in file:
      try:
          os.remove(PATH + file)
      except FileNotFoundError:
          pass
				
			

حال باید فایل‌های pfd را بر اساس نوع آن‌ها مرتب کنیم. من این کار را با ایجاد دو لیست برای فایل‌های pdf و فایل‌های docx شروع می‌کنم؛ زیرا این دو فرمت از پرکاربردترین انواع فرمت‌ها در فایل‌های متنی هستند:

				
					pdf_files = []
docx_files = []

# append document names into the lists by their extension type
for f in os.listdir(PATH):
  full_name = os.path.join(PATH, f) 
  if os.path.isfile(full_name):
    name = os.path.basename(f)
    filename, ext = os.path.splitext(name)
    if ext == '.pdf':
      pdf_files.append(name)
    elif ext == ('.docx'):
      docx_files.append(name)
				
			

اکنون می‌توانیم به طور نهایی متن را از فایل‌های PDF استخراج کنیم. در این‌جا تابع pdf_extract در ابتدا نام هر فایلی که متن از آن استخراج می‌شود را چاپ می‌کند. بسته به اندازه سند، استخراج آن ممکن است کمی طول بکشد.

این تابع print به شما کمک می‌کند تا ببینید کدام فایل در حال حاضر بررسی شده است:

				
					def pdf_extract(file, i):
  print("extracting from file:", file)
  delete_ppms()
  images = pdf2image.convert_from_path(PATH + file, output_folder=PATH)
  j = 0
  for file in sorted (os.listdir(PATH)):
      if '.ppm' in file and 'image' not in file:
        os.rename(PATH + file, PATH + 'image' + str(i) + '-' + str(j) + '.ppm')
        j += 1
  j = 0
  f = open(PATH +'result{}.txt'.format(i), 'w')
  files = [f for f in os.listdir(PATH) if '.ppm' in f]

  for file in sorted(files, key=lambda x: int(x[x.index('-') + 1: x.index('.')])):
      temp = pytesseract.image_to_string(Image.open(PATH + file))
      f.write(temp)
  f.close()
				
			

اکنون می‌توانیم از تابع خود برای استخراج از تمام فایل‌های pdf در این آموزش پروژه محور پایتون استفاده کنیم:

				
					for i in range(len(pdf_files)):
  pdf_file = pdf_files[i]
  pdf_extract(pdf_file, i)
				
			

اکنون پس از اجرای تابع، اگر به دایرکتوری بروید، یک فایل متنی به نام result1.txt با تمام متن استخراج شده از فایل PDF مشاهده خواهید کرد. اگر سؤالی درباره این پروژه داشتید، آن را در کامنت‌ها مطرح کنید.

آموزش پروژه محور پایتون: بازی ورق

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

Class Card

در این‌جا یک class وجود دارد که کارت‌های بازی را مدل می‌کند:

				
					class Card:
    suits = ["spades",
             "hearts",
             "diamonds",
             "clubs"]
    
    values = [None, None,"2", "3",
              "4", "5", "6", "7",
              "8", "9", "10",
              "Jack", "Queen",
              "King", "Ace"]

    def __init__(self, v, s):
        """suit + value are ints"""
        self.value = v
        self.suit = s

    def __lt__(self, c2):
        if self.value < c2.value:
            return True
        if self.value == c2.value:
            if self.suit < c2.suit:
                return True
            else:
                return False
        return False

    def __gt__(self, c2):
        if self.value > c2.value:
            return True
        if self.value == c2.value:
            if self.suit > c2.suit:
                return True
            else:
                return False
        return False

    def __repr__(self):
        v = self.values[self.value] +\
            " of " + \
            self.suits[self.suit]
        return v
				
			

اولین class در بازی ورق ما در این آموزش پروژه محور پایتون، یک class کارت است که دارای دو متغیر class ، بخش‌های بدنه (suits) و مقادیر (Values) است. Suits یک tuple از string ها است که تمام خال‌هایی را که یک کارت می‌تواند باشد نشان می‌دهند: گشنیز، خشت، پیک و دل (spades, hearts, diamonds, clubs). مقدار (value) یک tuple از string هایی است که مقادیر عددی متفاوتی را که یک کارت می‌تواند داشته باشد، نشان می‌دهد: 2 تا 10، سرباز، بی‌بی، شاه و آس (Jack, Queen, King, Ace).

عناصر دو شاخص (index) اول مقدار (value) مربوط به tuple هستند، بنابراین string های tuple با شاخصی که نشان می‌دهند، مطابقت دارند. بنابراین string کارت «2» در یک tuple از مقادیر (values)، در index کارت 2 است.

آبجکت‌های کارت (Card objects) دارای دو متغیر نمونه هستند: suit و value که هر کدام با یک عدد صحیح نمایش داده می‌شوند. متغیرهای نمونه با هم نوع Card object را نشان می‌دهند. به عنوان مثال، با ایجاد یک Card object و ارسال پارامترهای 2 (برای خال) و 1، یک 2 دل ایجاد می‌کنید.

این کد برای این متدهای جادویی همچنین می‌تواند نشان دهد که آیا کارت‌ها دارای ارزش یکسانی هستند یا خیر. به عنوان مثال، اگر هر دو کارت دارای ارزش 10 باشند،  متدها از value مربوط به ترکیب کارت‌ها، برای بریدن دست و مساوی نشدن استفاده می‌کنند.

ترکیب‌ها به ترتیب قدرت در ترکیب چندگانه tuple رده‌بندی می‌شوند. با قوی‌ترین ترکیب در آخر. بنابراین، قوی‌ترین ترکیب به بالاترین شاخص (index) و ضعیف‌ترین ترکیب به پایین‌ترین شاخص اختصاص داده می‌شود.

Class Deck

در مرحله بعد پروژه بازی ورق در این آموزش پروژه محور پایتون، برای نشان دادن یک دست کارت باید یک class تعریف کنید:

				
					from random import shuffle


class Deck:
    def __init__(self):
        self.cards = []
        for i in range(2, 15):
            for j in range(4):
                self.cards\
                    .append(Card(i,
                                 j))
        shuffle(self.cards)

    def rm_card(self):
        if len(self.cards) == 0:
            return
        return self.cards.pop()
				
			

هنگامی که Deck object را مقداردهی اولیه می‌کنید، دو حلقه (loop) __init__ ، Card object هایی را ایجاد می‌کنند که نشان دهنده تمام کارت‌های یک دست 52 کارتی است و آن‌ها را به لیست کارت‌ها اضافه می‌کنند. اولین loop از 2 به 15 می‌رود، به این دلیل که اولین value یک کارت 2 و آخرین value آن 15 (آس) است.

هر بار در اطراف loop داخلی، یک کارت جدید با استفاده از عدد صحیح از loop بیرونی به عنوان مقدار (یعنی 14 برای یک آس) و عدد صحیح از loop داخلی به عنوان خال ایجاد می‌شود. این فرآیند 52 کارت ایجاد می‌کند. یک کارت به ازای هر ترکیب از خال و ارزش عددی.

پس از این که متد کارت‌ها را ایجاد کرد، متد shuffle از ماژول shuffle به طور تصادفی موارد موجود در لیست کارت‌ها را مرتب می‌کند. این تقلیدی از بر زدن یک دست ورق است.

Deck ما متد دیگری به نام rm_card دارد که یک کارت را از لیست کارت‌ها حذف و برمی‌گرداند. یا اگر خالی باشد، None را برمی‌گرداند.

Class Player

شما برای نشان دادن هر بازیکن در بازی، به یک class نیاز دارید تا کارت‌های آن‌ها و تعداد دست‌هایی که هر کدام برده‌اند را دنبال کنید:

				
					class Player:
   def __init__(self, name):
       self.wins = 0
       self.card = None
       self.name = name
				
			

Player class دارای سه متغیر نمونه است: wins (بردها) برای پیگیری تعداد دست‌هایی که بازیکن برده است، card که نشان دهنده کارتی است که بازیکن در حال حاضر در دست دارد و name برای پیگیری هر بازیکن.

Class Game

در نهایت، شما برای نمایش بازی در این آموزش پروژه محور پایتون، به یک class نیاز دارید:

				
					class Game:
    def __init__(self):
        name1 = input("p1 name ")
        name2 = input("p2 name ")
        self.deck = Deck()
        self.p1 = Player(name1)
        self.p2 = Player(name2)

    def wins(self, winner):
        w = "{} wins this round"
        w = w.format(winner)
        print(w)

    def draw(self, p1n, p1c, p2n, p2c):
        d = "{} drew {} {} drew {}"
        d = d.format(p1n,
                     p1c,
                     p2n,
                     p2c)
        print(d)

    def play_game(self):
        cards = self.deck.cards
        print("beginning War!")
        while len(cards) >= 2:
            m = "q to quit. Any " + \
                "key to play:"
            response = input(m)
            if response == 'q':
                break
            p1c = self.deck.rm_card()
            p2c = self.deck.rm_card()
            p1n = self.p1.name
            p2n = self.p2.name
            self.draw(p1n,
                      p1c,
                      p2n,
                      p2c)
            if p1c > p2c:
                self.p1.wins += 1
                self.wins(self.p1.name)
            else:
                self.p2.wins += 1
                self.wins(self.p2.name)

        win = self.winner(self.p1,
                         self.p2)
        print("War is over.{} wins"
              .format(win))

    def winner(self, p1, p2):
        if p1.wins > p2.wins:
            return p1.name
        if p1.wins < p2.wins:
            return p2.name
        return "It was a tie!"
				
			

هنگامی که game object را ایجاد می‌کنید، پایتون متد __init__ را فراخوانی می‌کند و تابع ورودی نام دو بازیکن بازی را جمع‌آوری کرده و در متغیرهای name1 و name2 ذخیره می‌کند.

سپس یک Deck object جدید ایجاد می‌کنید، آن را در deck متغیر نمونه ذخیره می‌کنید و با استفاده از name1 و name2 دو Player object ایجاد می‌کنید. متد play_game از Game class بازی را شروع می‌کند. یک loop در این متد وجود دارد که تا زمانی که دو یا چند کارت بر روی زمین باقی مانده باشند، و تا زمانی که پاسخ متغیر برابر با q نباشد، بازی را ادامه می‌دهد.

در هر چرخش loop ، پاسخ متغیر را به ورودی کاربر اختصاص می‌دهید. بازی تا زمانی ادامه می‌یابد که کاربر q را تایپ کند یا کمتر از دو کارت روی زمین باقی بماند. هر بار دو کارت در loop کشیده می‌شود و متد play_game کارت اول را به p1 و کارت دوم را به p2 اختصاص می‌دهد.

سپس نام هر بازیکن و کارتی را که کشیده است، print می‌کند و در مرحله بعد، دو کارت را با هم مقایسه می‌کند تا ببیند کدام یک بزرگتر است. متغیر نمونه برد را به بازیکنی اختصاص می‌دهد که بالاترین کارت را دارد و پیامی را print می‌کند که نشان می‌دهد او برنده شده است. Game class همچنین متدی به نام winning دارد که دو آیتم بازیکن را می‌گیرد، به تعداد دست‌هایی که هر کدام برنده شده‌اند نگاه می‌کند و بازیکنی را که بیشترین دست را برده است، به عنوان برنده نهایی بازمی‌گرداند.

وقتی کارت‌های Deck object تمام می‌شود، متد play_game پیامی war is over را به منظور پایان بازی نشان می‌دهد، متد winning را فراخوانی می‌کند (هر دو p1 و p2 را pass می‌کند)، و پیامی را به عنوان نتیجه نشان می‌دهد. این پیام حاوی نام بازیکنی است که برنده شده است.

کد کامل

کد کامل بازی ورق در این آموزش پروژه محور پایتون این است:

				
					from random import shuffle


class Card:
    suits = ["spades",
             "hearts",
             "diamonds",
             "clubs"]

    values = [None, None,"2", "3",
              "4", "5", "6", "7",
              "8", "9", "10",
              "Jack", "Queen",
              "King", "Ace"]

    def __init__(self, v, s):
        """suit + value are ints"""
        self.value = v
        self.suit = s

    def __lt__(self, c2):
        if self.value < c2.value:
            return True
        if self.value == c2.value:
            if self.suit < c2.suit:
                return True
            else:
                return False
        return False

    def __gt__(self, c2):
        if self.value > c2.value:
            return True
        if self.value == c2.value:
            if self.suit > c2.suit:
                return True
            else:
                return False
        return False

    def __repr__(self):
        v = self.values[self.value] +\
            " of " + \
            self.suits[self.suit]
        return v


class Deck:
    def __init__(self):
        self.cards = []
        for i in range(2, 15):
            for j in range(4):
                self.cards\
                    .append(Card(i,
                                 j))
        shuffle(self.cards)

    def rm_card(self):
        if len(self.cards) == 0:
            return
        return self.cards.pop()


class Player:
    def __init__(self, name):
        self.wins = 0
        self.card = None
        self.name = name


class Game:
    def __init__(self):
        name1 = input("p1 name ")
        name2 = input("p2 name ")
        self.deck = Deck()
        self.p1 = Player(name1)
        self.p2 = Player(name2)

    def wins(self, winner):
        w = "{} wins this round"
        w = w.format(winner)
        print(w)

    def draw(self, p1n, p1c, p2n, p2c):
        d = "{} drew {} {} drew {}"
        d = d.format(p1n,
                     p1c,
                     p2n,
                     p2c)
        print(d)

    def play_game(self):
        cards = self.deck.cards
        print("beginning War!")
        while len(cards) >= 2:
            m = "q to quit. Any " + \
                "key to play:"
            response = input(m)
            if response == 'q':
                break
            p1c = self.deck.rm_card()
            p2c = self.deck.rm_card()
            p1n = self.p1.name
            p2n = self.p2.name
            self.draw(p1n,
                      p1c,
                      p2n,
                      p2c)
            if p1c > p2c:
                self.p1.wins += 1
                self.wins(self.p1.name)
            else:
                self.p2.wins += 1
                self.wins(self.p2.name)

        win = self.winner(self.p1,
                         self.p2)
        print("War is over.{} wins"
              .format(win))

    def winner(self, p1, p2):
        if p1.wins > p2.wins:
            return p1.name
        if p1.wins < p2.wins:
            return p2.name
        return "It was a tie!"

game = Game()
game.play_game()
				
			

امیدوارم این پروژه درباره ساخت بازی ورق با پایتون مورد پسند شما واقع شده باشد. خوشحال می‌شویم که سؤالات ارزشمند خود را در بخش کامنت‌ها بپرسید.

آموزش پروژه محور پایتون: Web Scraper

در این بخش از آموزش پروژه محور پایتون، من قصد دارم با این زبان برنامه نویسی یک Web Scraper ایجاد کنم که با استخراج تمام تگ‌ها از HTML مربوط به Google News ، تمام Story های آن را بیرون بکشد.

Google News از تگ‌ها برای ایجاد لینک‌هایی به وب‌سایت‌های مختلف که سایت را تشکیل می‌دهند، استفاده می‌کند. بنابراین علاوه بر برخی داده‌های اضافی، تمام URL های مقالاتی را که Google News نمایش می‌دهد، جمع آوری می‌کنید. من برای آنالیز مقالات از Google News ، از ماژول BeautifulSoup استفاده خواهم کرد.

Parsing به معنای گرفتن فرمتی مانند HTML و استفاده از یک زبان برنامه نویسی برای ساختار دادن به آن است. به عنوان مثال، برای تبدیل داده‌ها به یک شیء. اکنون برای شروع کار ساختن یک Web Scraper با پایتون، باید ماژولی به نام BeautifulSoup را نصب کنید. با استفاده از دستور pip به آسانی می‌توان آن را نصب کرد:

				
					pip install beautifulsoup4
				
			

ساخت Web Scraper با پایتون چگونه است؟

پایتون برای کار با URL ها، یک ماژول داخلی به نام urllib دارد. کد زیر را به فایل پایتون جدید اضافه کنید:

				
					import urllib.request
from bs4 import BeautifulSoup


class Scraper:
    def __init__(self, site):
        self.site = site
				
			

متد __init__ از یک وب سایت برای استخراج به عنوان یک پارامتر استفاده می‌کند. بعدتر باید https://news.google.com/ را به عنوان پارامتر ارسال کنید. کلاس Scraper متدی به نام scrape دارد که هر زمان بخواهید داده‌های سایتی را که ارسال کردید بازیابی کنید، آن را فراخوانی می‌کنید.

کد زیر را به متد scrape خود اضافه کنید:

				
					    def scrape(self):
        r = urllib.request.urlopen(self.site)
        html = r.read()
				
			

تابع urlopen() در این آموزش پروژه محور پایتون، درخواستی را به یک وب سایت ارسال می‌کند و یک Response object را که کد HTML در آن ذخیره شده استف همراه با داده‌های اضافی برمی‌گرداند. پاسخ تابع read() ، HTML مربوط به Response object را برمی‌گرداند. تمام HTML برای وب سایت در متغیر html قرار دارد.

اکنون شما آماده آنالیز HTML هستید. یک خط کد جدید در تابع scrape اضافه کنید که یک BeautifulSoup object ایجاد کند و متغیر html و رشته “html.parser” را به عنوان پارامتر ارسال کنید:

				
					 def scrape(self):
        r = urllib.request.urlopen(self.site)
        html = r.read()
        parser = "html.parser"
        sp = BeautifulSoup(html,parser)
				
			

BeautifulSoup object تمام کارهای سخت را انجام داده و HTML مربوطه را تجزیه (Parsing) می‌کند. اکنون می‌توانید کدی را به تابع scrape اضافه کنید که متد find_all را در BeautifulSoup object فراخوانی می‌کند.

“a” را به عنوان پارامتر ارسال کنید و این متد تمام URL های وب سایت لینک‌شده در HTML code خاصی که شما دانلود کرده‌اید را برمی‌گرداند:

				
					 def scrape(self):
        r = urllib.request.urlopen(self.site)
        html = r.read()
        parser = "html.parser"
        sp = BeautifulSoup(html,parser)
        for tag in sp.find_all("a"):
            url = tag.get("href")
            if url is None:
                continue
            if "articles" in url:
                print("\n" + url)
				
			

متد find_all ، یک iterable حاوی tag object های یافت شده را برمی‌گرداند. هر بار در اطراف حلقه for ، متغیر مقدار یک tag object جدید را دریافت می‌کند. هر tag object دارای متغیرهای نمونه مختلفی است، اما شما فقط مقدار متغیر نمونه href را می‌خواهید که شامل هر URL است.

شما می‌توانید با فراخوانی متد get و ارسال “href” به عنوان یک پارامتر، آن را دریافت کنید. در نهایت، شما تأیید می‌کنید که متغیر URL حاوی داده است. این شامل رشته “articles” است (شما نمی‌خواهید لینک‌های داخلی را print کنید)؛ و اگر چنین است، آن را print کنید. این یک Web Scraper کامل است:

				
					import urllib.request
from bs4 import BeautifulSoup


class Scraper:
    def __init__(self, site):
        self.site = site

    def scrape(self):
        r = urllib.request.urlopen(self.site)
        html = r.read()
        parser = "html.parser"
        sp = BeautifulSoup(html,parser)
        for tag in sp.find_all("a"):
            url = tag.get("href")
            if url is None:
                continue
            if "articles" in url:
                print("\n" + url)

news = "https://news.google.com/"
Scraper(news).scrape()
				
			

هنگامی که برنامه خود را اجرا می‌کنید، خروجی باید به شکل زیر باشد:

				
					./articles/CBMiiQFodHRwczovL3d3dy5tb25leWNvbnRyb2wuY29tL25ld3MvYnVzaW5lc3MvaXBvL2J1bXBlci1saXN0aW5nLWNoZW1jb24tc3BlY2lhbGl0eS1jaGVtaWNhbHMtZGVidXRzLWF0LXJzLTczMC05NS1hLTExNS1wcmVtaXVtLTU5MDc2MjEuaHRtbNIBjQFodHRwczovL3d3dy5tb25leWNvbnRyb2wuY29tL25ld3MvYnVzaW5lc3MvaXBvL2J1bXBlci1saXN0aW5nLWNoZW1jb24tc3BlY2lhbGl0eS1jaGVtaWNhbHMtZGVidXRzLWF0LXJzLTczMC05NS1hLTExNS1wcmVtaXVtLTU5MDc2MjEuaHRtbC9hbXA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiiQFodHRwczovL3d3dy5tb25leWNvbnRyb2wuY29tL25ld3MvYnVzaW5lc3MvaXBvL2J1bXBlci1saXN0aW5nLWNoZW1jb24tc3BlY2lhbGl0eS1jaGVtaWNhbHMtZGVidXRzLWF0LXJzLTczMC05NS1hLTExNS1wcmVtaXVtLTU5MDc2MjEuaHRtbNIBjQFodHRwczovL3d3dy5tb25leWNvbnRyb2wuY29tL25ld3MvYnVzaW5lc3MvaXBvL2J1bXBlci1saXN0aW5nLWNoZW1jb24tc3BlY2lhbGl0eS1jaGVtaWNhbHMtZGVidXRzLWF0LXJzLTczMC05NS1hLTExNS1wcmVtaXVtLTU5MDc2MjEuaHRtbC9hbXA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiiQFodHRwczovL3d3dy5tb25leWNvbnRyb2wuY29tL25ld3MvYnVzaW5lc3MvaXBvL2J1bXBlci1saXN0aW5nLWNoZW1jb24tc3BlY2lhbGl0eS1jaGVtaWNhbHMtZGVidXRzLWF0LXJzLTczMC05NS1hLTExNS1wcmVtaXVtLTU5MDc2MjEuaHRtbNIBjQFodHRwczovL3d3dy5tb25leWNvbnRyb2wuY29tL25ld3MvYnVzaW5lc3MvaXBvL2J1bXBlci1saXN0aW5nLWNoZW1jb24tc3BlY2lhbGl0eS1jaGVtaWNhbHMtZGVidXRzLWF0LXJzLTczMC05NS1hLTExNS1wcmVtaXVtLTU5MDc2MjEuaHRtbC9hbXA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEN65JBQTlrAk1479WuKaQrAqFwgEKg4IACoGCAowxLQ_MNevCDDnvNMF?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEN65JBQTlrAk1479WuKaQrAqFwgEKg4IACoGCAowxLQ_MNevCDDnvNMF?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEIfG6g8TDa91LrUgvv4SfRcqGQgEKhAIACoHCAow2pqGCzD954MDMJzyigY?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEIfG6g8TDa91LrUgvv4SfRcqGQgEKhAIACoHCAow2pqGCzD954MDMJzyigY?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEG22Qtp4ab78Y5kFLRsWq-wqGQgEKhAIACoHCAow55veCjDzvdUBMIPh5gU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEG22Qtp4ab78Y5kFLRsWq-wqGQgEKhAIACoHCAow55veCjDzvdUBMIPh5gU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEEQDNi_6fessB82J6KVeq60qFggEKg4IACoGCAowxLQ_MNevCDCkoh8?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEEQDNi_6fessB82J6KVeq60qFggEKg4IACoGCAowxLQ_MNevCDCkoh8?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEKuQtxbx8j-uunfY5g-gOtoqFggEKg4IACoGCAoww7k_MMevCDDpywE?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEKuQtxbx8j-uunfY5g-gOtoqFggEKg4IACoGCAoww7k_MMevCDDpywE?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEKuQtxbx8j-uunfY5g-gOtoqFggEKg4IACoGCAoww7k_MMevCDDpywE?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CCAiC0o4TkNDS2JxVUhjmAEB?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CCAiC0o4TkNDS2JxVUhjmAEB?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEEGQxdSeKlwa2YvVLQyLUb8qFwgEKg4IACoGCAoww7k_MMevCDC6rdgG?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEEGQxdSeKlwa2YvVLQyLUb8qFwgEKg4IACoGCAoww7k_MMevCDC6rdgG?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEJM9pEXAVv1HEP1h6QlDxTIqGAgEKg8IACoHCAow3rvTBDD89X4w0bTmBQ?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEJM9pEXAVv1HEP1h6QlDxTIqGAgEKg8IACoHCAow3rvTBDD89X4w0bTmBQ?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEKG6ZOcOPT_OJQ6OLwGKe7sqGQgEKhAIACoHCAowzrL9CjDC7vQCMK2y1gU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEKG6ZOcOPT_OJQ6OLwGKe7sqGQgEKhAIACoHCAowzrL9CjDC7vQCMK2y1gU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEKG6ZOcOPT_OJQ6OLwGKe7sqGQgEKhAIACoHCAowzrL9CjDC7vQCMK2y1gU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEB_BeoliNbGwiNgLG9wZvAcqGQgEKhAIACoHCAowj8n_CjDIrfkCMJWZ2AY?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEB_BeoliNbGwiNgLG9wZvAcqGQgEKhAIACoHCAowj8n_CjDIrfkCMJWZ2AY?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMia2h0dHBzOi8vdGltZXNvZmluZGlhLmluZGlhdGltZXMuY29tL2NpdHkvaHlkZXJhYmFkL3dhcy1tb3NxdWUtZGVtb2xpc2hlZC1tYWdpY2FsbHkvYXJ0aWNsZXNob3cvNzg0MTU3OTAuY21z0gFmaHR0cHM6Ly9tLnRpbWVzb2ZpbmRpYS5jb20vY2l0eS9oeWRlcmFiYWQvd2FzLW1vc3F1ZS1kZW1vbGlzaGVkLW1hZ2ljYWxseS9hbXBfYXJ0aWNsZXNob3cvNzg0MTU3OTAuY21z?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMia2h0dHBzOi8vdGltZXNvZmluZGlhLmluZGlhdGltZXMuY29tL2NpdHkvaHlkZXJhYmFkL3dhcy1tb3NxdWUtZGVtb2xpc2hlZC1tYWdpY2FsbHkvYXJ0aWNsZXNob3cvNzg0MTU3OTAuY21z0gFmaHR0cHM6Ly9tLnRpbWVzb2ZpbmRpYS5jb20vY2l0eS9oeWRlcmFiYWQvd2FzLW1vc3F1ZS1kZW1vbGlzaGVkLW1hZ2ljYWxseS9hbXBfYXJ0aWNsZXNob3cvNzg0MTU3OTAuY21z?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiigFodHRwczovL3RpbWVzb2ZpbmRpYS5pbmRpYXRpbWVzLmNvbS9jaXR5L2x1Y2tub3cvY291cnRyb29tLXRlbnNlLWFzLWp1ZGdlLXNwb2tlLWphaS1zcmktcmFtLWNyaWVzLWFmdGVyLWFjcXVpdHRhbC9hcnRpY2xlc2hvdy83ODQxNjU0NC5jbXPSAYUBaHR0cHM6Ly9tLnRpbWVzb2ZpbmRpYS5jb20vY2l0eS9sdWNrbm93L2NvdXJ0cm9vbS10ZW5zZS1hcy1qdWRnZS1zcG9rZS1qYWktc3JpLXJhbS1jcmllcy1hZnRlci1hY3F1aXR0YWwvYW1wX2FydGljbGVzaG93Lzc4NDE2NTQ0LmNtcw?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiigFodHRwczovL3RpbWVzb2ZpbmRpYS5pbmRpYXRpbWVzLmNvbS9jaXR5L2x1Y2tub3cvY291cnRyb29tLXRlbnNlLWFzLWp1ZGdlLXNwb2tlLWphaS1zcmktcmFtLWNyaWVzLWFmdGVyLWFjcXVpdHRhbC9hcnRpY2xlc2hvdy83ODQxNjU0NC5jbXPSAYUBaHR0cHM6Ly9tLnRpbWVzb2ZpbmRpYS5jb20vY2l0eS9sdWNrbm93L2NvdXJ0cm9vbS10ZW5zZS1hcy1qdWRnZS1zcG9rZS1qYWktc3JpLXJhbS1jcmllcy1hZnRlci1hY3F1aXR0YWwvYW1wX2FydGljbGVzaG93Lzc4NDE2NTQ0LmNtcw?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEHNTCoiBrzsZh27XzSLO4BgqGAgEKg8IACoHCAow3rvTBDD89X4w8YzmBQ?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEHNTCoiBrzsZh27XzSLO4BgqGAgEKg8IACoHCAow3rvTBDD89X4w8YzmBQ?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMikgFodHRwczovL3d3dy5uZXdzMTguY29tL25ld3MvYnV6ei9qb2UtYmlkZW4tc2FpZC1pbnNoYWxsYWgtdG8tdHJvbGwtZG9uYWxkLXRydW1wLWR1cmluZy1wcmVzaWRlbnRpYWwtZGViYXRlLXR3aXR0ZXItc2F5cy1pdHMtcGVhay0yMDIwLTI5MjI3MDUuaHRtbNIBlgFodHRwczovL3d3dy5uZXdzMTguY29tL2FtcC9uZXdzL2J1enovam9lLWJpZGVuLXNhaWQtaW5zaGFsbGFoLXRvLXRyb2xsLWRvbmFsZC10cnVtcC1kdXJpbmctcHJlc2lkZW50aWFsLWRlYmF0ZS10d2l0dGVyLXNheXMtaXRzLXBlYWstMjAyMC0yOTIyNzA1Lmh0bWw?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMikgFodHRwczovL3d3dy5uZXdzMTguY29tL25ld3MvYnV6ei9qb2UtYmlkZW4tc2FpZC1pbnNoYWxsYWgtdG8tdHJvbGwtZG9uYWxkLXRydW1wLWR1cmluZy1wcmVzaWRlbnRpYWwtZGViYXRlLXR3aXR0ZXItc2F5cy1pdHMtcGVhay0yMDIwLTI5MjI3MDUuaHRtbNIBlgFodHRwczovL3d3dy5uZXdzMTguY29tL2FtcC9uZXdzL2J1enovam9lLWJpZGVuLXNhaWQtaW5zaGFsbGFoLXRvLXRyb2xsLWRvbmFsZC10cnVtcC1kdXJpbmctcHJlc2lkZW50aWFsLWRlYmF0ZS10d2l0dGVyLXNheXMtaXRzLXBlYWstMjAyMC0yOTIyNzA1Lmh0bWw?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMikgFodHRwczovL3d3dy5uZXdzMTguY29tL25ld3MvYnV6ei9qb2UtYmlkZW4tc2FpZC1pbnNoYWxsYWgtdG8tdHJvbGwtZG9uYWxkLXRydW1wLWR1cmluZy1wcmVzaWRlbnRpYWwtZGViYXRlLXR3aXR0ZXItc2F5cy1pdHMtcGVhay0yMDIwLTI5MjI3MDUuaHRtbNIBlgFodHRwczovL3d3dy5uZXdzMTguY29tL2FtcC9uZXdzL2J1enovam9lLWJpZGVuLXNhaWQtaW5zaGFsbGFoLXRvLXRyb2xsLWRvbmFsZC10cnVtcC1kdXJpbmctcHJlc2lkZW50aWFsLWRlYmF0ZS10d2l0dGVyLXNheXMtaXRzLXBlYWstMjAyMC0yOTIyNzA1Lmh0bWw?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiMmh0dHBzOi8vd3d3LmJiYy5jb20vbmV3cy9lbGVjdGlvbi11cy0yMDIwLTU0MzU5OTkz0gE2aHR0cHM6Ly93d3cuYmJjLmNvbS9uZXdzL2FtcC9lbGVjdGlvbi11cy0yMDIwLTU0MzU5OTkz?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiMmh0dHBzOi8vd3d3LmJiYy5jb20vbmV3cy9lbGVjdGlvbi11cy0yMDIwLTU0MzU5OTkz0gE2aHR0cHM6Ly93d3cuYmJjLmNvbS9uZXdzL2FtcC9lbGVjdGlvbi11cy0yMDIwLTU0MzU5OTkz?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEN6aa394GsWZUcUGXrA5c1MqFggEKg4IACoGCAowl6p7MN-zCTCOvRU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEN6aa394GsWZUcUGXrA5c1MqFggEKg4IACoGCAowl6p7MN-zCTCOvRU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEN0KfjKEcFiAFIUFjmbZyVsqFAgEKgwIACoFCAowhgIwkDgwob0I?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEN0KfjKEcFiAFIUFjmbZyVsqFAgEKgwIACoFCAowhgIwkDgwob0I?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEB13zqCd52y2AMSVeJKeC0cqFggEKg4IACoGCAowl6p7MN-zCTC9vBU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEB13zqCd52y2AMSVeJKeC0cqFggEKg4IACoGCAowl6p7MN-zCTC9vBU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEMU5tjLhEKVlJN7lbLB1posqFwgEKg4IACoGCAowxLQ_MNevCDDnvNMF?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEMU5tjLhEKVlJN7lbLB1posqFwgEKg4IACoGCAowxLQ_MNevCDDnvNMF?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMisAFodHRwczovL3d3dy5uZXdzMTguY29tL25ld3MvaW5kaWEvY29yb25hdmlydXMtbGl2ZS11cGRhdGVzLW1vZGVybmFzLWNvdmlkLTE5LXNob3Qtd29udC1iZS1yZWFkeS1ieS11cy1lbGVjdGlvbnMtZmRhLXdpZGVucy1zYWZldHktaW5xdWlyeS1pbnRvLWFzdHJhemVuZWNhcy12YWNjaW5lLTI5MjM2MjkuaHRtbNIBtAFodHRwczovL3d3dy5uZXdzMTguY29tL2FtcC9uZXdzL2luZGlhL2Nvcm9uYXZpcnVzLWxpdmUtdXBkYXRlcy1tb2Rlcm5hcy1jb3ZpZC0xOS1zaG90LXdvbnQtYmUtcmVhZHktYnktdXMtZWxlY3Rpb25zLWZkYS13aWRlbnMtc2FmZXR5LWlucXVpcnktaW50by1hc3RyYXplbmVjYXMtdmFjY2luZS0yOTIzNjI5Lmh0bWw?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMisAFodHRwczovL3d3dy5uZXdzMTguY29tL25ld3MvaW5kaWEvY29yb25hdmlydXMtbGl2ZS11cGRhdGVzLW1vZGVybmFzLWNvdmlkLTE5LXNob3Qtd29udC1iZS1yZWFkeS1ieS11cy1lbGVjdGlvbnMtZmRhLXdpZGVucy1zYWZldHktaW5xdWlyeS1pbnRvLWFzdHJhemVuZWNhcy12YWNjaW5lLTI5MjM2MjkuaHRtbNIBtAFodHRwczovL3d3dy5uZXdzMTguY29tL2FtcC9uZXdzL2luZGlhL2Nvcm9uYXZpcnVzLWxpdmUtdXBkYXRlcy1tb2Rlcm5hcy1jb3ZpZC0xOS1zaG90LXdvbnQtYmUtcmVhZHktYnktdXMtZWxlY3Rpb25zLWZkYS13aWRlbnMtc2FmZXR5LWlucXVpcnktaW50by1hc3RyYXplbmVjYXMtdmFjY2luZS0yOTIzNjI5Lmh0bWw?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEHcEaDHAGN-USkGrC2ffI7sqGQgEKhAIACoHCAowj8n_CjDIrfkCMNCf6AU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEHcEaDHAGN-USkGrC2ffI7sqGQgEKhAIACoHCAowj8n_CjDIrfkCMNCf6AU?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiggFodHRwczovL2luZGlhbmV4cHJlc3MuY29tL2FydGljbGUvY29yb25hdmlydXMvbW9kZXJuYS1jb3ZpZC0xOS12YWNjaW5lLXdlbGwtdG9sZXJhdGVkLWdlbmVyYXRlcy1pbW11bmUtb2xkZXItYWR1bHRzLXN0dWR5LTY2NDg0NjUv0gGHAWh0dHBzOi8vaW5kaWFuZXhwcmVzcy5jb20vYXJ0aWNsZS9jb3JvbmF2aXJ1cy9tb2Rlcm5hLWNvdmlkLTE5LXZhY2NpbmUtd2VsbC10b2xlcmF0ZWQtZ2VuZXJhdGVzLWltbXVuZS1vbGRlci1hZHVsdHMtc3R1ZHktNjY0ODQ2NS9saXRlLw?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiggFodHRwczovL2luZGlhbmV4cHJlc3MuY29tL2FydGljbGUvY29yb25hdmlydXMvbW9kZXJuYS1jb3ZpZC0xOS12YWNjaW5lLXdlbGwtdG9sZXJhdGVkLWdlbmVyYXRlcy1pbW11bmUtb2xkZXItYWR1bHRzLXN0dWR5LTY2NDg0NjUv0gGHAWh0dHBzOi8vaW5kaWFuZXhwcmVzcy5jb20vYXJ0aWNsZS9jb3JvbmF2aXJ1cy9tb2Rlcm5hLWNvdmlkLTE5LXZhY2NpbmUtd2VsbC10b2xlcmF0ZWQtZ2VuZXJhdGVzLWltbXVuZS1vbGRlci1hZHVsdHMtc3R1ZHktNjY0ODQ2NS9saXRlLw?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEDfa74FROlvLHzyPIVDbXFYqFwgEKg4IACoGCAowxLQ_MNevCDDnvNMF?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEDfa74FROlvLHzyPIVDbXFYqFwgEKg4IACoGCAowxLQ_MNevCDDnvNMF?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEDetFhO9fBaleLttbd22zb4qFggEKg4IACoGCAoww7k_MMevCDDpywE?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEDetFhO9fBaleLttbd22zb4qFggEKg4IACoGCAoww7k_MMevCDDpywE?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEDetFhO9fBaleLttbd22zb4qFggEKg4IACoGCAoww7k_MMevCDDpywE?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEHgy-jTL75PvW0YSpz73cJMqGQgEKhAIACoHCAowzrL9CjDC7vQCMM6a0wY?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEHgy-jTL75PvW0YSpz73cJMqGQgEKhAIACoHCAowzrL9CjDC7vQCMM6a0wY?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEDH5jNSiFxuFpjIB29xGfY0qGAgEKg8IACoHCAow3rvTBDD89X4w8YzmBQ?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEDH5jNSiFxuFpjIB29xGfY0qGAgEKg8IACoHCAow3rvTBDD89X4w8YzmBQ?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEPGK1AAXrmZY6jsLb1sTa_MqGQgEKhAIACoHCAowj8n_CjDIrfkCMILSxQY?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CAIiEPGK1AAXrmZY6jsLb1sTa_MqGQgEKhAIACoHCAowj8n_CjDIrfkCMILSxQY?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiigFodHRwczovL2xpdmV1cGRhdGVzLmhpbmR1c3RhbnRpbWVzLmNvbS9pbmRpYS9jb3JvbmF2aXJ1cy1pbmRpYS13b3JsZC1sYXRlc3QtbmV3cy1jb3ZpZC0xOS1kZWF0aC10b2xsLXNlcHRlbWJlci0zMC0yMDIwLTIxNjAxNDI5OTE0MTM5Lmh0bWzSAY4BaHR0cHM6Ly9saXZldXBkYXRlcy5oaW5kdXN0YW50aW1lcy5jb20vaW5kaWEvY29yb25hdmlydXMtaW5kaWEtd29ybGQtbGF0ZXN0LW5ld3MtY292aWQtMTktZGVhdGgtdG9sbC1zZXB0ZW1iZXItMzAtMjAyMC0yMTYwMTQyOTkxNDEzOV9hbXAuaHRtbA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiigFodHRwczovL2xpdmV1cGRhdGVzLmhpbmR1c3RhbnRpbWVzLmNvbS9pbmRpYS9jb3JvbmF2aXJ1cy1pbmRpYS13b3JsZC1sYXRlc3QtbmV3cy1jb3ZpZC0xOS1kZWF0aC10b2xsLXNlcHRlbWJlci0zMC0yMDIwLTIxNjAxNDI5OTE0MTM5Lmh0bWzSAY4BaHR0cHM6Ly9saXZldXBkYXRlcy5oaW5kdXN0YW50aW1lcy5jb20vaW5kaWEvY29yb25hdmlydXMtaW5kaWEtd29ybGQtbGF0ZXN0LW5ld3MtY292aWQtMTktZGVhdGgtdG9sbC1zZXB0ZW1iZXItMzAtMjAyMC0yMTYwMTQyOTkxNDEzOV9hbXAuaHRtbA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiXGh0dHBzOi8vd3d3LmJvb21saXZlLmluL2Zha2UtbmV3cy9uby10aGlzLWlzLW5vdC1hLXBob3RvLW9mLXRoZS1kZWNlYXNlZC1oYXRocmFzLXZpY3RpbS05OTcw0gEA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiXGh0dHBzOi8vd3d3LmJvb21saXZlLmluL2Zha2UtbmV3cy9uby10aGlzLWlzLW5vdC1hLXBob3RvLW9mLXRoZS1kZWNlYXNlZC1oYXRocmFzLXZpY3RpbS05OTcw0gEA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiaGh0dHBzOi8vdGhlbG9naWNhbGluZGlhbi5jb20vZmFjdC1jaGVjay93b21hbi1hc3NhdWx0ZWQtdG9ydHVyZWQtaGF0aHJhcy11dHRhci1wcmFkZXNoLXZpcmFsLXBob3RvLTI0MDc50gEA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMiaGh0dHBzOi8vdGhlbG9naWNhbGluZGlhbi5jb20vZmFjdC1jaGVjay93b21hbi1hc3NhdWx0ZWQtdG9ydHVyZWQtaGF0aHJhcy11dHRhci1wcmFkZXNoLXZpcmFsLXBob3RvLTI0MDc50gEA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMidWh0dHBzOi8vd3d3LmluZGlhdG9kYXkuaW4vZmFjdC1jaGVjay9zdG9yeS93cm9uZy1naXJsLWdvZXMtdmlyYWwtb24tc29jaWFsLW1lZGlhLWFzLWhhdGhyYXMtdmljdGltLTE3MjY3MjItMjAyMC0wOS0yOdIBAA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMidWh0dHBzOi8vd3d3LmluZGlhdG9kYXkuaW4vZmFjdC1jaGVjay9zdG9yeS93cm9uZy1naXJsLWdvZXMtdmlyYWwtb24tc29jaWFsLW1lZGlhLWFzLWhhdGhyYXMtdmljdGltLTE3MjY3MjItMjAyMC0wOS0yOdIBAA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMibGh0dHBzOi8vd3d3LmFsdG5ld3MuaW4vdmlkZW8tc2hhcmVkLXRvLW1ha2UtbWlzbGVhZGluZy1jbGFpbS10aGF0LWhhdGhyYXMtdmljdGltcy1mYW1pbHktZGlkLWhlci1sYXN0LXJpdGVzL9IBAA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMibGh0dHBzOi8vd3d3LmFsdG5ld3MuaW4vdmlkZW8tc2hhcmVkLXRvLW1ha2UtbWlzbGVhZGluZy1jbGFpbS10aGF0LWhhdGhyYXMtdmljdGltcy1mYW1pbHktZGlkLWhlci1sYXN0LXJpdGVzL9IBAA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMibmh0dHBzOi8vZmFjdGx5LmluL29zZC10by1mb3JtZXItbWFoYXJhc2h0cmEtY20tZGV2ZW5kcmEtZmFkbmF2aXMtaXMtYmVpbmctcmVmZXJyZWQtYXMtb3NkLXRvLXVkZGhhdi10aGFja2VyYXkv0gEA?hl=en-IN&gl=IN&ceid=IN%3Aen

./articles/CBMibmh0dHBzOi8vZmFjdGx5LmluL29zZC10by1mb3JtZXItbWFoYXJhc2h0cmEtY20tZGV2ZW5kcmEtZmFkbmF2aXMtaXMtYmVpbmctcmVmZXJyZWQtYXMtb3NkLXRvLXVkZGhhdi10aGFja2VyYXkv0gEA?hl=en-IN&gl=IN&ceid=IN%3Aen

Process finished with exit code 0
				
			

اکنون با این Web Scraper که در آموزش پروژه محور پایتون یاد گرفتید، می‌توانید سرفصل‌های Google News را جمع‌آوری کنید. این شامل امکاناتی بی‌پایان است. شما می‌توانید برنامه‌ای بنویسید که کلمات پرکاربرد را در تیترها آنالیز کند. شما می‌توانید برنامه‌ای برای تجزیه و تحلیل احساسات بازار سهام ایجاد کنید و فرصت‌های معاملاتی را از این طریق کشف کنید.

در نهایت، می‌توان گفت که با داشتن یک Web Scraper ، دنیا برای شماست و امیدوارم که برای شما هم به اندازه من مفید باشد.

آموزش پروژه محور پایتون: ساخت طراحی با مداد به وسیله پایتون

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

آموزش پروژه محور پایتون: ساخت طراحی با مداد به وسیله پایتون
منبع: https://www.wallpapertip.com

در مرحله بعد، باید تصویر را با فرمت RBG بخوانیم و سپس آن را به یک grayscale image تبدیل کنیم. با این کار، تصویر به یک عکس سیاه و سفید کلاسیک تبدیل می‌شود.

سپس باید grayscale image را که negative image هم نامیده می‌شود، معکوس کنید. این تصویر همان grayscale image ماست که invert شده است. از inversion می‌توان برای افزایش جزئیات استفاده کرد.

در آخر، می‌توانیم با ترکیب کردن grayscale image و inverted image تار، یک طرح مدادی ایجاد کنیم. این کار را می‌توان با divide کردن grayscale image بر inverted image تارشده انجام داد. از آن‌جایی که تصاویر فقط آرایه هستند، به راحتی می‌توانیم این کار را با استفاده از تابع divide از کتابخانه cv2 در پایتون انجام دهیم.

بیایید کدنویسی کنیم

به تنها کتابخانه‌ای که برای آموزش پروژه محور پایتون: تبدیل تصویر به طرح مدادی نیاز داریم، کتابخانه OpenCV در پایتون است. با استفاده از دستور pip می‌توان از آن استفاده کرد.

				
					pip install opencv-python
				
			
				
					import cv2
				
			

من تصویر را در هر مرحله نمایش نمی‌دهم. اگر می‌خواهید تصویر را در هر مرحله نمایش دهید تا تغییرات را در آن مشاهده کنید، باید از دو دستور استفاده کنید. cv2.imshow(“Title You want to give”, Image) و سپس به سادگی cv2.waitKey(0) را بنویسید. با این کار، تصویر نمایش داده می‌شود.

حالا کار بعدی که باید انجام دهید این است که تصویر را بخوانید:

				
					image = cv2.imread("dog.jpg")
cv2.imshow("Dog", image)
cv2.waitKey(0)
				
			

اکنون پس از خواندن تصویر، با تبدیل تصویر اصلی به grayscale image ، یک تصویر جدید ایجاد می‌کنیم:

				
					gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow("New Dog", gray_image)
cv2.waitKey(0)
				
			

مرحله بعدی invert کردن تصویر جدید در مقیاس grayscale image است:

				
					inverted_image = 255 - gray_image
cv2.imshow("Inverted", inverted_image)
cv2.waitKey()
				
			

مرحله بعدی در این فرآیند، محو کردن تصویر با استفاده از تابع Gaussian در OpenCV است:

				
					blurred = cv2.GaussianBlur(inverted_image, (21, 21), 0)
				
			

مرحله نهایی این آموزش پروژه محور پایتون این است که تصویر تار شده را invert کنیم. سپس می‌توانیم به راحتی تصویر را به طرح مدادی تبدیل کنیم:

				
					inverted_blurred = 255 - blurred
pencil_sketch = cv2.divide(gray_image, inverted_blurred, scale=256.0)
cv2.imshow("Sketch", pencil_sketch)
cv2.waitKey(0)
				
			
طرح مدادی شده سگ

و در نهایت، اگر می‌خواهید هم به تصویر اصلی و هم به طرح مدادی نگاهی بیندازید، می‌توانید از دستورات زیر استفاده کنید:

				
					cv2.imshow("original image", image)
cv2.imshow("pencil sketch", pencil_sketch)
cv2.waitKey(0)
				
			
طرح اصلی و مدادی سگ کنار هم

بنابراین به این صورت است که می‌توانیم یک تصویر را با پایتون به طرح مدادی تبدیل کنیم. امیدوارم این مقاله در مورد نحوه تبدیل تصویر به طرح مدادی با پایتون مورد پسند شما قرار گرفته باشد.

بنابراین به این صورت، می‌توانیم یک تصویر را با پایتون به طرح مدادی تبدیل کنیم. امیدوارم این بخش از آموزش پروژه محور پایتون به کار شما آمده باشد.

آموزش پروژه محور پایتون: رابط کاربری گرافیکی متن با پایتون

در این بخش از آموزش پروژه محور پایتون، نحوه ایجاد رابط کاربری گرافیکی (GUI) ویرایشگر متن را به شما توضیح خواهم داد. این ویرایشگر متن می‌تواند فایل‌های متنی را ایجاد، ویرایش و ذخیره کند. برای ایجاد این GUI به سه ویجت مهم نیاز داریم. 2 ویجت دکمه برای ذخیره کردن و بستن، و ویجت text box برای ایجاد و ویرایش فایل‌های متنی.

GUI ویرایشگر متن چگونه با پایتون کدنویسی می‌شود؟

تمام ویجت‌ها باید به گونه‌ای مرتب شوند که ویجت‌های دکمه‌ها در سمت چپ layout پنجره و ویجت text box در سمت راست آن قرار بگیرند.

ارتفاع کل پنجره باید حداقل 800 پیکسل باشد و ویجت جعبه متن باید حداقل 800 پیکسل عرض داشته باشد. کل layout باید responsive باشد تا اگر اندازه پنجره تغییر کرد، اندازه ویجت text box نیز تغییر کند.

تصویر زیر نشان می‌دهد که یک ویرایشگر متن پایه، چگونه به نظر می‌رسد. اما به جای اضافه کردن دکمه‌های save as و open در بالا، آن‌ها را در سمت چپ ویرایشگر متن اضافه می‌کنیم:

آموزش پروژه محور پایتون: رابط کاربری گرافیکی متن با پایتون

من برای ساختن رابط کاربری گرافیکی ویرایشگر متن، از پکیج Tkinter در پایتون استفاده خواهم کرد. اکنون که ایده این کار را داریم، بیایید کدنویسی را شروع کنیم.

من این پروژه از آموزش های پروژه محور پایتون را با وارد کردن پکیج Tkinter و با تعریف متغیرهای ویجت‌هایی که در بالا صحبتشان را کردیم، آغاز می‌کنم. اگر برای اولین بار از پکیج Tkinter استفاده می‌کنید، نیازی به نصب آن با دستور pip ندارید. زیرا این پکیج از قبل در محیط مجازی پایتون نصب شده است. حالا بیایید کدنویسی را شروع کنیم:

				
					import tkinter as tk
window = tk.Tk()
window.title("Thecleverprogrammer")

window.rowconfigure(0, minsize=800, weight=1)
window.columnconfigure(1, minsize=800, weight=1)

txt_edit = tk.Text(window)
fr_buttons = tk.Frame(window)
btn_open = tk.Button(fr_buttons, text='Open')
btn_save = tk.Button(fr_buttons, text="Save As")
				
			

حالا بیایید روی layout ویرایشگر متن خود کار کنیم. ابتدا باید دکمه‌ها را به frame اختصاص دهیم:

				
					
btn_open.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
btn_save.grid(row=1, column=0, sticky="ew", padx=5)
				
			

از آن‌جایی که دکمه‌ها را به frame ویرایشگر متن خود اختصاص داده‌ایم، اکنون باید یک grid layout برای پنجره اصلی خود تنظیم کنیم:

				
					fr_buttons.grid(row=0, column=0, sticky="ns")
txt_edit.grid(row=0, column=1, sticky="nsew")
				
			

اکنون اگر کد را با استفاده از تابع window.mainloop() اجرا کنید، layout رابط کاربری گرافیکی ویرایشگر متن ما نمایش داده می‌شود:

layout رابط کاربری گرافیکی ویرایشگر متن

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

تابع Open file

				
					def open_file():
    """Open a file for editing."""
    filepath = askopenfilename(
        filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")]
    )
    if not filepath:
        return
    txt_edit.delete("1.0", tk.END)
    with open(filepath, "r") as input_file:
        text = input_file.read()
        txt_edit.insert(tk.END, text)
    window.title(f"Thecleverprogrammer - {filepath}")
				
			

تابع Save file

				
					def save_file():
    """Save the current file as a new file."""
    filepath = asksaveasfilename(
        defaultextension="txt",
        filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")],
    )
    if not filepath:
        return
    with open(filepath, "w") as output_file:
        text = txt_edit.get("1.0", tk.END)
        output_file.write(text)
    window.title(f"Thecleverprogrammer - {filepath}")
				
			

تابع بالا به ما کمک می‌کند تا با رابط کاربری گرافیکی، ویرایشگر متن خودمان را درک کنیم. شما می‌توانید این تابع را مطابق با تسک‌های مورد نظر خود تغییر دهید. حالا بیایید ببینیم کد کامل ما چگونه خواهد بود:

				
					import tkinter as tk
from tkinter.filedialog import askopenfilename, asksaveasfilename

def open_file():
    """Open a file for editing."""
    filepath = askopenfilename(
        filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")]
    )
    if not filepath:
        return
    txt_edit.delete(1.0, tk.END)
    with open(filepath, "r") as input_file:
        text = input_file.read()
        txt_edit.insert(tk.END, text)
    window.title(f"Thecleverprogrammer - {filepath}")

def save_file():
    """Save the current file as a new file."""
    filepath = asksaveasfilename(
        defaultextension="txt",
        filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")],
    )
    if not filepath:
        return
    with open(filepath, "w") as output_file:
        text = txt_edit.get(1.0, tk.END)
        output_file.write(text)
    window.title(f"Thecleverprogrammer - {filepath}")

window = tk.Tk()
window.title("Thecleverprogrammer")
window.rowconfigure(0, minsize=800, weight=1)
window.columnconfigure(1, minsize=800, weight=1)

txt_edit = tk.Text(window)
fr_buttons = tk.Frame(window, relief=tk.RAISED, bd=2)
btn_open = tk.Button(fr_buttons, text="Open", command=open_file)
btn_save = tk.Button(fr_buttons, text="Save As...", command=save_file)

btn_open.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
btn_save.grid(row=1, column=0, sticky="ew", padx=5)

fr_buttons.grid(row=0, column=0, sticky="ns")
txt_edit.grid(row=0, column=1, sticky="nsew")

window.mainloop()
				
			

آموزش پروژه محور پایتون: ساخت فیلترهای اینستاگرام

حتی اگر یک بار در زندگی خود از اینستاگرام استفاده کرده باشید، حتماً متوجه این موضوع شده‌اید که در هنگام آپلود تصویر، می‌توانید از فیلترهای متنوعی استفاده کنید. این فیلترها برای بهبود کیفیت تصویر طراحی شده‌اند. آن‌ها نمونه‌ای از الگوریتم‌های پیچیده یادگیری ماشین هستند که در برای ارائه سرویس به اینستاگرام ساخته شده‌اند. بنابراین، اگر این فیلترها توسط یادگیری ماشین ایجاد شده‌اند، به این معنی است که می‌توانیم فیلترهای اینستاگرام را با پایتون نیز ایجاد کنیم.

در این آموزش پروژه محور پایتون، نحوه ایجاد فیترهای زیبای اینستاگرام را با استفاده ازیادگیری ماشین به شما یاد می‌دهم. بهترین بخش کار این است که ما از پایتون استفاده می‌کنیم، و بزرگترین مزیت استفاده از چنین زبان محبوبی این است که تقریباً برای هر کار، پکیج‌هایی در آن وجود دارد.

ساخت فیلترهای اینستاگرام با پایتون چگونه ممکن است؟

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

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

با استفاده از دستور pip ، به راحتی می‌توانید این کتابخانه را نصب کنید. امیدوارم هنگام نصب این کتابخانه، با ارور مواجه نشوید.

				
					pip install instafilter
				
			

کتابخانه دیگری که برای ایجاد فیلترهای اینستاگرام به آن نیاز داریم، Open Source Computer Vision Library of Python است که به آن OpenCV هم می‌گویند. اگر هرگز با OpenCV کار نکرده‌اید، می‌توانید آن را به راحتی و با استفاده از دستور pip نصب کنید.

				
					pip install opencv-python
				
			

برای استفاده از OpenCV ، آن را با نام cv2 (import cv2) وارد می‌کنیم. حالا بیایید در این آموزش پروژه محور پایتون، به ساخت فیلترهای اینستاگرام بپردازیم:

				
					from instafilter import Instafilter

model = Instafilter("Lo-fi")
new_image = model("image.jpg")

# To save the image, use cv2
import cv2
cv2.imwrite("modified_image.jpg", new_image)
				
			

تصاویر ذخیره شده شما به این صورت خواهند بود:

آموزش پروژه محور پایتون: ساخت فیلترهای اینستاگرام

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

در این آموزش پروژه محور پایتون، با چندین پروژه جذاب آشنا شدید. اگر دستتان گرم شده و می‌خواهید پروژه های حرفه‌ای‌تر را هم امتحان کنید، این مطالب را از دست ندهید:

{{ reviewsTotal }}{{ options.labels.singularReviewCountLabel }}
{{ reviewsTotal }}{{ options.labels.pluralReviewCountLabel }}
{{ options.labels.newReviewButton }}
{{ userData.canReview.message }}
هوش مصنوعی GPT
X