ورود به دنیای وب اسکرپینگ قسمت اول

6 ديدگاه

وب اسکرپینگ با پایتون

خب با یه مقاله جذاب و همراه با پروژه دیگ ای در خدمت دوستان هستیم

تو این مقاله قصد داریم راجب Web Scraping صحبت کنیم. پس همراه ما باشید.

Web Scraping دقیقا چیه؟

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

Web Scraping به چه دردی میخوره؟

ببینید ممکنه شما بخواید برنامه ای بنویسید که مثلا بیاد قیمت یه سری از اجناس تو یه سایت های مختلف و یا یه سایت رو بررسی و مقایسه کنه. خب در مرحله اول شما نیاز دارید اول اون اطلاعات رو از سایت ها بیرون بکشید. خب اینجا نیاز به Web Scraping احساس میشه. یه چندتا مثال دیگ بزنیم.. شما مثلا در قسمتی از برنامتون نیاز دارید ایمیل هایی که تو یه سایت یا چندتا سایت هست رو بیرون بکشید، یا مثلا ترند های توییتر رو جمع آوری کنید، یا مثلا برنامه تحلیلی روی داده هایی مثل دما و… داشته باشید، یا مثلا لیست شغل هایی که تو سایت های استخدام هست رو بخواید و… . پس دیدیم چه قدر مواردی هست که ما نیاز داریم که عمل Web Scraping رو انجام بدیم.

Web Scraping آیا قانونی است؟

ممکنه فکر کنید که صاحبان سایت ها از این کار بدشون میاد و… . البته ما دو بحث اینجا داریم. یکی Web Scraping و یکی Web crawling که این دو مبحث تفاوت هایی با هم دارند و بعضی سایت ها از ورود بات و.. به سایت به روش های مختلفی جلوگیری میکنند. راجب این مباحث میتونید وارد این لینک بشید.

Web Scraping چه ماژول ها و متدی داره؟

این یکی از ماژول های نصب شده پایتون هست که برای درخواست به url ها به کار میره.

from urllib.request import urlopen
html=urlopen("http://pythons.ir")
print(html.read())
  • Requests:

این ماژول برای ارسال درخواست های از نوع HTTP/1.1 به کار میره و شباهت هایی به urllib2 داره. این ماژول کار با دیتا های ارسالی و دریافتی رو ساده تر کرده و کار باهاش ساده تر هست. که ما با این ماژول کار خواهیم کرد. برای مشاهده مقایسه های این ماژول و ماژول قبلی میتونید به این لینک سر بزنید. همچنین ما تو سایت یه پست برای این ماژول قرار دادیم. میتونید سربزنید و مطالعه کنید.

این کتابخونه برای پارس کردن و بیرون کشیدن دیتاهای Html و XML هست. این ماژول بصورت خودکار دیتا هارو به صورت UTF-8 خروجی میده.  این ماژول رو میتونید با دستور زیر نصب کنید:

Pip install bs4

ما با این کتابخونه هم کار خواهیم کرد پس اینجا فعلا مثالی نمیزنیم.

  • LXml:

این یک کتابخونه بسیار پر سرعت برای تولید کد های html و xml هست. این کتابخونه متد های متنوعی برای این کار تدارک دیده باهم یه مثالو میبینیم:

