1. 程式人生 > >【Python爬蟲實戰專案一】爬取大眾點評團購詳情及團購評論

【Python爬蟲實戰專案一】爬取大眾點評團購詳情及團購評論

1 專案簡介

從大眾點評網收集北京市所有美髮、健身類目的團購詳情以及團購評論,儲存為本地txt檔案。
技術:Requests+BeautifulSoup
以美髮為例:http://t.dianping.com/list/beijing?q=美髮
在這裡插入圖片描述
爬取內容包括:
【團購詳情】團購名稱、原價(最高價)、團購價、銷量,團購裡包含的各個專案的名稱、單價。
【團購評論】包括評論使用者名稱稱、評論星級、評論時間、評論內容。
團購詳情
團購評價

2 程式結構

  1. 從大眾點評團購頁面獲取所有“美髮”、“健身”團購專案id的列表;
  2. 根據團購專案列表逐個獲取每個專案的團購詳情、團購評論;
  3. 儲存資料到本地檔案。

3 爬取前準備工作(以美髮為例)

爬取前需要提前檢視所要爬取資訊的位置—是靜態儲存在html頁面還是通過JavaScript動態生成?
檢視方法
在想要爬取頁面右鍵點選“檢視網頁原始碼”,在原始碼如果能搜尋到即為靜態儲存在html頁面,否則為通過JavaScript動態生成。
經過檢查,團購專案id、團購詳情靜態儲存在html中,團購評價為JavaScript動態生成。

3.1 獲取團購專案id列表、團購詳情

獲取所有團購專案id列表:http://t.dianping.com/list/beijing?q=美髮
獲取id為“6009460”團購詳情:http://t.dianping.com/deal/6009460

3.2 獲取團購評價

由於團購評價資訊由js動態生成,不存在原始碼中,需要動態載入頁面。
解決方案

  1. 在團購評價所在頁面點選F12,依次點選NetworkXHR開啟如下介面;
  2. 向下滑動頁面,直至頁面全部加載出評論資訊;
    在這裡插入圖片描述
  3. 找到下圖中框選的“detailDealRate?..”點選開啟;
    在這裡插入圖片描述
  4. Response中即可看到團購評價的原始碼;
    在這裡插入圖片描述
  5. 點選Headers獲取評論資訊的URL
    在這裡插入圖片描述

3.3 實現爬取過程中的自動翻頁

【團購專案列表頁面】
第一頁URL:http://t.dianping.com/list/beijing?q=美髮
第二頁URL:http://t.dianping.com/list/beijing?q=美髮&pageIndex=1


第三頁URL:http://t.dianping.com/list/beijing?q=美髮&pageIndex=2
嘗試將第一頁URL改成:http://t.dianping.com/list/beijing?q=美髮&pageIndex=0 與原來開啟頁面一樣
【團購評價頁面】
第一頁URL:http://t.dianping.com/ajax/detailDealRate?dealGroupId=6009460&pageNo=1
第二頁URL:http://t.dianping.com/ajax/detailDealRate?dealGroupId=6009460&pageNo=2
找到規律了吧,翻頁時只需修改url中頁碼即可,不同頁面規律不同。

3.4 應對反爬技術

現在大部分網站都對爬蟲進行了限制,伺服器允許人類訪問,不允許“機器”訪問,所以模仿人類的訪問行為就可以解決這一問題。
解決方法:加一個請求頭完全模擬瀏覽器的請求,請求頭獲取見下圖:
在這裡插入圖片描述

4 編寫程式碼

4.1 引入所需要的庫

import requests
import re
import os
import traceback
from bs4 import BeautifulSoup
from fake_useragent import UserAgent
from urllib.parse import quote

4.2 獲取單頁面內容

def getHtmlText(url,refer):
    #模擬瀏覽器頭部資訊應對反爬
    headers = {
                "User-Agent": UserAgent(verify_ssl=False).random,
                "Host":"t.dianping.com",
                "Referer":refer
               }
    try:
        r=requests.get(url,headers=headers)
        r.raise_for_status()
        if (r.encoding != "UTF-8"):
            r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""

4.3 獲取所有團購專案列表

def getDealList(list,url,refer):
    html=getHtmlText(url,refer)
    soup=BeautifulSoup(html,"html.parser")
    for item in soup.find_all("li",attrs={"class":"tg-floor-item"}):
        try:
            deal_id=item.attrs["data-eval-config"]
            list.append(re.findall(r'\d+',deal_id)[0])
        except:
            continue

