通過python選擇美食店

在我們日常生活中,當需要尋找美食的時候,通常都是通過美團、大衆點評搜索,然後看下大家的評論,然後再決定是否選擇這家店。這對我們來說是比較方面省時的。

之前接過一個單子就是需要採集大衆點評商家評論的,今天我們就拿來分享交流下。一般這樣的網站反爬策略都是很嚴的,如果爬蟲技術不行,或者反爬策略做的不夠好是沒法採集到數據的。因爲大衆點評的反爬措施,需要設置IP代理以及隨機切換可用的User-Agent來進行大量數據的爬取。說到代理這裏就分享下,我之前使用的是億牛雲的爬蟲代理,因爲要採集這個網站,他們還免費給我提供了一份ua庫,用過市面上不少的代理,只有他們家站在客戶的角度考慮,希望客戶能更好的採集數據,這點真的是很讚的。

關於採集大衆點評的完整代碼如下:

"""
Version: Python3.5

"""
import re
import time
import requests
from lxml import etree
from fake_useragent import UserAgent


class DianPing:
    def __init__(self):
        self.url = "http://www.dianping.com/wuhan/ch10"
        self.ua = UserAgent()
        self.headers = {
            "Cookie": "s_ViewType=10; _lxsdk_cuid=167ca93f5c2c8-0c73da94a9dd08-68151275-1fa400-167ca93f5c2c8; _lxsdk=167ca93f5c2c8-0c73da94a9dd08-68151275-1fa400-167ca93f5c2c8; _hc.v=232064fb-c9a6-d4e0-cc6b-d6303e5eed9b.1545291954; cy=16; cye=wuhan; td_cookie=686763714; _lxsdk_s=%7C%7CNaN",
            "User-Agent": self.ua.random  # 獲取隨機的User-Agent
        }
        self.dic = {}  # class-digit字典

    def get_page(self):
        res = requests.get(self.url, headers=self.headers)
        s = etree.HTML(res.text)
        title_list = s.xpath('//*[@id="shop-all-list"]/ul/li/div[2]/div[1]/a[1]/@title')  # 標題
        dish_list = []  # 招牌菜
        if len(title_list):
            self.get_dict(res.text)
            for i in range(len(title_list)):
                dish_list.append(s.xpath('//*[@id="shop-all-list"]/ul/li[{}]/div[2]/div[4]/a/text()'.format(i + 1))[0])
            score1_list = self.get_score(res.text, len(title_list), 1)  # 口味評分
            score2_list = self.get_score(res.text, len(title_list), 2)  # 環境評分
            score3_list = self.get_score(res.text, len(title_list), 3)  # 服務評分
            for i in range(len(title_list)):
                info = {
                    "店名": title_list[i],
                    "口味評分": score1_list[i],
                    "環境評分": score2_list[i],
                    "服務評分": score3_list[i],
                    "招牌菜": dish_list[i]
                }
                print(info)
        else:
            print("Error!")

    def get_dict(self, html):
        # 提取css文件的url
        css_url = "http:" + re.search('(//.+svgtextcss.+\.css)', html).group()
        css_res = requests.get(css_url)
        # 這一步得到的列表內容爲css中class的名字及其對應的偏移量
        css_list = re.findall('(un\w+){background:(.+)px (.+)px;', '\n'.join(css_res.text.split('}')))
        # 過濾掉匹配錯誤的內容,並對y方向上的偏移量初步處理
        css_list = [[i[0], i[1], abs(float(i[2]))] for i in css_list if len(i[0]) == 5]
        # y_list表示在y方向上的偏移量,完成排序和去重
        y_list = [i[2] for i in css_list]
        y_list = sorted(list(set(y_list)))
        # 生成一個字典
        y_dict = {y_list[i]: i for i in range(len(y_list))}
        # 提取svg圖片的url
        svg_url = "http:" + re.findall('class\^="un".+(//.+svgtextcss.+\.svg)', '\n'.join(css_res.text.split('}')))[0]
        svg_res = requests.get(svg_url)
        # 得到svg圖片中的所有數字
        digits_list = re.findall('>(\d+)<', svg_res.text)
        for i in css_list:
            # index表示x方向上的索引(最小的索引值是0)
            index = int((float(i[1]) + 7) / -12)
            self.dic[i[0]] = digits_list[y_dict[i[2]]][index]

    def get_score(self, html, l, x):
        """
        :param html: 網頁源碼
        :param l: 迭代長度
        :param x: 1或2或3
        :return: 評分列表
        """
        s = etree.HTML(html)
        num_list = []
        for i in range(l):
            t = s.xpath('//*[@id="shop-all-list"]/ul/li[{}]/div[2]/span/span[{}]/b/text()'.format(i + 1, x))[0]
            c = s.xpath('//*[@id="shop-all-list"]/ul/li[{}]/div[2]/span/span[{}]/b/span/@class'.format(i + 1, x))
            num = self.dic[c[0]] + '.' + self.dic[c[1]] if t == '.' else self.dic[c[0]] + '.1'
            num_list.append(num)
        return num_list


if __name__ == '__main__':
    dp = DianPing()
    dp.get_page()

以上只是簡單的一些分享,如果有更好的方法大家可以留言交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章