آموزش اتصال به دیتابیس mysql با استفاده از پایتون
- زمان مطالعه: 14 دقیقه
- اشتراک گذاری این نوشته در:
امروزه، زبان برنامه نویسی پایتون و قدرت بالای آن تقریبا برای هیچ برنامه نویسی پوشیده نیست! در آموزش اتصال به دیتابیس mysql با استفاده از پایتون باهم یاد میگیریم که چطوری با پایتون، دادهها را از سایت بخوانیم و اون رو توی دیتابیس ذخیره کنیم تا بتوانیم بعدا ازش استفاده کنیم. (این آموزش متناسب با سیستم عامل ویندوز طراحی شده است)
آموزش پروژه محور شامل استخراج کد ملک، نوع ملک، آدرس و قیمت ملک از وبسایت
در این پروژه آموزشی، داخل دیتابیس یک جدول میسازیم و بعد دیتا را از سایت (https://iranfile.ir/properties/buy) میخوانیم و داخل دیتابیسی که ساختیم ذخیره میکنیم. در این برنامه، اسم منطقه یا محلهای از تهران از کاربر دریافت میشود و خانههایی که در آن ناحیه برای خرید قرار گرفتهاند، برای کاربر نمایش داده می شود. برای ایجاد وب سرور مجازی یکی از بهترین برنامههای موجود، XAMPP هست و نصب آن هم بسیار ساده است. بنابراین XAMPP رو از این لینک دانلود و نصب کنید.
نصب ماژولهـای لازم
داخل ترمینال این دستورات رو اجرا کنید…
برای web scraping نیاز به نصب موارد زیر داریم:
pip install requests
pip install bs4
برای دیتابیس نیاز به نصب موارد زیر داریم:
python -m pip install mysql-connector
python -m pip install wheel
python -m pip install mysql-connector-python
راهاندازی دیتابیـس
بعد نصب موارد لازم، برای راه اندازی دیتابیس باید XAMPP را اجرا کنیم و دو تا گزینهی Apache و MySQL را start کنیم. (اگر MySQL ارور قرمز رنگ داشت و start نشد، احتمال دارد Port آن اشغال شده باشد. برای رفع این ارور، از منوی استارت، Services رو سرچ کنید. توی لیست، MySQL را پیدا کنید و آن سرویس را stop کنید)
حالا یک فایل پایتونی به نام init_db.py بسازید و اجرا کنید تا یک دیتابیس و یک جدول داخل آن ایجاد بشود:
# In init_db.py
import mysql.connector
# Database connection
connection = mysql.connector.connect(
user='root',
password='',
host='127.0.0.1', # localhost
)
cursor = connection.cursor()
def init_db():
new_db = """
CREATE DATABASE homes;
"""
new_table = """
CREATE TABLE data(
code VARCHAR(10),
type VARCHAR(20),
address VARCHAR(256),
price VARCHAR(32));
"""
cursor.execute(new_db)
connection.commit()
cursor.execute(new_table)
connection.commit()
cursor.close()
init_db()
connection.close() # Close the connection
افزودن کوئری به برنامه
ابتدای برنامه، ما یک کانکشن به دیتابیس زدیم. با متد connect به سرور وصل شدیم و با استفاده از آن یک آبجکت cursor ساختیم. حالا با این آبجکت میتوانیم کوئریهای SQL را اجرا کنیم. داخل تابع دو تا کوئری قرار گرفته است؛ new_db برای ساخت یک دیتابیس جدید و new_table برای ساخت یک جدول جدید. بعد از اینکه کد را اجرا کردید خروجی خاصی نمیبینید. میتوانید به عنوان تمرین، کوئریهای زیر را داخل برنامه قرار دهید تا مطمئن بشوید که دیتابیس و جدول آن ایجاد شدهاند. (البته دقت داشته باشید که دوباره تابع init_db را اجرا نکنید!)
cursor.execute("SHOW DATABASES;")
for db in cursor:
print(db)
cursor.execute("SHOW TABLES;")
for tb in cursor:
print(tb)
اینجا چون داریم دیتا را میخوانیم (عمل READ) دیگه نیازی به connection.commit نیست!
حالا یه فایل پایتون دیگر به نام دلخواه بسازید و کدهای زیر را داخل آن بنویسید:
import time
import requests
from bs4 import BeautifulSoup
import mysql.connector
# Database connection
connection = mysql.connector.connect(
user='root',
password='',
host='127.0.0.1',
database='homes', # Recently added
)
cursor = connection.cursor()
def insert_to_db(data: dict):
add_home = """
INSERT INTO data(code, type, address, price)
VALUES (%s, %s, %s, %s);
"""
cursor.execute(add_home, (data['code'], data['type'], data['address'], data['price']))
connection.commit()
cursor.close()
خواندن دادهها از روی سایت
بعد از اینکه ماژولهای مورد نیاز را import کردیم، دوباره نیاز داریم به دیتابیس متصل بشویم. دقت کنید که اینبار پارامتر database به متد connect اضافه شده (برای استفاده کردن از دیتابیسی که ایجاد کردیم). ورودی تابع یک دیکشنری هست که پارامترهایی که میخواهیم داخل دیتابیس ذخیره کنیم را داخل آن قرار دادیم. دقت کنید که اولین پارامترِ متدِ execute، کوئری SQL و دومین پارامتر، یک تاپل از مقادیری هست که میخواهیم داخل کوئری قرار بدهیم.
حالا یک تابع به نام crawl نوشتم که دیتا را از روی سایت میخواند:
def crawl(pages: int):
"""Crawler"""
print('The crawler is running...')
for page in range(1, pages + 1):
url = f'https://iranfile.ir/Search/A4BDC39B-{page}/NOX-%D8%AE%D8%B1%DB%8C%D8%AF_%D8%AA%D9%87%D8%B1%D8%A7%D9%86'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find_all('table', attrs={'class': 'table table-hover'})
table_soup = BeautifulSoup(str(table), 'html.parser')
t_body = table_soup.find('tbody')
trs = # All 'tr' html tags on each page
data = {}
for tr in trs:
tr_soup = BeautifulSoup(str(tr), 'html.parser')
td = tr_soup.find_all('td')
if td:
data['code'] = td[1].text.strip()
data['type'] = td[3].text.strip()
data['address'] = td[4].text.strip()
data['price'] = td[7].text.strip()
insert_to_db(data)
time.sleep(1)
# By KhaneCode with ❤️
ورودی این تابع تعداد صفحاتی از سایت هست که میخواهیم دیتا را از صفحات آن برداریم (مثلا میخواهیم 12 تا صفحه اول رو بخواند). دیتاهایی که از سایت استخراج کردیم شامل: کد ملک، نوع ملک، آدرس و قیمت هست.
یک sleep هم قرار میدیم با مکث 1 ثانیهای تا از بلاک شدن جلوگیری کنیم.
یک تابع دیگر نیز میخواهیم برای اینکه دیتایی که از سایت برداشتیم و داخل دیتابیس قرار دادیم را از دیتابیس بخواند:
def read_form_db(location):
query = """
SELECT * FROM data;
"""
cursor.execute(query)
result = []
for code, type_, address, price in cursor:
if location in address:
data = {code: {'type': type_, 'address': address, 'price': price}}
result.append(data)
return result
کنترل جریان اصلی برنامه با تابع main
تا به اینجای کار توابع اصلی را داریم، ولی مهم تر از این موارد، کنترل جریان برنامه هست! (داخل برنامهها سعی کنید همیشه تابعی به نام main داشته باشید که جریان اصلی برنامه را کنترل میکند):
def main():
while True:
mode = input('Select mode by press [1], [2] or [0]:\n\t1. Crawl 🐍\n\t2. Read 📖\n\t0. Cancel ❌\n>>> ')
if mode == '1':
pages = int(input('Enter the number of pages you want to crawl; example: 5\n>>> '))
crawl(pages)
print(f"{pages} page(s) are saved in database ✔️")
elif mode == '2':
location = input('Enter the location you want; example: نارمک\n>>> ')
result = read_form_db(location)
print(f"\n{len(result)} results:")
if result:
for item in result:
for code, value in item.items():
output = "-- -- -- --\n"
output += f"code: {code}\n"
output += f"\taddress: {value['address']}\n"
output += f"\ttype: {value['type']}\n"
output += f"\tprice: {value['price']}\n"
print(output)
else:
print('Sorry, Not found!')
elif mode == '0':
break
else:
print('Just press [1], [2] or [0]')
if __name__ == '__main__':
main()
connection.close()
کل کدهای پروژه به صورت یکجــا و کامل:
import time
import requests
from bs4 import BeautifulSoup
import mysql.connector
# Database connection
connection = mysql.connector.connect(
user='root',
password='amirHosein@1379',
host='127.0.0.1',
database='homes',
)
cursor = connection.cursor()
def insert_to_db(data: dict):
add_home = """
INSERT INTO data(code, type, address, price)
VALUES (%s, %s, %s, %s);
"""
cursor.execute(add_home, (data['code'], data['type'], data['address'], data['price']))
connection.commit()
cursor.close()
def read_form_db(location):
query = """
SELECT * FROM data;
"""
cursor.execute(query)
result = []
for code, type_, address, price in cursor:
if location in address:
data = {code: {'type': type_, 'address': address, 'price': price}}
result.append(data)
return result
def crawl(pages: int):
"""Crawler"""
print('The crawler is running...')
for page in range(1, pages + 1):
url = f'https://iranfile.ir/Search/A4BDC39B-{page}/NOX-%D8%AE%D8%B1%DB%8C%D8%AF_%D8%AA%D9%87%D8%B1%D8%A7%D9%86'
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
table = soup.find_all('table', attrs={'class': 'table table-hover'})
table_soup = BeautifulSoup(str(table), 'html.parser')
t_body = table_soup.find('tbody')
trs = # All 'tr' html tags on each page
data = {}
for tr in trs:
tr_soup = BeautifulSoup(str(tr), 'html.parser')
td = tr_soup.find_all('td')
if td:
data['code'] = td[1].text.strip()
data['type'] = td[3].text.strip()
data['address'] = td[4].text.strip()
data['price'] = td[7].text.strip()
insert_to_db(data)
time.sleep(1)
def main():
while True:
mode = input('Select mode by press [1], [2] or [0]:\n\t1. Crawl 🐍\n\t2. Read 📖\n\t0. Cancel ❌\n>>> ')
if mode == '1':
pages = int(input('Enter the number of pages you want to crawl; example: 5\n>>> '))
crawl(pages)
print(f"{pages} page(s) are saved in database ✔️")
elif mode == '2':
location = input('Enter the location you want; example: نارمک\n>>> ')
result = read_form_db(location)
print(f"\n{len(result)} results:")
if result:
for item in result:
for code, value in item.items():
output = "-- -- -- --\n"
output += f"code: {code}\n"
output += f"\taddress: {value['address']}\n"
output += f"\ttype: {value['type']}\n"
output += f"\tprice: {value['price']}\n"
print(output)
else:
print('Sorry, Not found!')
elif mode == '0':
break
else:
print('Just press [1], [2] or [0]')
if __name__ == '__main__':
main()
connection.close()