لذت برنامه نویسی: IPython Notebook یا Jupyter Notebook

اینم یه تجربه پراکنده دیگه!

من این چند روز بخاطر یه کاری نیاز داشتم یه مساله تئوری گراف رو حل کنم. من معمولا سعی میکنم که توی کارها یه چیز جدید رو یاد بگیرم. به همین خاطر با استفاده از ipython notebook یا jupyter notebook مساله رو حل کردم. اتفاقا جادی هم یه ویدئوی آموزشی خوب در موردش ساخته.

چرا Jupyter Notebook

خب اول از همه میخوام یه چیزایی رو توضیح بدم که به نظر من چرا شاید کسی بخواد از این سیستم‌ها استفاده کنه. مهم‌ترین استفاده‌ای که من براش داشتم اینه که هر جا که به نظرم میخواستم از matlab استفاده کنم میتونستم از jupyter notebook استفاده کنم. بدین شکل که شما برای خیلی کارهای علمی یه کارهایی رو توی matlab پیاده‌سازی میکنی و تست می‌کنی و وقتی لازم شد واقعا در محیط عملیاتی ازش استفاده کنی اون‌ها رو در محیط عملیاتی دوباره پیاده‌سازی می‌کنی.

خب اولین زبانی که jupyter notebook پشتیبانی میکرده python بوده که مثل زبان matlab ساده بوده و بخاطر پکیج‌های عملی که هر دو زبان دارن پیاده‌سازی کارهای علمی به شدت ساده می‌شه.

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

سوم اینکه هر دو ابزارهای بسیار خوب و قوی برای کشیدن نمودارهای علمی دارن که باعث میشه گزارش ساختن با اونها راحت باشه.

چهارم اینکه در jupyter notebook شما می‌تونید همزمان که کد می‌نویسید گزارش هم بنویسید. یعنی بلوک‌هایی داریم که توش میشه با استفاده از markdown متن هم بنویسید که در نهایت گزارش کاری که دارید انجام می‌دید هم آماده باشه. لازم نیست تکرار کنم که markdown رو من خیلی دوست دارم(۱ و ۲ و ۳)

یه مثال ساده

حالا کار من این بود که بتونم یه گراف جهت‌دار بدون دور بسازم و بتونم اون رو بکشم. خب اول از هم نحوه ساختن اون. کلا در ریاضی اثبات میشه که اگه بخواید گراف جهت‌دار بدون دور بسازید تنها چیزی که نیاز دارید اینه که توی ماتریس مجاورت اون گراف تنها درایه‌های زیر قطر اصلی ۱ باشن. این تضمین می‌کنه که گراف تولید شده گراف جهت‌دار بدون دور باشه.

اول از همه باید نیازمندی ها رو وارد کرد


		

بعد نوبت به کد ساختن DAG میرسه که کد این کار اینه


		

بعدش هم میشه نمایش دادنش که به سادگی میشه این


		

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

pandoc-filter

لذت برنامه نویسی: نوشتن یک pandoc filter با python

اینم یه تجربه پراکنده دیگه!

همنطور که اخیرا زیاد نوشتم فرمت مورد علاقه تولید مستندات من markdown شده و برای تبدیل کردنش به یه متن تر و تمیز pdf از pandoc به همراه xepersian استفاده می‌کنم. حالا این وسط من یه مشکلی داشتم و اونم این بود که متون انگلیسی توی فارسی به درستی به فرمت xepersian تبدیل نمی‌شدند و هی مجبور بودم بصورت دستی متن latex بدست آمده رو ویرایش کنم. به همین خاطر علاقه مند شدم که ببینم چطور می‌شه این مشکل رو توی pandoc حل کرد. راه حل از این قراره که شما بایستی یه فیلتر برای pandoc تعریف کنی و اون pandoc filter اون کاری که ما دوست داریم رو برای ما انجام میده!

فیلترهای pandoc

زبان برنامه نویسی که pandoc با اون توسعه یافته haskell هست که خب به نظر من زبان عجیب غریبی هست. شما می‌تونید با استفاده از این زبان فیلترها رو توسعه بدید. کل ماجرای فیلترها هم از این قراره که ابتدا pandoc متن ورودی رو میخونه و به ساختار سلسله مراتبی داخلی خودش تبدیل می‌کنه. حالا این ساختار رو بصورت اصلی (که فقط در زبان haskell در دسترسه) یا بصورت json در اختیار فیلتر شما قرار می‌ده و فیلتر شما بر اساس فرمت نهایی، نوع المنت و متا دیتاهای مربوط به اون المنت تصمیم می‌گیره که چه کاری انجام بده. تقریبا هیچ مستندات درست حسابی من پیدا نکردم که همه چیز رو توضیح داده باشه، اما سعی کردم به کمک آزمایش و خطا و همچنین دیدن فیلترهای مشابهی که برای کارهای مختلف توسعه پیدا کرده بود گلیم خودم رو از آب بیرون بکشم.

