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

۴۱۴ بازدید
آخرین به‌روزرسانی: ۲۴ اردیبهشت ۱۴۰۲
زمان مطالعه: ۴ دقیقه
تبدیل داده های بدون ساختار به ساخت یافته با پایتون و API نقشه گوگل — راهنمای کامل

جمع‌آوری آدرس‌ها از منابع گوناگون وب، اغلب منجر به ایجاد مجموعه داده‌های ناسازگار می‌شود. ساختاردهی به این داده‌ها یکی از وظایفی به شمار می‌آید که هیچ کس واقعا تمایلی به انجام آن ندارد زیرا کاری عادی، خسته‌کننده و زمان‌بر است. چنین مسائلی معمولا با استفاده از کدنویسی قابل حل هستند. در این مطلب، چگونگی تبدیل داده‌های بدون ساختار آدرس‌ها با پایتون و API نقشه گوگل بررسی شده است.

مساله تبدیل داده‌های بدون ساختار آدرس

فرض می‌شود که جدول داده‌ای با آدرس‌هایی شبیه آنچه در تصویر زیر آمده وجود دارد.

جدول آدرس‌های ساختار نیافته

اما کاربر به جدولی مانند آنچه در تصویر زیر آمده نیاز دارد.

جدول آدرس‌های ساختاریافته

انجام این تبدیل کار عذاب‌آوری به نظر می‌رسد! دلیل این امر وجود ناسازگاری‌ها و مرزبندی‌های نامناسب است که البته در مثال بالا تعداد کمی از آن‌ها وجود دارد، ولی در مجموعه داده‌های جهان واقعی تعداد آن‌ها بسیار زیاد و قابل توجه محسوب می‌شود. افرادی که با نرم‌افزارهای صفحه گسترده مانند «اکسل» (Excel) آشنایی دارند، ممکن است راهی برای حل این مساله به صورت خودکار پیدا کنند، ولی این کار نیازمند تعداد زیادی عبارت if-else تو‌در‌تو است که نوشتن آن‌ها زمان زیادی می‌برد و توسط شخص دیگری نیز قابل خواندن نیست.

راهکار

دستکاری داده‌ها با استفاده از «زبان برنامه‌نویسی پایتون» (Python Programming Language) آسان‌تر است. در این راستا باید بخش‌های آدرس در یک رشته منفرد را پیدا، مجزا و هر یک را در یک ستون جدید ذخیره کرد. برای انجام این کار، از یک API رایگان استفاده خواهد شد. یک گزینه خوب در این زمینه «Google Maps Geocoding API» (+) است.

آنچه که کاربر در نوار جست‌و‌جوی «نقشه گوگل» (Google Map) وارد می‌کند با استفاده از همین «رابط برنامه‌نویسی نرم‌افزار کاربردی» (Application programming interface | API) اغلب به درستی به داده‌های آدرس‌ها تفسیر می‌شوند. با وجود محدودیت‌های مشخصی که برای استفاده از این API وجود دارد (+)، Geocoding API به طور کامل رایگان است و می‌توان آن را بدون پرداخت هزینه نصب کرد. پس از نصب لازم است که هر کاربر کلید API خود را در این مسیر (+) اعلام کند.

راهنمای گام به گام

در ادامه، راهنمای گام به گام تبدیل داده‌های بدون ساختار آدرس به داده‌های ساختار یافته ارائه شده است.

۱. مخازن

ابتدا، ماژول‌هایی که به تعامل با رابط برنامه‌نویسی نرم‌افزار کاربردی (requests) کمک می‌کند ایمپورت، داده‌ها بارگذاری (json، CSV) و پیشرفت کار پیگیری می‌شود (tqdm).

1import requests
2import json
3import csv
4from tqdm import *

۲. واکشی آدرس‌ها از ستون‌های CSV

یک تابع برای دریافت آدرس‌ها از CSV و ذخیره‌سازی آن‌ها در یک آرایه ساخته می‌شود. تنها ورودی‌های این تابع path و column هستند.

1def addresses_from_csv(path=None, column=None):
2        
3    addresses = []
4
5    with open(path, 'r') as f:
6        reader = csv.reader(f)
7        for row in reader:
8            addresses.append(row[column])
9            
10    return addresses

۳. مقداردهی اولیه

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

