สงครามไก่ทอด — ทำแผนที่ Popeyes กับ KFC Territory โดยใช้ Felt
![](https://post.nghiatu.com/assets/images/m/max/724/1*-bReSw8jQQ5VxiyhpEfMig.png)
เมื่อเร็ว ๆ นี้ ฉันออกไปทานอาหารกลางวันกับเพื่อนที่เพิ่งย้ายกลับบ้านที่ออร์แลนโด ขณะที่พูดคุยเกี่ยวกับพัฒนาการของเมือง ฉันเล่าให้เขาฟังว่าเห็นร้านอาหาร Popeyes ใหม่ๆ เปิดขึ้นทุกที่ที่ฉันไป จากมุมมองของเขา เขาเคยเห็นร้านเคเอฟซีเปิดใหม่ทุกที่ ฉันรู้ว่าเราทั้งคู่ไม่ถูกกัน เราลงเอยด้วยการถกเถียงกันว่าร้านไก่ทอดร้านใดมีส่วนแบ่งการตลาดที่โดดเด่นกว่าในสหรัฐอเมริกา
จากการถกเถียงอย่างเผ็ดร้อนนี้ ฉันจึงเริ่มตอบคำถามด้วยการรวบรวมข้อมูลและสร้างภาพแผนที่ ด้านล่างนี้ฉันจะแนะนำคุณตลอดกระบวนการของฉัน
- รวบรวมข้อมูล
ความท้าทายแรกที่ฉันมีคือการหาแหล่งข้อมูลที่เชื่อถือได้สำหรับตำแหน่งร้านของ Popeyes และ KFC ฉันพบเว็บไซต์ชื่อ scrapehero.com ซึ่งเสนอขายข้อมูลให้ฉันในราคา 95 ดอลลาร์สำหรับชุดข้อมูลของเชนหนึ่ง อย่างไรก็ตาม ฉันไม่ได้กำลังจะใช้เงินประมาณ 200 ดอลลาร์เพื่อคุยโม้กับเพื่อนของฉัน หลังจากสำรวจเว็บไซต์ Popeyes ความคิดหนึ่งก็แล่นเข้ามาในหัวของฉัน ฉันสงสัยว่าฉันสามารถทำวิศวกรรมย้อนกลับ API (หรือที่เรียกว่า Web Scraping) ได้หรือไม่
ขั้นตอนแรกคือฉันเปิดเครื่องมือสำหรับนักพัฒนาโดยคลิกขวาที่เมาส์แล้วตรวจสอบ ฉันไปที่แท็บเครือข่ายและดูคำขอที่เข้ามาทั้งหมด หลังจากตรวจสอบแล้ว ฉันพบคำขอที่ใช้เพื่อดึงข้อมูลและเติมตำแหน่งร้านค้าบนส่วนต่อประสานผู้ใช้
![](https://post.nghiatu.com/assets/images/m/max/724/1*QPd3hgE8mX4BDapuY2BJBQ.png)
คุณสามารถคัดลอกคำขอ cURL และนำเข้าสู่บุรุษไปรษณีย์และบุรุษไปรษณีย์จะจัดการการจัดรูปแบบทั้งหมดให้กับคุณ นอกจากนี้ บุรุษไปรษณีย์ยังมีตัวเลือกที่คุณสามารถส่งออกคำขอเป็นภาษาที่คุณเลือกได้
![](https://post.nghiatu.com/assets/images/m/max/724/1*OuaCjZ8yBZ7ZTmkf4ybe5Q.png)
![](https://post.nghiatu.com/assets/images/m/max/724/1*DkQ6zxQYz_w1PnjUaCXdpA.png)
หลังจากขั้นตอนนี้ ฉันได้เขียนสคริปต์คร่าว ๆ ซึ่งจะส่งคำขอและบันทึกเป็น CSV บนคอมพิวเตอร์ของฉัน สิ่งสำคัญที่ฉันสังเกตเห็นจากคำขอที่ใช้ในการดึงตำแหน่งที่ตั้งร้านค้าทั้งหมดนั้นอยู่ในเพย์โหลดที่คุณมีตัวแปรสองสามตัวที่คุณสามารถลองใช้งานได้ ซึ่งรวมถึง: userLat, userLng, searchRadius และตัวแรก การปรับแต่งตัวแปรเหล่านี้ทำให้ฉันสามารถรวบรวมข้อมูลสำหรับที่ตั้งร้านค้าทั้งหมด 2851 แห่งได้ ผู้ใช้ Github meiqimichelle ทำการยกของหนักด้วยการระบุพิกัดละติจูดและลองจิจูดของทุกรัฐที่ฉันจะวนซ้ำ ฉันจะใช้วิธีการที่คล้ายกันกับการรวบรวมข้อมูลร้าน 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
ตอนนี้ส่วนที่สนุกคือการแมปข้อมูลทั้งหมดที่ฉันรวบรวม ฉันใช้ฟีเจอร์อัปโหลดภายใน Felt เพื่อสร้างเลเยอร์สองชั้น หนึ่งอันสำหรับ Popeyes และอีกอันสำหรับ KFC
ด้วยจุดเกือบ 6,700+ จุดบนแผนที่ ฉันใช้แผงจัดแต่งภายใน Felt เพื่อลบป้ายกำกับและลดขนาดเครื่องหมาย นี่เป็นสิ่งสำคัญในการทำความสะอาดแผนที่เพื่อให้ดูเรียบร้อยยิ่งขึ้น
![](https://post.nghiatu.com/assets/images/m/max/724/1*Ub8LnfV3_q7UA67LH_zlFA.png)
ผลลัพธ์ค่อนข้างน่าตกใจแม้ว่าฉันจะแอบมองเมื่อฉันดูตัวอย่างข้อมูล KFC มีร้านอาหารมากกว่า 1,000 แห่งมากกว่า Popeyes และดูเหมือนว่าจะล้นหลาม KFC กลืน Popeyes เข้าไปจนไม่เห็นเครื่องหมายของ Popeyes เลย
รู้สึกว่าเครื่องมือทำแผนที่ที่ฉันใช้ยังมีความสามารถในการเปิดและปิดเลเยอร์ได้อย่างง่ายดายเช่นกัน
หมายเหตุสุดท้าย
ข้อมูลไม่โกหก (ในกรณีส่วนใหญ่) KFC ครอง Popeyes ในสหรัฐอเมริกา อย่างไรก็ตาม การทดลองทางความคิดนี้ทำให้ฉันคิดว่าสักวันหนึ่งอาจใช้เครื่องมือนี้ทำแผนที่พื้นที่ขายและวิเคราะห์ว่าคุณควรเปิดร้านอาหาร/ธุรกิจในพื้นที่ใดพื้นที่หนึ่งหรือไม่
![](https://post.nghiatu.com/assets/images/m/max/724/1*PgnUFYXbfb1QWz25BuYBDw.png)
ปล.ป๊อปอายส์เหนือกว่าเคเอฟซี
ตรวจสอบแผนที่บน Felt:
คุณมีคำถามหรือข้อเสนอแนะ? ฉันชอบที่จะได้ยินมัน!
อีเมล์: [email protected]
ทวิตเตอร์:https://twitter.com/duckduckquy
รู้สึก:https://felt.com/
Github:https://github.com/duckduckquy/popeyesScraper
ลาดยาว แหล่งข้อมูล :https://gist.github.com/meiqimichelle/7727723