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

2 ديدگاه





 

webscrap_image

دریافت داده از سایت یا webscraping چیست ؟

نرم افزار هایی ( webscraping ) با ارسال درخواست های مختلف به تجزیه و تحلیل داده هایی که درون پاسخ وجود دارد اقدام می کند

کتابخانه Requests :

برای نصب کتابخونه Requests تنها کافی است دستور زیر را بزنید

pip3 install requests

درخواست GET بسیار ساده تعریف می شود نحوه ارسال درخواست به این صورت می باشد

>>> import requests
>>> response = requests.get('https://api.github.com')

خب از متغیر response برای دسترسی به پاسخ وبسایت استفاده می کنیم برای دریافت کد وضعیت درخواست از کد

>>> print(response.status_code)

استفاده می کنیم برای مشاهده پاسخ سایت سه روش وجود دارد روش اول دریافت به صورت Bytes می باشد که با دستور

>>> response.content
b'{"current_user_url":"https://api.github.com/user"}'

برگردانده می شود داده می شود روش دوم دریافت پاسخ به صورت String می باشد که با دستور

>> response.text
'{"current_user_url":"https://api.github.com/user"}'

مقدار به صورت String برگردانده می شود ، این کتابخونه می تواند نوع کدگذازی پاسخ را متوجه شده و کدگشایی کند اما درصورتی که نوع کدگذاری را به اشتباه پیدا کرده بود می توانید با دستور

>>> response.encoding = 'utf-8'

نوع کدگذاری را تعیین کنید سپس پاسخ را به صورت String دریافت کنید روش سوم دریافت پاسخ از سایت به صورت Json می باشد که با دستور

>>> response.json()
{"current_user_url":"https://api.github.com/user"}

پاسخ درصورتی که به صورت json باشد تبدیل به دیکشنری در پایتون می شود و برگردانده می شود. یکی دیگر از تابع های پرکاربرد این کتابخونه تابع headers است که اطلاعات مفیدی درباره Content-type ، مدت زمانی که پاسخ توسط سرور نگه داشته می شود چه قدر است و … با دستور

>>> response.headers
{'Server': 'GitHub.com', 'Date': 'Mon, 10 Dec 2018 17:49:54 GMT', .....}

این مقدار ها به شما بازگردانده می شود همچنین برای دریافت تنها یک بخش از Header می توانید از دستور زیر استفاده کنید

>>> response.headers['Server']
GitHub.com

در متود get می توانیم پارامتر ها را درون لینک قرار دهیم اما برای اصولی تر شدن کار از دیکشنری به نام params درون ارسال درخواست اسفتاده می کنیم

>>> response = requests.get('https://api.github.com/search/repositories', params={'q': 'requests+language:python'})

همچنین می توایند پارامتر ها را به صورت Bytes هم ارسال کنید

>>> response = requests.get('https://api.github.com/search/repositories', params=b'q = requests+language:python')

برای تنظیم Header دیکشنری همانند پارامتر می نویسید به نام headers

>>> response = requests.get('https://api.github.com/search/repositories', params={'q': 'requests+language:python'},headers={'Accept': 'application/vnd.github.v3.text-match+json'})

درضمن درون Header با استفاده از دستور زیر می توانیم User-agent تایین کنیم

>>> my_user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.47 Safari/537.36'
>>> response = requests.get('https://api.github.com/search/repositories', params={'q': 'requests+language:python'},headers={'Accept': 'application/vnd.github.v3.text-match+json','user-agent':my_user_agent})

تمام تابع های ذکر شده برای متود Post نیز قابل استفاده است برای ارسال Post باید دستور زیر را وارد کرد

>>> requests.post('https://httpbin.org/post', data={'key':'value'})

دیگر متود هایی که کتابخونه Requests پشتیبانی می کند

>>> requests.put('https://httpbin.org/put', data={'key':'value'})
>>> requests.delete('https://httpbin.org/delete')
>>> requests.head('https://httpbin.org/get')
>>> requests.patch('https://httpbin.org/patch', data={'key':'value'})
>>> requests.options('https://httpbin.org/get')
کتاب خانه beautifulsoup4 :

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

pip3 install beautifulsoup4

برای دریافت کد های Html اول باید یک درخواست Get توسط کتابخونه Request بفرستیم

>>> import requests
>>> response = requests.get("http://www.example.com")

خب سپس باید بازخوردی که دریافت کردیم ( صفحه Html ) قابل تجزیه کنیم با دستور زیر این عمل را انجام می دهیم

>>> from bs4 import BeautifulSoup as BS
>>> soup = BS(response.content,'html.parser')