1# Get addresses from CSV
2addresses = addresses_from_csv(path='path/to/your/file.csv', column=0)
3
4# Set Google Maps API key
5api_key = YOUR_API_KEY
6
7# Initialize array for transformed addresses
8transformed = []
9transformed.append(['Country', 'Post code', 'City', 'Street & No'])

۴. فراخوانی API

اجرای حلقه در آرایه addresses با هر آدرسی به عنوان یک کوئری در یک فراخوانی تنهای API آغاز می‌شود.

کتابخانه requests برای اجرای فراخوانی‌های API مورد استفاده قرار می‌گیرد.

1for query in tqdm(addresses):
2    
3    # API call, storing information as JSON
4    url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' + query + '&lang=en&key=' + api_key
5    r = requests.get(url)
6    data = r.json()

آنچه در ادامه آمده خروجی JSON کد بالا است.

1{
2   "results" : [
3      {
4         "address_components" : [
5            {
6               "long_name" : "221B",
7               "short_name" : "221B",
8               "types" : [ "street_number" ]
9            },
10            {
11               "long_name" : "Baker Street",
12               "short_name" : "Baker St",
13               "types" : [ "route" ]
14            },
15            {
16               "long_name" : "Marylebone",
17               "short_name" : "Marylebone",
18               "types" : [ "neighborhood", "political" ]
19            },
20            {
21               "long_name" : "London",
22               "short_name" : "London",
23               "types" : [ "postal_town" ]
24            },
25            {
26               "long_name" : "Greater London",
27               "short_name" : "Greater London",
28               "types" : [ "administrative_area_level_2", "political" ]
29            },
30            {
31               "long_name" : "England",
32               "short_name" : "England",
33               "types" : [ "administrative_area_level_1", "political" ]
34            },
35            {
36               "long_name" : "United Kingdom",
37               "short_name" : "GB",
38               "types" : [ "country", "political" ]
39            },
40            {
41               "long_name" : "NW1 6XE",
42               "short_name" : "NW1 6XE",
43               "types" : [ "postal_code" ]
44            }
45         ]
46      }

۵. آدرس‌دهی عنصر صحیح در JSON/Dict

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

تنها کافی است به موارد مرزی مانند «داده‌های ناموجود» (missing data) یا داده‌های تگ شده به صورت ناسازگار دقت کرد. گاهی، city به عنوان locality و گاهی به عنوان postal_town ظاهر می‌شود.

1for query in tqdm(addresses):
2    
3    # API call, storing information as JSON
4    url = 'https://maps.googleapis.com/maps/api/geocode/json?address=' + query + '&lang=en&key=' + api_key
5    r = requests.get(url)
6    data = r.json()
7    
8    # clear all values to avoid appending values from previous iterations a second time
9    number = street = country = postal_code = city = '' 
10    
11    # looping over address components in JSON
12    for component in data['results'][0]['address_components']:
13        if 'street_number' in component['types']:
14            number = component['long_name']
15        elif 'route' in component['types']:
16            street = component['long_name']
17        elif 'country' in component['types']:
18            country = component['long_name']
19        elif 'postal_code' in component['types']:
20            postal_code = component['long_name']
21        elif 'locality' in component['types']:
22            city = component['long_name']
23        elif 'postal_town' in component['types']:
24            city = component['long_name']
25        else:
26            continue
27
28    street_and_no = street + ' ' + number
29    transformed.append([country, postal_code, city, street_and_no])

۶. نوشتن نتایج نهایی در فایل CSV

در گام نهایی، از آرایه تبدیل شده استفاده و محتوای آن روی یک فایل CSV نوشته می‌شود.

1with open('transformed_addresses.csv', 'w', newline='', encoding='utf-8') as f:
2    writer = csv.writer(f)
3    for row in transformed:
4        writer.writerow(row)

ماموریت انجام شد!

داده‌های ساختار یافته آدرس

اکنون فایل ساختار یافته آدرس‌ها در فایل CSV وجود دارد. کد کامل این مطلب در گیت‌هاب (+) موجود است. علاقمندان می‌توانند به این کد امتیاز بدهند، آن را فورک کرده و تغییر دهند و یا صرفا از آن استفاده کنند.

اگر مطلب بالا برای شما مفید بوده، آموزش‌های زیر نیز به شما پیشنهاد می‌شود:

^^

بر اساس رای ۳ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
codeburst
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *