Fried Chicken Wars — Memetakan Wilayah Popeyes vs KFC menggunakan Felt

Baru-baru ini, saya pergi makan siang dengan seorang teman yang baru saja pulang ke Orlando. Saat berbicara tentang bagaimana kota itu berkembang, saya menyebutkan kepadanya melihat restoran Popeyes baru buka ke mana pun saya pergi. Dari sudut pandangnya, dia melihat restoran KFC baru dibuka di mana-mana. Aku tahu kami berdua tidak mungkin benar. Kami akhirnya memperdebatkan Rantai Ayam Goreng mana yang memiliki pangsa pasar lebih dominan di Amerika Serikat.
Sebagai hasil dari perdebatan sengit ini, saya mulai menjawab pertanyaan tersebut dengan mengumpulkan data dan membuat visualisasi peta. Di bawah ini saya akan memandu Anda melalui proses saya.
- Mengumpulkan data
Tantangan pertama yang saya hadapi adalah menemukan sumber data yang dapat diandalkan untuk lokasi toko Popeyes dan KFC. Saya menemukan sebuah situs web bernama scrapehero.com yang menawarkan untuk menjual data kepada saya dengan harga $95 untuk kumpulan data satu rantai. Namun, saya tidak akan menghabiskan sekitar $200 untuk menyombongkan diri terhadap teman saya. Setelah menjelajahi situs web Popeyes, sebuah ide muncul di benak saya. Saya ingin tahu apakah saya dapat merekayasa balik API (alias Web Scraping).
Langkah pertama adalah saya membuka alat pengembang dengan mengklik kanan mouse saya dan memeriksanya. Saya melanjutkan untuk menavigasi ke tab Jaringan dan melihat semua permintaan yang masuk. Setelah beberapa penyelidikan, saya menemukan permintaan digunakan untuk mengambil dan mengisi lokasi toko di Antarmuka Pengguna.

Anda dapat menyalin permintaan cURL dan benar-benar mengimpornya ke Postman dan Postman menangani semua pemformatan untuk Anda. Selain itu, Postman memiliki opsi untuk mengekspor permintaan ke dalam bahasa pilihan Anda.