خب حال می خواهیم نوع داده هایی که درون متغیر soup را ببینیم ، children. عنصر را به عنصر های کوچک تر تبدیل می کند

>>> [type(item) for item in list(soup.children)]‍
‍‍‍‍[bs4.element.Doctype, bs4.element.NavigableString, bs4.element.Tag]

خب اولین عنصر این لیست هاوی نوع فایل است ، عنصر دوم متنی است که به عنوان جدا کننده می شناسد که گاها n می باشد اما عنصر سوم عنصری است که ما می خواهیم با آن کار کنیم حال باید عنصر سوم که هاوی کد های html است را به عناصری کوچک تر تبدیل کنیم

>> html = list(soup.children)[2]

حالا که تگ ها html صفحه را در اختیار داریم می خواهیم روش های مختلف انتخاب تگ را بررسی می کنیم . خب در صورتی که بخواهیم تمام تگ های مد نظر را انتخاب کنیم از دستور زیر استفاده می کنیم برای مثال ما از درون صفحه تمام تگ های a را انتخاب می کنیم

html.find_all('a')

توجه داشته باشید به دلیل وجود چند تگ a درون صفحه نوع پاسخ این تابع به صورت List است حالا در صورتی که بخواهیم یک تگ را انتخاب کنیم با خصوصیات مشخص از تابع زیر استفاده می کنیم

>>> html.find("input",{"id":"input1"})

این تابع ورودی ( input ) که id آن برابر input1 است را انتخاب می کند حال می خواهیم مقدار این ورودی را دریافت کنیم تنها کافی است از این دستور استفاده کنیم

>>> html.find("input",{"id":"input1"})["value"]

در صورتی که جای value هر یک از ورودی های استفاده شده در تگ انتخاب شده را قرار دهید مقدار آن را بر میگرداند . ما نیز می توانیم همانند انتخاب تگ در css تگ مورد نظر را انتخاب کنیم

کتابخانه Selenium :

این کتاب خانه در بیشتر زبان های برنامه نویسی وجود دارد اگر بخواهیم به طور کاملا خلاصه این کتاب خانه را معرفی کنیم می توانیم بگوییم این کتابخانه عرضه شده جهت ارتباط زبان برنامه نویسی با مرورگر ( ربات نویسی ) .

خب برای اینکه بتوانیم با مرورگر ارتباط بگیریم نیاز به یک برنامه رابط داریم نام این رابط webdrive است.

خب webdrive ها برای هر مرورگر متفاوت است شما می توانید برای مرورگر Chorm, Edge, Firefox, Safari وب درایور مخصوصشان را دانلود کنید لینک صفحه وب درایو مخصوص هر مرورگر را اینجا قرار می دهیم

Chrome: https://sites.google.com/a/chromium.org/chromedriver/downloads

Edge: https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/

Firefox: https://github.com/mozilla/geckodriver/releases

Safari: https://webkit.org/blog/6900/webdriver-support-in-safari-10/

خب ما در این آموزش از geckodrive استفاده می کنیم این درایو مخصوص FireFox است . geckodrive هم برای ویندوز هم برای لینوکس عرضه شده است نصب در هر دو همانند یک دیگر است مراحل آماده سازی درایو به این صورت است

۱. دانلود فایل پرس شده مخصوص سیستم عامل

۲. استخراج فایل

۳. قرار دادن فایل geckodrive در پوشه ای که پروژه قرار دارد

حالا میخواهیم یک صفحه باز کنیم ( در لینوکس executable_path را به صورت ./geckodriver و در ویندوز geckodrive.exe برای ادرس دهی استفاده می کنیم توجه داشته باشید تعریف executable_path واجب نمی باشد در صورت کنار هم بودن درایو مورد نظر تنها صدا زدن نام درایو کافیست)

>> from selenium import webdriver
>> from selenium.webdriver.common.keys import Keys
>> from time import sleep
>> browser = webdriver.Firefox(executable_path='./geckodriver')
>> browser.set_window_size(900,900)
>> browser.get("https://pythons.ir/")
>> browser.find_element_by_name("s").send_keys("selenium")
>> sleep(5)
>> browser.close()

در مثال بالا در خط ۴ با استفاده از ()webdrive.Firefox گفتیم که webdrivex ما برابر با فایرفاکس و محل خود فایل در همانجا به نام geckodriver است همچنین می توانیم از نوشتن آن امتناع کنیم. خط بعدی امده ایم اندازه صفحه را بر حسب پیکس ابعاد داده ایم سپس در خط بعد با دستور get گفتیم یک درخواست به صفحه اصلی pythons.ir بفرستد سپس به دنبال تگی گشتیم که name آن برابر s است پس از پیدا کردن با دستور send_keys مقدار selenium را درون آن قرار می دهد و اجرا می کند سپس با استفاده از sleep گفته ایم ۵ ثانیه منتظر بمان و بعد مرورگر را ببند

