1. 程式人生 > >爬取全國所有必勝客餐廳資訊,只需要50行程式碼

爬取全國所有必勝客餐廳資訊,只需要50行程式碼

python自學的同學,需要一個學習的氛圍,加QQ群883444106 小編時不時的會發python的教程和資料。 歡迎小夥伴的加入。小編希望我小夥伴一起學習。
當我剛接觸 Python 時,我已經被 Python 深深所吸引。Python 吸引我的地方不僅僅能用其編寫網路爬蟲,而且能用於資料分析。我能將大量的資料中以圖形化方式呈現出來,更加直觀的解讀資料。

資料分析的前提是有資料可分析。如果沒有資料怎麼辦?一是可以去一些資料網站下載相關的資料,不過資料內容可能不是自己想要的。二是自己爬取一些網站資料。

今天,我就爬取全國各地所有的必勝客餐廳資訊,以便後續做資料分析。

1 爬取目標

我們要爬取的目標是必勝客中國。開啟必勝客中國首頁,進入“餐廳查詢”頁面。在這裡插入圖片描述

我們要爬取的資料內容有城市、餐廳名字、餐廳地址以及餐廳聯絡電話。因為我看到頁面中有地圖,所以頁面一定有餐廳地址的經緯度。因此,餐廳的經緯度也是我們需要爬取的資料。

至於全國有必勝客餐廳的城市列表,我們可以通過頁面的“切換城市”獲取。
在這裡插入圖片描述

2 分析目標頁面在這裡插入圖片描述

在編寫爬蟲程式之前,我都是先對頁面進行簡單分析,然後指定爬取思路。而且對頁面結構進行分析往往會有一些意想不到的收穫。

我們使用瀏覽器的開發者工具對頁面結構進行簡單分析。
在這裡插入圖片描述

我們在 StoreList 頁面中能找到我們所需的資料。這個能確定資料提取的 Xpath 語法。

StoreList 頁面的 Response 內容比較長。我們先不著急關閉頁面,往下看看,找找看是否有其他可利用的內容。最後,我們找到呼叫獲取餐廳列表資訊的 JavaScript 函式程式碼。在這裡插入圖片描述

我們接著搜尋下GetStoreList函式,看看瀏覽器如何獲取餐廳列表資訊的。
在這裡插入圖片描述

從程式碼中,我們可以瞭解到頁面使用 Ajax 方式來獲取資料。頁面以 POST 方式請求地址http://www.pizzahut.com.cn/StoreList/Index。同時,請求還攜帶引數 pageIndex 和 pageSize。

3 爬取思路

經過一番頁面結構分析之後,我們指定爬取思路。首先,我們先獲取城市資訊。然後將其作為引數,構建 HTTP 請求訪問必勝客伺服器來獲取當前城市中所有餐廳資料。

為了方便資料爬取,我將所有城市全部寫入到 cities.txt 中。等要爬取資料時,我們再從檔案中讀取城市資訊。

爬取思路看起來沒有錯,但是還是有個難題沒有搞定。我們每次開啟必勝客的官網,頁面每次都會自動定位到我們所在的城市。如果無法破解城市定位問題,我們只能抓取一個城市資料。

於是乎,我們再次瀏覽首頁,看看能不能找到一些可用的資訊。最終,我們發現頁面的 cookies 中有個 iplocation 欄位。
在這裡插入圖片描述

我將其進行 Url 解碼,得到 深圳|0|0 這樣的資訊。
在這裡插入圖片描述

看到這資訊,我恍然大悟。原來必勝客網站根據我們的 IP 地址來設定初始城市資訊。如果我們能偽造出 iplocation 欄位資訊,那就可以隨便修改城市了。

4 程式碼實現

第一步是從檔案中讀取城市資訊。

全國有必勝客餐廳的城市, 我將城市放到檔案中, 一共 380 個城市

cities = []

def get_cities():
“”" 從檔案中獲取城市 “”" file_name = ‘cities.txt’
with open(file_name, ‘r’, encoding=‘UTF-8-sig’) as file:
for line in file:
city = line.replace(’\n’, ‘’)
cities.append(city)
第二步是依次遍歷 cities 列表,將每個城市作為引數,構造 Cookies 的 iplocation 欄位。

依次遍歷所有城市的餐廳

for city in cities:
restaurants = get_stores(city, count)
results[city] = restaurants
count += 1
time.sleep(2)
然後,我們再以 POST 方式攜帶 Cookie 去請求必勝客伺服器。最後再對返回頁面資料進行提取。

def get_stores(city, count):
“”" 根據城市獲取餐廳資訊 “”"
session = requests.Session()
# 對【城市|0|0】進行 Url 編碼
city_urlencode = quote(city + ‘|0|0’)
# 用來儲存首頁的 cookies
cookies = requests.cookies.RequestsCookieJar()

headers = {
    'User-agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.3964.2 Safari/537.36',
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Host': 'www.pizzahut.com.cn',
    'Cache-Control': 'max-age=0',
    'Connection': 'keep-alive',
}

print('============第', count, '個城市:', city, '============')
resp_from_index = session.get('http://www.pizzahut.com.cn/', headers=headers)
# print(resp_from_index.cookies)
# 然後將原來 cookies 的 iplocation 欄位,設定自己想要抓取城市。
cookies.set('AlteonP', resp_from_index.cookies['AlteonP'], domain='www.pizzahut.com.cn')
cookies.set('iplocation', city_urlencode, domain='www.pizzahut.com.cn')
# print(cookies)

page = 1
restaurants = []

while True:
    data = {
        'pageIndex': page,
        'pageSize': "50",
    }

    response = session.post('http://www.pizzahut.com.cn/StoreList/Index', headers=headers, data=data, cookies=cookies)
    html = etree.HTML(response.text)
    # 獲取餐廳列表所在的 div 標籤
    divs = html.xpath("//div[@class='re_RNew']")
    temp_items = []
    for div in divs:
        item = {}
        content = div.xpath('./@onclick')[0]
        # ClickStore('22.538912,114.09803|城市廣場|深南中路中信城市廣場二樓|0755-25942012','GZH519')
        # 過濾掉括號和後面的內容
        content = content.split('(\'')[1].split(')')[0].split('\',\'')[0]

        if len(content.split('|')) == 4:
            item['coordinate'] = content.split('|')[0]
            item['restaurant_name'] = content.split('|')[1] + '餐廳'
            item['address'] = content.split('|')[2]
            item['phone'] = content.split('|')[3]
        else:
            item['restaurant_name'] = content.split('|')[0] + '餐廳'
            item['address'] = content.split('|')[1]
            item['phone'] = content.split('|')[2]
        print(item)
        temp_items.append(item)

    if not temp_items:
        break
    restaurants += temp_items
    page += 1
    time.sleep(5)
return restaurants

第三步是將城市以及城市所有餐廳資訊等資料寫到 Json 檔案中。

with open(‘results.json’, ‘w’, encoding=‘UTF-8’) as file:
file.write(json.dumps(results, indent=4, ensure_ascii=False))
5 爬取結果

程式執行完之後, 就會在當前目錄下生成一個名為「results.json」檔案。

在這裡插入圖片描述

python自學的同學,需要一個學習的氛圍,加QQ群883444106 小編時不時的會發python的教程和資料。 歡迎小夥伴的加入。