همچنین میشه این فیلترها رو به زبانی غیر از haskell توسعه داد. این زبان‌های پایتون، جاوا اسکریپت(در محیط nodejs)، پرل و php هست. من به علت آشنایی بیشترم با پایتون از اون استفاده کردم

نحوه توسعه

کل روند از این قراره که شما فایل پایتون رو بصورت یک فیلتر با دسترسی اجرایی در اختیار pandoc قرار میدید و اون تابع main رو صدا میزنه. پس از اون اطلاعات از stdin به برنامه داده شده و خروجی‌ها از stdout گرفته می‌شه. خود توسعه دهنده pandoc هم پکیجی به نام pandocfilters توسعه داده که با استفاده از pip یا ابزارهای مشابه قابل نصب و استفاده است.

تنها کاری که باید انجام بشه اینه که تابعی نوشته بشه و به عنوان آرگومان به تابع ‍‍

پاس داده بشه. این تابع بایستی چهارتا ورودی داشته باشه که به ترتیبت ‍‍

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

همین!
پ.ن.: برای مطالعه بیشتر به اینجا مراجعه کنید.

چرا لینوکس را دوست دارم: استخراج کلمات کلیدی از سایت نارنجی

اینم یه تجربه پراکنده دیگه!

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

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

خب اول از همه تابع استخراج تمامی url های تمام پست‌های نارنجی هست

 

def getNarenjiURLs(inUrl):
	lst = []
	url = 'http://narenji.ir/'

	# Check if it is a valid URL
	if 'http://' in inUrl:
		url = inUrl
	else:
		url = 'http://' + inUrl

	# logging start time
	rst = time.time()
	# getting URL content
	r  = requests.get(url)
	#logging end time
	rend = time.time()
	
	pst = time.time()
	data = r.text
	 
	# parsing content using Beautiful soupe
	soup = BeautifulSoup(data, 'lxml')

	for link in soup.find_all('div',class_='views-field views-field-title'):
		for a in link.find_all('a'):
			if a['href'].startswith('/'):
				lst.append('http://narenji.ir' + a['href'])
			else :
				lst.append(a['href'])
	pend = time.time()
	#print (' r Time = ' + str(rend - rst) +' p Time ' + str(pend - pst))
	return lst

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

def getNarenjiKeywords(inUrl):
	lst = []
	url = ""
	if 'http://' in inUrl:
		url = inUrl
	else:
		url = 'http://' + inUrl

	# logging start time	 
	rst = time.time()
	# getting URL content
	r  = requests.get(url)
	#logging end time
	rend = time.time()

	pst = time.time()

	# parsing content using Beautiful
	data = r.text
	 
	soup = BeautifulSoup(data, 'lxml')
	 
	for link in soup.find('div',class_='meta').findAll('a'):
		lst.append(link.text)
	pend = time.time()

	#print (' r Time = ' + str(rend - rst) +' p Time = ' + str(pend - pst))

	return lst

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

def doUrlWork():
	global urlList
	while True:
		url=qGetUrl.get()
		tmpUrl = getNarenjiURLs(url)
		print ( str(len(tmpUrl)) + ' URLs found')
		urlList.update(set(tmpUrl))
		qGetUrl.task_done()

def doKeywordWork():
	global keys
	while True:
		url=qGetKeywords.get()
		tmpKey = getNarenjiKeywords(url)
		print ( str(len(tmpKey)) + ' keys found')
		keys.update(set(tmpKey))
		qGetKeywords.task_done()

برای اینکه تعداد Thread ها زیاد نشه از یه صف استفاده کردم که الان یادم نیست. همچنین از مجموعه‌های پایتون برای حذف کلمات تکراری استفاده کردم.

پس اگه بخوام کل اسکریپت بصورت یکجا بیارم میشه:

import timeit
import time
from bs4 import BeautifulSoup
import urllib2
import requests
from Queue import Queue
from threading import Thread
import codecs