نحوه انتخاب تگ ها :

انتخاب تگ با استفاده از id

my_tag = browser.find_element_by_id("id")

انتخاب تگ با استفاده از name

my_tag = browser.find_element_by_name("name")

انتخبا تگ با استفاده از xpath
xpath زبانی است که برای یافتن تگ ها در یک سند XML استفاده می شود. از آنجا که HTML به XML نزدیک است باشد ، در نتیجه ما می توانند از این زبان قدرتمند برای هدف قرار دادن تگ ها استفاده کنیم ، برای مثال می خواهیم یک تگ form را انتخاب کنیم که id آن برابر loginform باشه به مثال زیر دقت کنید.

my_tag = browser.find_element_by_xpath("//form[@id='loginForm']")

انتخاب توسط link_text
این تابع تمام تگ های لینک را انتخاب می کند و سپس می توانیم تایین کنیم تنها تگی که متن آن برابر متن مورد نظر ما است را برگرداند

my_tag = browser.find_element_link_text("hello")

انتخاب تگ توسط class

my_tag = browser.find_element_by_class_name("hello")

انتخاب تگ مانند انتخاب تگ در css

my_tag = driver.find_element_by_css_selector('div#p')

منتظر ماندن ، خارج شدن :
ما می توانیم درون webdrive تایین کنیم در صورتی که تگ مورد نظر ما در زمان معین شده پیدا نشد ارور داده و از حالت لودینگ خارج شود و دستور بعدی را اجزا کند به مثال زیر دقت کنید

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("https://pythons.ir/")
try:
    element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "myDynamicElement")))
    element.click()
finally:
    driver.quit()

خب در مثال بالا سه تابع جدید import کردیم اولین تابع By است که می توانیم تایین کنیم بر چه اساس می خواهیم تگ را انتخاب کنیم نحوه استفاده از این تابع با رنک قرمز در بالا نشان داده شده. و تابع بعدی که import شده است از support.ui تابع WebDriverWait است همانطور که از نام این تابع مشخص مربوط به دریافت زمان و مدت زمان منتظر ماندن است که دو ورودی میگیرید یکی driver و دیگری مدت زمان انتظار به ثانیه و سپس از تابع until استفاده کردیم که به معنی تا زمانی که را می دهد درون until از EC استفاده کردیم همانطور که در خط ۴ مشاهده می کنید از webdriver.support تابع expected_conditions به معنی شرط مورد انتظار است را به عنوان EC اضافه کردیم ، از EC تابع presence_of_element_located را صدا زدیم به این معنی که در صورتی که تگ myDynamicElement را پیدا کرد مقدار تگ را بر گرداند و بر روی آن کلیک کند در غیر این صورت اروری را پرتاب می کند. در مثالی که بالا نوشته ایم تگ پیدا نمیشود در نتیجه درایو بسته می شود.
توجه داشته باشید که تابع By تنها از طریق ID اقدام به پیدا کردن تگ نمی کند شما می توانید از طریق name, class_name و … تگ را پیدا کنید .انواع پیدا کردن تگ توسط By :
توسط id

By.ID

توسط name

By.NAME

توسط نام کلاس

By.CLASS_NAME

توسط Xpath

By.XPATH

شرط های مورد انتظار :

می توانیم به جای presence_of_element_located در مثال بالا از شرط های مورد انتظار دیگری نیز استفاده کنیم لیست شرط های قابل دسترس :
در صورت وجود title

title_is

در صورت وجود بدنه

title_contains

درصورت نمایان شدن تگ مورد نظر

visibility_of_element_located

در صورت نماین شدن

visibility_of

وجود تمام تگ های مشخص شده

presence_of_all_elements_located

در صورت وجود متن مشخص شده در تگ

text_to_be_present_in_element

در صورت وجود متن مورد نظر در مقدار یک تگ

text_to_be_present_in_element_value

در صورت وجود frame که بتوان بر روی آن عملی را انجام دهیم

frame_to_be_available_and_switch_to_it

در صورت نامرئی بودن تگ

invisibility_of_element_located

در صورتی که تگ مورد نظر قابلیت کلیک کردن داشته باشد

element_to_be_clickable

در صورتی که تگ انتخاب شده در حالت … باشد

element_selection_state_to_be

وضعیت تگ از بخش مد نظر در حالت … باشد

element_located_selection_state_to_be

در صورتی که popup جاوا اسکریپتی اجرا شود