root=et.Element('html',version="5.0") #Pass the parent node,name of the child node
et.subElement(root,'head')
et.subElement(root,'title',bgcolor="read",fontsize='22")
et.subElement(root,'body',fontsize="15")
print(et.tostring(root,pretty_print=True).decode("utf-8")

این هم از خروجی:

الان اینجا اومدیم یه کد نوشتیم وخروجی کد بصورت یک کد html مرتب شده درومد. این کتابخونه هم کارایی بخصوص خودشو داره.

برای دیدن متدها مثال هایی از این کتابخونه میتونید به این لینک سربزنید.

این کتابخونه مشهور درواقع یک مرورگر اتوماتیک است. جالبه بدونید که استفاده از مرورگر برای استخراج داده ها بشدت سرعت رو کاهش میده. خب پس چرا selenium؟ زمانی ما مجبور به استفاده از این کتابخونه میشیم، که دیتا های سایت ما بصورت javascript باشن. یعنی توی DOM مرورگر ران بشه. برای مثال اینستاگرام که عکس ها با اسکرول کردن لود میشن. خب اینجا ها ما دیگ مجبور میشیم از selenium استفاده کنیم. الان سایت ها دارن میرن سمت اینکه بیشتر روی جاوااسکریپت پیاده سازی کنند (یه دلیل میتونه این باشه که تا حد ممکن جلو ورود خزنده های وب رو به سایت هاشون بگیرن. البته نه همه سایت ها). این کتابخونه رو باید نصب کنید با دستور زیر:

pip install selenium

این هم یک نمونه کد برای کارایی selenium:

from selenium import webdriver
#path for chromedriver
path_to_chromdriver='/Users/Admin/Desktop/chromdriver'
browser=webdriver.chrome(executable path=path_to_chromedriver)
url='pythons.ir'
browser.get(url)

الان اینجا اومدیم از selenium یه webdriver رو import کردیم و بعدش آدرس مروگر کروم رو از سیستم بهش دادیم و در نهایت آدرس پیج هدف رو بهش دادیم. برای دیدن کد های بیشتر و متد های این کتابخونه به لینک عنوان مراجعه کنید.

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

 pip install scrapy
import scrapy
 class GeeksSpider(scrapy.spider)
  name="geeks_spider"
   start_urls=['http://www.pythons.ir']
 #parse function
  def parse(self.response)
   SET_SELECTOR='geeks'
    for geek in response.css(SET_SELECTOR):
  pass

الان توی این کد ما اومدیم یه خزنده خودمون رو نوشتیم که با یه کلاس شروع شده. و این کلاس شامل یه متغیر name و آدرس url شروع برای خزیدن، و بعدش یع تابع parse برای پارس کردن هر درخواست request. این فریم ورک کاربرد خوبی برای ساخت خزنده های وب داره که حتما به داکیومنت های لینکی که تو عنوان اشاره شده سربزنید.

 

یه نکته برای دوستانی که میخوان تو این زمینه فعالیت کنن. ببینید دوستان چون شما نهایتا با یه سری اعداد یا یه سری رشته سروکار دارید پس باید متدها و نحوه کار با string ها و لیست ها و دیکشنری هارو بدونید و باهاشون تمرین های لازم رو کرده باشید. تو اکثر پروژه ها ما به یه سری لیست از رشته ها و اعداد سروکار داریم و باید بتونیم خوب مرتب کنید.

نکته دیگ ای که اینجا مطرح هست اینه که ما اغلب یه سری اطلاعاتی رو میخوایم از دل یه متن بیرون بکشیم که آرایش خاصی دارن. مثلا ایمیل ها، به فرض ما میخوایم آدرس قبل حرف @ رو بیرون بکشیم. خب اینجا باید چیکار کنیم؟ بخوام واضح تر بیان کنم صورت مسئله اینه که ما بعد از اینکه کل صورت ایمیل هارو بیرون کشیدیم از سایت، حالا چطوری آدرس قبل از حرف @ رو جدا کنیم؟

فرض کنید اینارو بیرون کشیدیم:

aaaaa@gmail.com
asd21w@gmail.com
asdAw@gmail.com

حالا باید چیجوری قبل @ رو بیرون بکشیم از این متن ها؟ پاسخ تو مبحث regex هاست. پس به مروری روی این موضوع بکنیم.

  • Regex:

رجکس ها یا همون Regular Expression، یه سری عبارات با قاعده ای هستن که کمک میکنه تا ما دنبال یه سری چیز خاص توی متن بگردیم. این قاعده رو ما بهش میدیم تا اون چیز خاص رو بفهمه چیه. مثلا برای اینکه اعداد این متن رو خارج کنیم:

.Pythons.ir is the one of 100 sites for learning pythons. This site has 200 contents for python

خب برای اینکه اعداد ۱۰۰ و ۲۰۰ رو بیرون بکشیم باید چه کنیم؟

Regex ما این میشه:

[۹-۰]

یعنی اعداد ۰ تا ۹ رو بده. خروجی میشه ۱و۰و۰و۲و۰و۰

برای مطالعه بهتر و کامل تر regex ها به این لینک مراجعه کنید.

الان دیگ آماده شدیم برای نمونه پروژه. پس بریم سروقتش:

  • صورت پروژه:

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

حالا ما تو این پروژه کوچک میخوایم از قسمت وبلاگ سایت pythons.ir اسامی مقاله ها و همچنین اسامی نویسنده هاشو بیرون بکشیم و در اخر توی یک اکسل چاپ کنیم. یعنی در آخر خروجی ما اینجوری میشه:

import requests
from bs4 import BeautifulSoup
from openpyxl import Workbook
workbook = Workbook()
sheet = workbook.active
article_title=[]
article_author=[]
  for j in range(1,3):
      mohtava=requests.get("https://pythons.ir/blog/page/{}/".format(j))
    mohtava=mohtava.content
      soup=BeautifulSoup(mohtava,'html.parser')
       soup1=soup.findAll('h4',attrs={'class':'entry-title-detail'})
       soup2=soup.findAll('span',attrs={'class':'entry-author'})
       for i in range(0,len(soup1)):
         article_title.append(soup1[i].text)
         article_author.append(soup2[i].text)
     print("page{} : ".format(j),article_title)
cnt=0
   for i in range(0,len(article_author)):
    cnt+=1
     sheet["A{}".format(cnt)] = article_title[i]
     sheet["B{}".format(cnt)] = article_author[i]
workbook.save(filename="articles.xlsx")

خب اگه بخوایم خط به خط کد رو توضیح بدیم:

import requests

تو این خط اومدیم کتابخونه request رو import کردیم. چون برای ارسال درخواست  به آدرس سایت میخوایم از این کتابخونه استفاده کنیم.

from bs4 import BeautifulSoup

برای استفاده از Beautifulsoup باید از کتابخونه bs4 این رو import کنیم.

from openpyxl import Workbook

برای اینکه بخوایم کد خروجی رو در اکسل چاپ کنیم باید از openpyxl بخش workbook رو import کنیم.

workbook = Workbook()
sheet = workbook.active

حالا برای اینکه بخوایم با این کتابخونه کار کنیم اول نیازه یه فایل ایجاد کنیم. برای ایجاد فایل لازمه یه شی بسازیم. تابع ساخت شی اکسل در این کتابخونه ()Workbook هست. این تابع میاد یه فایل اکسل درست میکنه و پیش فرض یک صفحه(sheet) بهش اضافه میکنه. پس دیگ لازم نیست یک sheet دیگ بسازیم. خب این آبجکت یه سری property های مختلفی داره. ما میایم تو خط بعدی با property .active اون sheet رو که ایجاد کرده تابع سازنده، میدیم به متغیر sheet. این sheet پیش فرض که ایجاد شده بود شماره ۰ رو داره و اگه شما بخواید عوض کنید باید جداگونه تعریف کنید. که ما اینجا با همین sheet0 کار میکنیم.

  for j in range(1,2):
     mohtava=requests.get("https://pythons.ir/blog/page/{}/".format(j)

اینجارو دقت کنید چون آدرس pythons.ir/blog/page=… صفحه های مختلفی داره واسه همین برای اینکه ما بتونیم تا اخرین صفحه رو دیتاهارو بگیریم واسه همین تو یه حلقه گذاشتیم و تا صفحه ۱۰ حلقه رو گذاشتیم.

mohtava=mohtava.content

این mohtava که خروجی درخواست ما هست property های مختلفی داره مثلا status که نشون میده که درخواست ما موفقیت آمیز بوده یا سرور مشکل داشته یا چیز های دیگ. برای مثال اگه درخواست get موفقیت آمیز ارسال شده باشه شما اگه mohtava.status رو چاپ کنید میبنید که باید ۲۰۰ رو نشون بده که یعنی موفقیت آمیز بوده. خب شما با این property ها میتونید عمل error handler رو انجام بدید و مشخص کنید که خطا از سمت client بوده یا server.

 یکی از این propertyها content هست که نشون میده محتوای خروجی درخواستمون چی بوده. یعنی همون کل کد صفحه. الان شما بیاید همین mohtava رو print کنید میبینید که کل کد صفحه رو مینویسه. پس الان نوبت به این میرسه که توی این کد ها دنبال تگ ها و قسمت های دلخواهمون بگردیم.

soup=BeautifulSoup(mohtava,'html.parser')

حالا میایم با تابع Beautifulsoup یه شی درست میکنیم از همون خروجی request بالا. بعد میگیم بهش که بصورت html باید پارس بشه. الان این کار باعث میشه که قابلیت ها و توابع Beautifulsoup برای ما ایجاد بشه.

soup1=soup.findAll('h4',attrs={'class':'entry-title-detail')}

برای اینکه دقیقا بقهمیم این کد چی هست باید بریم کد صفحه رو بخونیم. کدوم صفحه؟ همون صفحه ای که request زدیم. یعنی https://pythons.ir/blog/page/1 برای صفحه اول. برای این کار اول وارد پیچ میشیم. بعدش روی پیج کلیک راست و بعدش گزینه inspect رو میزنیم و حالا با موس رو هر کجای صفحه بیاریم کد html اون قسمت رو مشخص میکنه. مثل این عنوان مقاله اول :

که اینجا ما میبینیم که عنوان توی یه تگ h4 با کلاس entry-title-detail هست. خب پس ما میایم تو هر صفحه مثلا اینجا صفحه اول یعنی https://pythons.ir/blog/page/1  کل این تگ های h4 که کلاس entry-title-detail رو پیدا میکنیم واسه همین از تابع soup.finaAll استفاده کردیم. خروجی این قسمت یک آرایه هست از تمام این تگ ها در صفحه. یعنی مثلا اگه توی صفحه اول ۱۰ تا مقاله هست پس یعنی ۱۰ تا تگ h4 که کلاس entry-title-detail هستند، هست. پس یه آرایه هست که ۱۰ تا عنصر داره و هر عنصر یه عنوان مقاله هست. خب پس تا الان یه soup1 داریم که آرایه ای از عنوان مقاله های صفحه اوله.

 soup2=soup.findAll('span',attrs={'class':'entry-author')}

خب فک کنم دیگ بتونید حدس بزنید که این برای اسم نویسنده هاست. میبینید که اغلب برای کلاس های کد های html یک اسم مربوط استفاده میکنند. برای اسم نویسنده ها هم همون کار بالارو انجام میدیم و به این میرسیم که اسم نویسنده ها تو هر صفحه توی یک span با کلاس entry-author هستند. پس الان soup2 هم شد یه آرایه از اسم نویسنده ها.

   for i in range(0,len(soup1)):
         article_title.append(soup1[i].text)
         article_author.append(soup2[i].text)
     print("page{} : ".format(j),article_title)

خب دقت کنید که الان شما همین soup1 و ۲ رو print کنید میبینید که یه سری کد هم همراشون هست یعنی خیلی تمیز نمیاد اسم مقاله و اسم نویسنده هارو چاپ کنه. برای همین این soup یه متد به اسم text داره که میاد دقیقا چیزی که بین تگ ها نوشته شده رو چاپ میکنه. حالا توی این قسمت از کد چون ما با آرایه soup کار داریم توی یه حلقه اومدیم به تعداد هر آبجکت آرایه soup، اسم نویسنده رو توی آرایه ای به اسم article_author و اسم مقاله رو توی آرایه ای به اسم article_title اپند کردیم. بعدش چاپ کردیم.

دقت میکنید که تمام این کد ها توی حلقه for بالایی بودن یعنی برای هر صفحه ۱ تا ۱۰ این کار ها انجام شد و در اخر آرایه ی article_author و آرایه ی article_title شامل اسم کل مقاله ها و اسم نویسنده ها هستن. حالا وقتشه توی دو ستون در اکسل ذخیره کنیم.

cnt=0
   for i in range(0,len(article_author)):
       for j in range(0,len(article_author[i])):
        cnt+=1
         sheet["A{}".format(cnt)] = article_title[i][j]
         sheet["B{}".format(cnt)] = article_author[i][j]
  workbook.save(filename="hello_world.xlsx")

برای این کار میایم تو یه حلقه مثل کد بالا میریزیم. این قسمت از کد تقریبا واضح هست که داریم چیکار میکینم. برای توضیح تکمیلی sheet[“A1”] و همینجوری به ترتیب … یعنی ستون A در ردیف ۱ و همینجوری ردیف ۲ و…

همچنین sheet[“B1”] و… یعنی ستون B و ردیف ۱ و…

اکسل رو اگه نگاه بندازیم بهتر متوجه میشیم.

خب این هم از خروجی مطلبوب:

این هم از استخراج داده ها از سایت…

برای مطلب آخر لازمه بگم این کاری که کردیم با html بود و اگه سایت کاملا javascript باشه دیگ نمیتونیم اینطوری کار کنیم. مثل سایت اینستاگرام یا دیجیتون و.. اونجا دیگ باید بریم سراغ سلنیوم و متدهای اون.

برای مشاهده قسمت دوم ورود به دنیای وب اسکرپینگ با پایتون  کلیک کنید

6 ديدگاه

  1. 1398-12-22

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

    • 1399-02-19

      خیلی مچکر از شما. این مباحث رو ان شالله با قدرت و مباحث جذاب تری ادامه میدیم.

  2. 1399-02-17

    خیلی سایت خوب و کاربردی دارید و برا منی که یه کارمندم میتونم با پایتون کار های خسته کنندم رو با سرعت و دقت و سریع انجام بدم از اموزش سایتتون خیلی استفاده کردم و خیلی سر میزنم به شما. پیروز و شاد باشید.

    • 1399-02-19

      خیلی مچکر از شما. شما به ما لطف دارید. ان شالله که بتونیم بصورت مستمر مفید واقع بشیم.

  3. 1399-10-02

    سلام سایت بسیار خوبی دارید و مطالب بسیار مفید و کاربردی رو به خوبی توضیح دادین. خیلی از مطالبتون استفاده کردم . تشکر می کنم از زحماتتون
    فقط اگر زحمت بکشید و غلط های املایی متن رو تصحیح کنید عالی میشه.
    راجب –> راجع به
    دیگ –> دیگه

نوشتن دیدگاه

نشانی ایمیل شما منتشر نخواهد شد.