keys = set([])
urlList = set([])

concurrent = 10

def doUrlWork():
	global urlList
	while True:
		url=qGetUrl.get()
		tmpUrl = getNarenjiURLs(url)
		print ( str(len(tmpUrl)) + ' URLs found')
		urlList.update(set(tmpUrl))
		qGetUrl.task_done()

def doKeywordWork():
	global keys
	while True:
		url=qGetKeywords.get()
		tmpKey = getNarenjiKeywords(url)
		print ( str(len(tmpKey)) + ' keys found')
		keys.update(set(tmpKey))
		qGetKeywords.task_done()

def getNarenjiKeywords(inUrl):
	lst = []
	url = ""
	if 'http://' in inUrl:
		url = inUrl
	else:
		url = 'http://' + inUrl

	# logging start time	 
	rst = time.time()
	# getting URL content
	r  = requests.get(url)
	#logging end time
	rend = time.time()

	pst = time.time()

	# parsing content using Beautiful
	data = r.text
	 
	soup = BeautifulSoup(data, 'lxml')
	 
	for link in soup.find('div',class_='meta').findAll('a'):
		lst.append(link.text)
	pend = time.time()

	#print (' r Time = ' + str(rend - rst) +' p Time = ' + str(pend - pst))

 

به این ترتیب کلمات کلیدی نارنجی بصورت موازی استخراج شد و ذخیره شد!

همین!

لذت برنامه نویسی: اولین تجربه جدی من در وب به کمک django

اینم یه تجربه پراکنده دیگه!

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

وضعیت من این بود:

  • اولا ترجیحا باید توی سیستم لینوکس ران میشد
  • دوما اینکه من یه ذره بلد بودم با bootstrap و zurb foundation کار کنم
  • سوم اینکه یه ذره بلد بودم ASP.Net، Python Django و Symfony 2 آشنا بودم

همین. انتخاب‌هایی که من واسه پروژه انجام دادم اینا بودن

  • از bootstrap استفاده کردم چون دوستانی داشتم که بلد بودن با bootstrap کار کنن پس اگه کمک لازم بود کمک دم دسته!
  • از Django استفاده کردم چون بیشتر از اون دوتای دیگه ازش استفده کرده بودم

کار با این مجموعه فریم ورک ها بسیار لذت بخش بود چون بخوبی مستند شده بودند هم بدون باگ کار میکردن. میزان کد نویسی و تمیزی کد خیلی خوب بود. چون کد کوچک و خوانا و تمیز بود. همچنین من یه جایی نیاز داشتم که AJAX استفاده کنم که اون هم با استفاده از یه فریم ورک به نام prototype.js اون رو هم بصورت خیلی خوب و قابل قبولی پیاده سازی کردم.

در مجموع تجربه جدی من در کار با این فریم‌ورک‌ها به شدت خوب و لذت بخش بود و سادگی، روانی برنامه نویسی و روانی برنامه خیلی لذت بخش بود

همین!

python logo

لذت برنامه نویسی یا پایتون چیست و چرا؟

اینم یه تجربه پراکنده دیگه

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

اما برم سراغ اصل مطلب که همون پایتون باشه! من تجربم با پایتون بسیار تجربه لذت بخشی بوده. یعنی اینکه بسیار زبون شیرین و تو دل برو ای هست. ساختار زبان تا اونجایی که من میدونم به گونه‌ای ساده شده که سرعت توسعه توش زیاد باشه. چارچوب‌ها و کتابخانه‌های بسیاری خوبی بالاخص برای طراحی وب داره(django, flask, …) که باعث میشه شما بتونید به راحتی خیلی از کارهای سختی که قبلا انجام میدادید رو تنها با چند خط کد انجام بدید.

همچنین یه سیستم خیلی قشنگ هم برای مدیریت پکیج‌ها، نیازمندی‌ها و سایر چیزا داره(pip) که برای شما این امکان رو ایجاد میکنه که یه پروژه رو خیلی سریع استارت بزنید. همچنین برای اونهایی که لینوکس کار میکنن یه سری امکانات داره که به شما اجازه میده بدون اینکه به root سیستم دسترسی داشته باشید خیلی کارهای زیادی رو انجام بدید(virtualenv). وب سرورهای خوبی برای محیط توسعه و حتی محیط‌های عملیاتی داره که بسیار هم خوش دسن.

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

امیدوارم این تجربه هم به درد کسی بخوره.