alert_is_present

دسترسی های Selenium :

دسترسی به popup ها :

نکته قابل توجه ای که selenium دارد قابلیت دسترسی به popup های جاوااسکریپتی (alert, prompt) نیز می باشد با استفاده از شرط های مورد انتظار می توانیم به popup دسترسی پیدا کنیم به مثال زیر دقت کنید

from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait 
from selenium.webdriver.support import expected_conditions as EC 
driver = webdriver.Firefox() 
driver.get("https://pythons.ir/")
try: 
   WebDriverWait(driver, 10).until(EC.alert_is_present())
   prompt = driver.switch_to_alert()
   print(prompt.text)
   prompt.send_keys("ok")
   user_ans = int(input("Enter 1 if you want to accept and if you want to dismiss enter 2 >>>"))
   if(user_ans == 1):
      prompt.accept()
   else:
      prompt.dismiss()
finally:
   sleep(3)
   driver.quit()

در مثال بالا به درایو گفته ایم ۱۰ ثانیه وایسا تا زمانی که popup نمایان شود اگر نمایان شد پس اروری رخ نمی دهد و شرط ادامه پیدا می کند درخط بعد گفته ایم که بر روی alert متمرکز شود (توجه داشته باشید که منظور از alert همان popup است) و آن را برابر متغییر prompt قرار بده و متن آن را پرینت کن و از کاربر بخواه که عدد ۱ را درصورتی که می خواهد prompt را تایید کند و ۲ را در صورتی که می خواهد prompt را کنسل کند و در آخر گفته ایم برای ۳ ثانیه منتظر بمان و سپس درایو را ببند

دسترسی به تاریخچه و موقعیت :

پیش تر به دستور driver.get اشاره ای داشتیم همانطور که می دانید هنگامی که شما صفحه ای را باز می کنید درون تاریخچه مرورگر ذخیره می شود در کتابخانه selenium می توانیم به این تاریخچه ها دسترسی داشت باشیم اما به صورت موقت. در نتیجه می توانید با دو دستور driver.forward و driver.back به موقعیت قبلی بروید

دسترسی به کوکی :

یکی از دسترسی های پر کاربرد selenium دسترسی به کوکی ها می باشد . نجوه تنظیم کردن کوکی در selenium به این صورت است که اول باید یک دیکشنری تعریف کنیم سپس با دستور add_cookie کوکی را اضافه می کنیم و برای دریافت کوکی ا ز دستور get_cookie استفاده می کنیم. توجه داشته باشید path هر کوکی بابر موقعیت فعلی درایو است

from selenium import webdriver
from time import sleep
driver = webdriver.Firefox()
driver.get("https://pythons.ir")
cookie = {‘name’ : ‘foo’, ‘value’ : ‘bar’}
driver.add_cookie(cookie)
driver.get_cookies()
sleep(3)
driver.close()
دسترسی به دیگر صفحات :

همانطور که پیشتر در مثال دسترسی به popup ها دیدید که ما بر روی alert متمرکز شدیم می توانیم همین عمل را برای دیگر صفحهات یا تگ های frame انجام دهیم یعنی بر روی دیگر صفحات سویچ کنیم

from selenium import webdriver
from time import sleep
driver = webdriver.Firefox()
driver.get("https://pythons.ir")
driver.switch_to_window("windowName")
sleep(3)
driver.close()
دسترسی به سورس صفحه :

با استفاده از تابع page_source می توانیم به کد html صفحه دسترسی پیدا کنیم و سپس

from selenium import webdriver
from time import sleep
driver = webdriver.Firefox()
driver.get("https://pythons.ir")
html = driver.page_source
f = open("index.html","w")
f.write(html)
f.close()​
sleep(3)
driver.close()​

تعامل با صفحه در کتابخانه selenium :

انتخاب مقداری از تگ Select :

پیش تر نحوه انتخاب تگ را یاد گرفتیم حال میخواهیم انتخاب یک Select و انتخاب value را آموزش دهیم برای کار با تگ Select تابعی به نام Select وحود دارد. به مثال زیر دقت کنید

from selenium import webdriver
from selenium.webdriver.support.ui import Select
from time import sleep
driver = webdriver.Firefox()
driver.get("https://pythons.ir")
select = Select(driver.find_element_by_name('name'))
print(select.options)
select.select_by_index(1)
select.select_by_visible_text("English")
select.select_by_value("en")sleep(3)
driver.close()​