Setelah langkah ini, saya menulis skrip kasar yang akan mengirimkan permintaan dan menyimpannya ke CSV di komputer saya. Hal utama yang saya perhatikan dengan permintaan yang digunakan untuk mengambil semua lokasi toko adalah di dalam payload Anda memiliki beberapa variabel yang dapat Anda mainkan termasuk: userLat, userLng, searchRadius, dan first. Dengan menyesuaikan variabel-variabel ini, saya dapat mengumpulkan data untuk semua 2851 lokasi toko. Pengguna Github meiqimichelle melakukan beberapa pekerjaan berat dengan memberikan koordinat lintang dan bujur dari setiap negara bagian yang akan saya lewati. Saya akan mengambil pendekatan serupa dengan mengumpulkan data toko KFC.
const axios = require('axios');
const ObjectsToCsv = require('objects-to-csv');
const states = require('./constants');
function getPopeyesLocations(){
const promises = []
for( let i = 0; i < states.length; i++){
const state = states[i]
const { latitude : lat, longitude : lon } = state
var data = JSON.stringify([
{
"operationName": "GetRestaurants",
"variables": {
"input": {
"filter": "NEARBY",
"coordinates": {
"userLat": lat,
"userLng": lon,
"searchRadius": 800000
},
"first": 10000,
"status": "OPEN"
}
},
"query": "query GetRestaurants($input: RestaurantsInput) {\n restaurants(input: $input) {\n pageInfo {\n hasNextPage\n endCursor\n __typename\n }\n totalCount\n nodes {\n ...RestaurantNodeFragment\n __typename\n }\n __typename\n }\n}\n\nfragment RestaurantNodeFragment on RestaurantNode {\n _id\n storeId\n isAvailable\n posVendor\n chaseMerchantId\n curbsideHours {\n ...OperatingHoursFragment\n __typename\n }\n deliveryHours {\n ...OperatingHoursFragment\n __typename\n }\n diningRoomHours {\n ...OperatingHoursFragment\n __typename\n }\n distanceInMiles\n drinkStationType\n driveThruHours {\n ...OperatingHoursFragment\n __typename\n }\n driveThruLaneType\n email\n environment\n franchiseGroupId\n franchiseGroupName\n frontCounterClosed\n hasBreakfast\n hasBurgersForBreakfast\n hasCatering\n hasCurbside\n hasDelivery\n hasDineIn\n hasDriveThru\n hasTableService\n hasMobileOrdering\n hasLateNightMenu\n hasParking\n hasPlayground\n hasTakeOut\n hasWifi\n hasLoyalty\n id\n isDarkKitchen\n isFavorite\n isHalal\n isRecent\n latitude\n longitude\n mobileOrderingStatus\n name\n number\n parkingType\n phoneNumber\n physicalAddress {\n address1\n address2\n city\n country\n postalCode\n stateProvince\n stateProvinceShort\n __typename\n }\n playgroundType\n pos {\n vendor\n __typename\n }\n posRestaurantId\n restaurantImage {\n asset {\n _id\n metadata {\n lqip\n palette {\n dominant {\n background\n foreground\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n crop {\n top\n bottom\n left\n right\n __typename\n }\n hotspot {\n height\n width\n x\n y\n __typename\n }\n __typename\n }\n restaurantPosData {\n _id\n __typename\n }\n status\n vatNumber\n __typename\n}\n\nfragment OperatingHoursFragment on OperatingHours {\n friClose\n friOpen\n monClose\n monOpen\n satClose\n satOpen\n sunClose\n sunOpen\n thrClose\n thrOpen\n tueClose\n tueOpen\n wedClose\n wedOpen\n __typename\n}\n"
}
]);
var config = {
method: 'post',
url: 'https://use1-prod-plk.rbictg.com/graphql',
headers: {
'authority': 'use1-prod-plk.rbictg.com',
'accept': '*/*',
'accept-language': 'en-US,en;q=0.9',
'apollographql-client-name': 'wl-web',
'apollographql-client-version': '4ef9144',
'content-type': 'application/json',
'origin': 'https://www.popeyes.com',
'sec-ch-ua': '"Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'cross-site',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36',
'x-forter-token': '4798c310640a4c129119b405583aca62_1669841988907__UDF43_13ck_tt',
'x-session-id': '4C6B1EAF-0D2A-4295-84FB-81CDCDFC25D2',
'x-ui-language': 'en',
'x-ui-platform': 'web',
'x-ui-region': 'US',
'x-user-datetime': '2022-11-30T16:00:05-05:00'
},
data : data
};
promises.push(axios(config))
}
Promise.allSettled(promises).then((res) => {
const popeyes = []
for( let i = 0; i < res.length; i++){
const nodes = res[i].value.data[0].data?.restaurants?.nodes
const restaurants = nodes.map(node => {
return {
id : node?.id, name : 'Popeyes ' + node?.name, lat : node?.latitude, lon : node?.longitude
}
})
restaurants.forEach(restaurant => {
const isInArray = popeyes.find(fRestaurant => fRestaurant.id === restaurant.id )
if( !isInArray){
popeyes.push(restaurant)
}
})
}
const csv = new ObjectsToCsv(popeyes);
csv.toDisk('./Popeyes_Store_Locations.csv');
})
}
getPopeyesLocations();
Popeyes Store Locations CSV
Sekarang bagian yang menyenangkan adalah memetakan semua data yang saya kumpulkan. Saya menggunakan fitur unggah di dalam Felt untuk membuat dua lapisan. Satu untuk Popeyes dan satu lagi untuk KFC.
Dengan hampir 6700+ titik di peta, saya menggunakan panel gaya yang dibuat di dalam Felt untuk menghapus label serta mengecilkan ukuran penanda. Ini penting untuk membersihkan peta agar lebih rapi.

Hasilnya cukup mengejutkan meskipun saya sempat mengintip saat melihat pratinjau datanya. KFC memiliki lebih dari 1000+ restoran lebih banyak daripada Popeyes dan secara visual sangat luar biasa. KFC menelan Popeyes sampai-sampai Anda bahkan tidak bisa melihat penanda Popeyes.
Merasa alat pemetaan yang saya gunakan juga memiliki kemampuan untuk mengaktifkan dan menonaktifkan lapisan dengan mudah.
Catatan Akhir
Data tidak berbohong (dalam banyak kasus). KFC mendominasi Popeyes di Amerika Serikat. Eksperimen pemikiran ini membuat saya berpikir bahwa suatu hari nanti akan menarik untuk menggunakan alat ini untuk memetakan wilayah penjualan serta melakukan analisis tentang apakah Anda harus membuka restoran/bisnis di area tertentu atau tidak.

PS Popeyes lebih unggul dari KFC
Lihat peta di Felt:
Apakah Anda memiliki pertanyaan atau umpan balik? Saya ingin sekali mendengarnya!
email: [email protected]
Indonesia:https://twitter.com/duckduckquy
Dirasakan:https://felt.com/
Github:https://github.com/duckduckquy/popeyesScraper
Sumber Data Bujur Lat :https://gist.github.com/meiqimichelle/7727723