خانه هوش مصنوعی آشنایی با Scrapy هوش مصنوعی علم داده نوشته شده توسط: میثم عقیلی تاریخ انتشار: ۲۴ فروردین ۱۳۹۹ آخرین بروزرسانی: 17 تیر 1403 زمان مطالعه: 14 دقیقه ۴.۵ (۲) مقدمه به استخراج اطلاعات از وب با ایجاد الگو و روشی خودکار را Web Crawling میگویند. برای استفاده از این روش که حجم زیادی از اطلاعات را با سرعت مناسب برای ما فراهم میکند ,ابزارهای مختلفی در زبانهای برنامه نویسی گوناگون وجود دارد مانند: • Scrapy • Beautiful Soap • GRUB • Selenium Scrapy Scrapy یکی از محبوبترین و سادهترین ابزارهای Web Crawling در زبان Python میباشد که: Open Source رایگان Cross-Platform سرعت زیاد نسبت به دیگر Crawlerها Scrapy با ایجاد Request به وبسایتها اطلاعات صفحات مختلف را جمع آوری میکند که میتوان آنرا در قالب فایل CSV,Json,Xml,.. و یا در دیتابیسهای SQL Server,MongoDB,MySql,… ذخیره کرد. در این مطلب به استخراج اطلاعات مناسبتهای سال جاری از سایت time.ir میپردازیم. مرحله ۱: نصب Scrapy در cmd pip install scrapy در ادامه با ایجاد یک پروژه کار خود را آغاز میکنیم. scrapy startproject <Project Name> scrapy startproject Nikamooz cd <Project Name> Example cd Nikamooz Scrapy genspider <Spider Name> <Url> scrapy genspider time_ir https://time.ir Spider یک class در پروژه میباشد که ما با دستوراتی که درآن مینویسیم راه و روش استخراج و ذخیره اطلاعات مورد نیاز خود را تعیین میکنیم. با ایجاد Spider ازطریق کد بالا در پوشه Spiders فایلی با نام Spiderای که وجود دارد. در مسیری که پروژه شما ایجاد شده است تعدادی فایل با فرمت .py وجود دارد که آنهارا مورد بررسی قرار میدهیم. Items.py: برای ایجاد فیلد یا ستونی برای ذخیره اطلاعات Middlewares.py: اضافه کردن Proxy به پروژه و یا تغییر اطلاعاتی که در حال ذخیره آنها هستیم. Piplines.py: برای ذخیره اطلاعات به دست آمده در دیتابیسهای مختلف مانند SQL Server , MySQL MongoDB , .. Settings.py: تنظیمات مربوط به پروژه شما برای مثال فعال کردنpiplines و middlewares و یا تنظیم User Agent Scrapy اطلاعات درون کدهای Html هر page که در Page Source آن قابل مشاهده است را ذخیره میکند در این پروژه برای این که بتوانیم تمام مناسبتهای امسال را به دست بیاوریم باید بر روی دکمه ماه قبل یا بعد با استفاده از کدهای scrapy کلیلک کرده تا اطلاعات هر ماه هر بار بارگذاری شود تا بتوان آنها را به دست آورد .از طرفی در سایت time.ir با کلیک روی ماه قبل یا بعد اطلاعات جدید در کد Html قابل مشاهده نیست و فقط یک Response میباشد که با inspect میتوان اطلاعات بارگذاری شده را دید.به این نوع صفحات JavaScript Pages میگویند که با Scrapy به تنهایی نمیتوان اطلاعات این صفحات را به دست آورد. برای این کار میتوان از Scrapy-Splash استفاده کرد. مرحله ۲: نصب و راه اندازی Scrapy-Splash pip install scrapy-splash در فایل Settings.py کدهای زیر را جهت فعال کردن و تنظیمات Splash اضافه میکنیم #js readable-------------------------------------------------------------------- SPLASH_URL='http://127.0.0.1:8050' DOWNLOADER_MIDDLEWARES = { 'scrapy_splash.SplashCookiesMiddleware': 723, 'scrapy_splash.SplashMiddleware': 725, 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810, } SPIDER_MIDDLEWARES={ 'scrapy_splash.SplashDeduplicateArgsMiddleware':100, } DUPEFILTER_CLASS='scrapy_splash.SplashAwareDupeFilter' HTTPCACHE_STORAGE='scrapy_splash.SplashAwareFSCacheStorage' #---------------------------------------------------------------------------- همچنین Splash نیاز به یک Instance دارد که میتوان آنرا از طریق Docker دانلود و استفاده کرد.برای دانلود از کد زیر استفاده کنید. docker pull scrapinghub/splash بعد از دانلود با دستور زیر image دانلود شده را درip 127.0.0.1 و port 8050 میتوان اجرا کرد. docker run -p 8050:8050 scrapinghub/splash در خط آخر خروجی میتوانید نتیجه را ببینید.برای ادامه کار cmd دیگری را اجرا کنید. ۲۰۱۹-۱۲-۱۶ ۱۶:۴۱:۰۶.۱۴۴۰۹۷ [-] Server listening on http://0.0.0.0:8050 مرحله ۳: تاریخ و مناسبت اطلاعاتی هستند که نیاز داریم پس در فایل items.py برای هر کدام فیلدی ایجاد میکنیم. Date=scrapy.Field() Title=scrapy.Field() مرحله ۴: سپس برای ذخیره اطلاعات در دیتابیس SQL Server میتوان در فایل piplines.py تغییرات زیر را انجام داد. # -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html import pyodbc class NikamoozPipeline(object): def __init__(self): self.create_con() self.create_table() def create_con(self): try: self.con= pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER=MEYSAM_LAP\MEYSAM;DATABASE=temp;UID=sa;PWD=Sh!@#123') self.cur=self.con.cursor() except pyodbc.Error as e: print (e) def create_table(self): self.cur.execute("""drop table if exists time_tb""") self.cur.execute("""create table time_tb( [Date] nvarchar(100), Title nvarchar(100) ) """) def process_item(self,item,spider): self.store_db(item) print("--------------Stored---------------") return item def store_db(self,item): self.cur.execute("""insert into time_tb values(?,?)""",(item['Date'],item['Title'])) self.con.commit() def close_spider(self, spider): self.con.close() سپس برای اینکه بتوانید از piplines.pyاستفاده کنید باید در فایل settings.py کدهای زیر را از حالت comment خارج کنید. ITEM_PIPELINES = { ‘Nikamooz.pipelines.NikamoozPipeline’: ۳۰۰, } مرحله ۵: شروع کد نویسی در Spider در فایل time_ir.py با ایجاد تابع start_requests() میتوان با ارسال SplashRequest به سایت time.ir کدهای Html و اطلاعات مورد نیاز صفحه اول که مربوط به ماه جاری است را دریافت کرد و آن را به سمت تابع parse() فرستاد.درون script_thism یک تابع به زبان برنامه نویسی lua میباشد که Splash را تبدیل به یک Browser میکند و میتوانیم یک url به تابع به عنوان ورودی بدهیم تا یک button را کلیک کند و منتظر شود تا اطلاعات load شوند و خروجی Html آنرا دریافت کنیم. برای استفاده از این تابع باید آنرا در SplashRequest خود به صورت زیر بیاوریم و endpoint را برابر execute قراردهیم. # -*- coding: utf-8 -*- import scrapy import time from scrapy_splash import SplashRequest class TimeIrSpider(scrapy.Spider): name = 'time_ir' start_urls = ["https://time.ir"] def start_requests(self): script_thism = """ function main(splash) splash.private_mode_enabled=false local url = splash.args.url assert(splash:go(url)) assert(splash:wait(2)) return { html = splash:html() } end """ url='https://time.ir' yield SplashRequest(url, self.parse, meta={ 'splash': { 'args': {'lua_source': script_thism}, 'endpoint': 'execute', } }) قبل از این که کار خود را با استخراج اطلاعات از خروجی SplashRequest در تابع Parse شروع کنیم باید با Css Selector آشنا شویم. برای مشخص کردن و پیدا کردن اطلاعات مورد نیاز, باید به Scrapy با استفاده از Css Selector و XPath آدرس اطلاعات را بدهیم. برای پیداکردن این آدرس میتوان از ابزاری به نام Selector Gadget کمک گرفت . (https://chrome.google.com/webstore/detail/selectorgadget/mhjhnkcfbdhnjickkkdbjoemdmbfginb?hl=en) پس از دانلود آن به صورت زیر عمل میکنیم.در scrapy به صورت زیر میتوان عمل کرد. m=response.css(.list-unstyled span::text).extract() با اینکار در کد Html و element مربوطه را پیدا میکنیم و اطلاعات آنرا به صورت یک list در m ذخیره میکنیم. به پروژه خود کد زیر را اضافه میکنیم تا بتوانیم از فیلدهایی که در items.py ایجاد کردیم استفاده کنیم. from ..items import NikamoozItem در تابع parse ابتدا با ایجاد NikamoozItem () فیلدهای خود را فراخوانی میکنیم سپس با استفاده از css selector مناسب برای اطلاعات تاریخ و مناسبت آن اطلاعات را به صورت یک list استخراج میکنیم.درادامه فرایند مرتب سازی دیتا را انجام میدهیم. در لیست تاریخ اطلاعاتی همچون [۲۵ December] و یا رکوردهای empty وجود دارد که باید آنها را حذف کنیم. در آخر اطلاعات را در دو list جدا ذخیره میکنیم و با یک حلقه هر بار یک رکورد را در فیلد مربوط به خود ریخته و آنها را با استفاده از Yield به سمت دیتابیس میفرستیم.هربار که Yield اجرا میشود Scrapy فایل piplines را اجرا میکند. def parse(self,response): items=NikamoozItem() m=response.css('.list-unstyled li::text').extract() m2=response.css('.list-unstyled span::text').extract() y=0 x=0 z=0 r=[] t=[] for i in range(0,len(m)): if m[y].strip()!='': r.append(m[y].strip()) y=y+1 for j in range(0,len(m2)): if m2[z].strip()!='' and '[' not in m2[z]: t.append(m2[z].strip()) z=z+1 for o in range(0,len(t)): b=t[x].strip() a=r[x].strip() items['Date']=b items['Title']=a x=x+1 yield items با ایجاد یک request جدید به سایت اطلاعات ماه قبل را استخراج میکنیم for o in range(0,len(t)): b=t[x].strip() a=r[x].strip() items['Date']=b items['Title']=a x=x+1 yield items url='https://time.ir' script_pre1 = """ function main(splash) splash.private_mode_enabled=false local url = splash.args.url assert(splash:go(url)) assert(splash:wait(2)) assert(splash:runjs("$('#ctl00_cphTop_Sampa_Web_View_EventUI_EventCalendarSimple30cphTop_3732_ecEventCalendar_pnlPrevious').click()")) assert(splash:wait(2)) -- return result as a JSON object return { html = splash:html() } end """ yield SplashRequest(url, self.parse, meta={ 'splash': { 'args': {'lua_source': script_pre1}, 'endpoint': 'execute', } }) در ادامه تابع parse تابع script_pre1 با کلیک روی button ماه قبل با id آن کدهای Html را دوباره به تابع parse جهت مرتب سازی و ذخیره اطلاعات جدید میفرستد. هم چنین برای دو ماه قبل باید دو بار button ماه قبل را کلیلک کنیم که به صورت زیر میباشد script_pre2 = """ function main(splash) splash.private_mode_enabled=false local url = splash.args.url assert(splash:go(url)) assert(splash:wait(2)) assert(splash:runjs("$('#ctl00_cphTop_Sampa_Web_View_EventUI_EventCalendarSimple30cphTop_3732_ecEventCalendar_pnlPrevious').click()")) assert(splash:wait(2)) assert(splash:runjs("$('#ctl00_cphTop_Sampa_Web_View_EventUI_EventCalendarSimple30cphTop_3732_ecEventCalendar_pnlPrevious').click()")) assert(splash:wait(2)) -- return result as a JSON object return { html = splash:html() } end """ yield SplashRequest(url, self.parse, meta={ 'splash': { 'args': {'lua_source': script_pre2}, 'endpoint': 'execute', } }) تابع runjs() button ای که id آن به عنوان ورودی داده شده است را کلیک میکند و با اضافه کردن wait(2) زمان کافی برای بارگذاری اطلاعات جدید را فراهم میکنیم.به همین صورت برای هر ماه دلخواه باید request آنرا فرستاد. مرحله ۶: در آخر برای اجرای پروژه و به دست آوردن اطلاعات در cmd به صورت زیر عمل میکنیم. توجه داشته باشید که مرحله ۲ را در cmd دیگری اجرا کرده باشید. cd <Project Address> scrapy crawl <Spider Name> example scrapy crawl time_ir میتوانید خروجی حاصل را در دیتابیس خود ببینید و یا مانند زیر آنرا در قالب یک فایل csv ذخیره کنید. scrapy crawl <Spider Name> -o <File Name>.csv scrapy crawl time_ir myfile.csv (or .json /.xml) فایل شما در مسیر پروژه شما قرار میگیرد. نتیجه به صورت زیر خواهد بود. SQL Server به دلیل ساختار منحصر به فرد سایت time.ir پروژه ما با lua_Script برای کلیک بر روی buttonها و گرفتن خروجی JavaScriptای و SplashRequest برای خواندن خروجی به نتیجه رسید ولی درحالت ساده تر میتوان از کد زیر فقط برای ذخیره اطلاعات صفحه نخست که اطلاعات ماه جاری است استفاده کرد. یعنی نیازی به نوشتن Splash Settings در فایل Settings.pyو اجرا کردن نسخه docker , instance splash نیست. # -*- coding: utf-8 -*- import scrapy from ..items import NikamoozItem class TimeIrSpider(scrapy.Spider): name = 'time_ir' start_urls = ["https://time.ir"] def parse(self,response): items=NikamoozItem() m=response.css('.list-unstyled li::text').extract() m2=response.css('.list-unstyled span::text').extract() y=0 x=0 z=0 r=[] t=[] for i in range(0,len(m)): if m[y].strip()!='': r.append(m[y].strip()) y=y+1 for j in range(0,len(m2)): if m2[z].strip()!='' and '[' not in m2[z]: t.append(m2[z].strip()) z=z+1 for o in range(0,len(t)): b=t[x].strip() a=r[x].strip() items['Date']=b items['Title']=a x=x+1 yield items چه رتبه ای میدهید؟ میانگین ۴.۵ / ۵. از مجموع ۲ اولین نفر باش معرفی نویسنده مقالات 1 مقاله توسط این نویسنده محصولات 0 دوره توسط این نویسنده میثم عقیلی معرفی محصول دوره یادگیری علم داده 1.780.000 تومان 1.068.000 تومان مقالات مرتبط ۰۳ آبان هوش مصنوعی راهنمای کاربردی اصطلاحات هوش مصنوعی تیم فنی نیک آموز ۰۱ آبان هوش مصنوعی ساخت پایپ لاین RAG در یک قدم بسیار ساده + نمونه کد واقعی نگین فاتحی ۰۴ مهر هوش مصنوعی پارادایم های RAG در مدل های زبانی بزرگ تیم فنی نیک آموز ۲۰ شهریور هوش مصنوعی نحوه ساخت RAG های کارآمد با Query Routing نگین فاتحی دیدگاه کاربران لغو پاسخ دیدگاه نام و نام خانوادگی ایمیل ذخیره نام، ایمیل و وبسایت من در مرورگر برای زمانی که دوباره دیدگاهی مینویسم. موبایل برای اطلاع از پاسخ لطفاً مرا با خبر کن ثبت دیدگاه Δ