در مثال بالا ما تگی که نام ان برابر name است را با استفاده از متد های find انتخاب کردیم سپس درون تابع Select قرار دادیم این تابع انتخاب option ها را برای ما در دسترس تر خواهد کرد سپس با دستور select.options تمام مقادیر تگ Select را پرینت می کندما به سه روش می توانیم option مورد نیاز را انتخاب کنیم روش اول با دادن index ( شماره ترتیب قرار گرفتن option مورد نظر ) بر اسا نوشته option یا بر اسا مقداری که option همراه خود دارد.

ارسال اطلاعات فرم :

یکی از راه های ارسال اطلاعات فرم کلیک بر روی دکمه submit است برای این کار دکمه Submit را انتخاب کرده و سپس تابع click را صدا می کنیم این عمل همانند کلیلک کردن بر روی دکمه ارسال داده فرم می باشد مثال زیر دقت کنید

from selenium import webdriver
from selenium.webdriver.support.ui import Select
from time import sleep
driver = webdriver.Firefox()
driver.get("https://pythons.ir")
btn_submit = driver.find_element_by_id('submit')
​btn_submit.click()
sleep(3)
driver.close()​

اما در بعضی از فرم ها هیچ دکمه Submit وجود ندارد و تنها با فشردن کلید Enter عمل می کند مانند فرم های سرچ برای اینکار از common تابع keys را به ضفحه اضافه می کنیم سپس ورودی مورد نظر را انتخاب می کنیم و زدن Enter را شبیه سازی می کنیم به مثال زیر دقت کنید

from selenium import webdriver
from selenium.webdriver.support.ui import Select
from time import sleep
driver = webdriver.Firefox()
driver.get("https://pythons.ir")
search_input = driver.find_element_by_id('s')
search_input.send_keys("hello")
search_input.send_keys(u'ue007') sleep(3) driver.close()​​

در مثال بالا ما ورودی جست و جو را پیدا کرده و درون متغیر search_input قرار دادیم سپس مقدار hello را درون ورودی نوشته و سپس با همان تابع send_keys و با استفاده از api key کد دکمه Enter را وارد کردیم در ادامه کد کلید های خاص را مشاهده می کنید

ALT = u'ue00a'
ARROW_DOWN = u'ue015'
ARROW_LEFT = u'ue012'
ARROW_RIGHT = u'ue014'
ARROW_UP = u'ue013'
BACKSPACE = u'ue003'
BACK_SPACE = u'ue003'
CANCEL = u'ue001'
CLEAR = u'ue005'
COMMAND = u'ue03d'
CONTROL = u'ue009'
DECIMAL = u'ue028'
DELETE = u'ue017'
DIVIDE = u'ue029'
DOWN = u'ue015'
END = u'ue010'
ENTER = u'ue007'
EQUALS = u'ue019'
ESCAPE = u'ue00c'
F1 = u'ue031'
F10 = u'ue03a'
F11 = u'ue03b'
F12 = u'ue03c'
F2 = u'ue032'
F3 = u'ue033'
F4 = u'ue034'
F5 = u'ue035'
F6 = u'ue036'
F7 = u'ue037'
F8 = u'ue038'
F9 = u'ue039'
HELP = u'ue002'
HOME = u'ue011'
INSERT = u'ue016'
LEFT = u'ue012'
LEFT_ALT = u'ue00a'
LEFT_CONTROL = u'ue009'
LEFT_SHIFT = u'ue008'
META = u'ue03d'
MULTIPLY = u'ue024'
NULL = u'ue000'
NUMPAD0 = u'ue01a'
NUMPAD1 = u'ue01b'
NUMPAD2 = u'ue01c'
NUMPAD3 = u'ue01d'
NUMPAD4 = u'ue01e'
NUMPAD5 = u'ue01f'
NUMPAD6 = u'ue020'
NUMPAD7 = u'ue021'
NUMPAD8 = u'ue022'
NUMPAD9 = u'ue023'
PAGE_DOWN = u'ue00f'
PAGE_UP = u'ue00e'
PAUSE = u'ue00b'
RETURN = u'ue006'
RIGHT = u'ue014'
SEMICOLON = u'ue018'
SEPARATOR = u'ue026'
SHIFT = u'ue008'
SPACE = u'ue00d'
SUBTRACT = u'ue027'
TAB = u'ue004'
UP = u'ue013​'

2 ديدگاه

  1. 1399-03-02

    با سلام و ممنون از آموزشی که دادید فقط یه سوال دارم
    اینکه در پایتون ۳٫۸٫۲ خود json رو نتونستم نصب کنم چون ارور میده واینکه من از simbeljson استفاده کردم درست بود کارم؟

    • 1399-03-02

      سلام دوست خوبم

      فکر کنم خود json بصورت پیش فرض نصب باشه هااا

نوشتن دیدگاه

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