4.4 獲取團購詳情

def getDealInfo(list,url,refer):
    path="D://deal_info.txt"
    headers=["團購id","團購名稱","原價","團購價","銷量","單項名稱","單項數量","單項單價"]
    for id in list[:3]:  #資料太多,這裡選前三條做demo
        try:
            info=[]
            deal_url=url+id
            html=getHtmlText(deal_url,refer)
            soup=BeautifulSoup(html,"html.parser")

            #爬取團購名稱,原價,團購價,銷量等資訊
            main_info=soup.find("div",attrs={"class":"setmeal-box J_setmeal-box"})
            name=main_info.find("li")
            data=eval(name.attrs["data-eval-config"])#將字串轉換成字典格式
            info.append(id)#團購id
            info.append(data["title"])#團購名稱
            info.append(data["marketPrice"])#原價
            info.append(data["price"])#團購價
            info.append(data["sold"])#銷量

            #爬取團購裡包含的各個專案的名稱、單價等資訊
            detail_info=soup.find("table",attrs={"class":"detail-table"})
            head=detail_info.find("thead")
            head_list=head.find_all("th")
            value=detail_info.find("tbody")
            value_list=value.find_all("td")
            item_num = int(len(value_list) / 3 - 1)  # 三個為一組減去最後一組價格組    num表示團購專案中單項的數量
            for i in range(item_num):
                for j in range(len(head_list)):
                    info.append(re.sub(r'[\r\n" "]', "", value_list[3 * i + j].text))  # 用正則表示式去除多餘的\r\n和空格
            saveInfo(info,path,headers)

        except:
            # 顯示錯誤資訊
            traceback.print_exc()
            continue


4.5 獲取團購評論

def getComInfo(list,url,refer):
    com_path="D://com_info.txt"
    headers=["團購id", "使用者名稱稱", "評論星級", "評論時間", "評論內容"]
    page=2 #爬取評論的頁面數
    #對每一個團購專案的評論
    for id in list[:3]:    #資料太多,這裡選前三條做demo
        #對每一頁評論
        for i in range(page):
                com_url=url+id+"&pageNo="+str(i+1)
                com_html = getHtmlText(com_url,refer+id)
                com_soup = BeautifulSoup(com_html, "html.parser")
                com_tag = com_soup.find_all("li", attrs={"class": "Fix"})
                # 對每一條評論
                for tag in com_tag:
                    try:
                        #儲存每一條評論資訊
                        com_info = []
                        star = tag.find("span", attrs={"class": "star-rating"})
                        com_info.append(id)#團購名稱
                        com_info.append(tag.find("span", attrs={"class": "name"}).text)#使用者名稱稱
                        com_info.append(re.search(r'\d',str(star)).group(0))#評論星級
                        com_info.append(tag.find("span", attrs={"class": "date"}).text)#評論時間
                        cont=tag.find("div", attrs={"class": "J_brief_cont_full Hide"})
                        #如果評論有隱藏資訊
                        if(cont):
                            com_info.append(re.sub(r'[\r\n]',"",cont.text))#評論內容
                        #無隱藏
                        else:
                            com_info.append(re.sub(r'[\r\n]',"",tag.find("div", attrs={"class": "J_brief_cont_full"}).text))#評論內容

                        saveInfo(com_info,com_path,headers)
                    except:
                        #顯示錯誤資訊
                        traceback.print_exc()
                        continue

4.5 儲存資訊到本地txt

def saveInfo(info, path,headers):
    with open(path, "a", encoding="utf-8") as f:
        #獲取檔案大小
        file_size = os.path.getsize(path)
        if file_size == 0:
            # 表頭
            f.write(re.sub(r'[\[\]\']', "",str(headers))+ "\n")
        f.write(re.sub(r'[\[\]\']', "",str(info)) + "\n")

5 執行結果

5.1 團購評論

在這裡插入圖片描述

5.2 團購詳情(美髮、健身各選擇前三條做demo)

在這裡插入圖片描述

寫在最後

本人剛學習爬蟲不久,第一個自己寫的專案做個總結~
如有不盡完善之處,還請各位大佬指出,一起交流,一起進步~~
轉載記得標明出處哦~