在我們日常生活中,當需要尋找美食的時候,通常都是通過美團、大衆點評搜索,然後看下大家的評論,然後再決定是否選擇這家店。這對我們來說是比較方面省時的。
之前接過一個單子就是需要採集大衆點評商家評論的,今天我們就拿來分享交流下。一般這樣的網站反爬策略都是很嚴的,如果爬蟲技術不行,或者反爬策略做的不夠好是沒法採集到數據的。因爲大衆點評的反爬措施,需要設置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()
以上只是簡單的一些分享,如果有更好的方法大家可以留言交流。