├── .gitignore ├── README.md ├── crawler ├── __init__.py ├── clean.py ├── deep.py ├── job_engine.py ├── log4f.py ├── request.py ├── scanner.py ├── settings.py ├── test_cl.py └── wechat.py ├── dianping.py ├── settings.py └── test ├── __init__.py ├── test_tools.py └── testdata.html /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore by JackonYang 2 | 3 | database.sqlite3 4 | cache/* 5 | 6 | 7 | ### Django ### 8 | media/* 9 | static/* 10 | db.sqlite3 11 | local_settings.py 12 | *.log 13 | 14 | 15 | ### python ### 16 | *.py[cod] 17 | __pycache__/ 18 | *.so # C extensions 19 | pip-log.txt # Installer logs 20 | 21 | 22 | ### Vim ### 23 | .ropeproject/* 24 | [._]*.s[a-w][a-z] 25 | [._]s[a-w][a-z] 26 | *~ 27 | 28 | ### Pycharm ### 29 | .idea/* 30 | 31 | 32 | ### Mac ### 33 | .DS_Store 34 | 35 | 36 | # SVN 37 | .svn 38 | 39 | 40 | !PLACEHOLDER 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 大众点评爬虫 2 | ============ 3 | 4 | 抓取页面: 5 | 6 | 1. shop profile 7 | 2. shop review 8 | 3. user profile 9 | 10 | 11 | ## 用法 12 | 13 | #### Scanner 14 | 15 | 以 shop review 为例, 下载的数据保存在 16 | `/home/jackon/media/dianping/reviews` 目录下. 17 | 希望从 reviews 页面中找出所有的 user-id 18 | 19 | ```python 20 | import re 21 | from scanner import Scanner 22 | 23 | uid_ptn = re.compile(r'href="/member/(\d+)(?:\?[^"]+)?"') 24 | json_name = 'uid.json' 25 | 26 | s = Scanner(json_name, uid_ptn) 27 | s.scan('/home/jackon/media/dianping/reviews') 28 | 29 | for k, v in s.data.items(): 30 | print '{} items in {}'.format(len(v), k) 31 | ``` 32 | 33 | 扫描完成后输出如下格式: 34 | ```shell 35 | 20 items in 6845514_1.html 36 | 20 items in 550426_18.html 37 | 0 items in 3926803_2.html 38 | 20 items in 4550817_72.html 39 | 0 items in 6006104_3.html 40 | 0 items in 22281825_3.html 41 | 20 items in 2817364_18.html 42 | 20 items in 18221165_1.html 43 | 20 items in 550099_10.html 44 | 20 items in 21293756_2.html 45 | 20 items in 586687_31.html 46 | 20 items in 20815806_10.html 47 | ``` 48 | 49 | 50 | #### 压缩 / 解压数据的 shell 命令 51 | 52 | ```shell 53 | $ time 7z x shop_prof_20150821.7z 54 | # Folders: 1 55 | # Files: 164805 56 | # Size: 18068875270 57 | # Compressed: 359098116 58 | 59 | # real 164m37.408s 60 | # user 18m2.913s 61 | # sys 39m50.784s 62 | $ ls shop_prof | wc -l 63 | # 164805 64 | 7z l shop_prof_20150821.7z | grep '.html' | wc -l 65 | # 164805 66 | ``` 67 | -------------------------------------------------------------------------------- /crawler/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackonYang/dianping-crawler/f01abb31b11fcb6a469042d339112a2c6779f29a/crawler/__init__.py -------------------------------------------------------------------------------- /crawler/clean.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | __author__ = 'vivian' 3 | import re 4 | import os 5 | import json 6 | 7 | from scanner import Scanner 8 | 9 | revp_ptn = re.compile(r'(\d+)_(\d+)') 10 | revp_list = {} 11 | data = {} 12 | ret_ex = [] 13 | ret_vac = [] 14 | path = 'D:\github\data\shop_review' 15 | 16 | uid_ptn = re.compile(r'href="/member/(\d+)(?:\?[^"]+)?"') 17 | filename = 'uid.json' 18 | s = Scanner(filename, uid_ptn) # 找到每个店铺的评价页面的用户id,输出在uid.json中,key为店铺评价页面,values为对应页面的 19 | # 评价的用户id 20 | s.scan(path, save_period=500) 21 | 22 | count = 0 23 | rid = [] 24 | for k, v in s.data.items(): # 店铺评价页面的首页没有评价的店铺。输出在 rid.json中。 25 | if len(v) == 0 and k.endswith('_1.html'): 26 | count += 1 27 | rid.append(k) 28 | print count # 输出符合条件的店铺总数 29 | with open("rid.json",'w ') as fp: 30 | json.dump(rid, fp) 31 | 32 | 33 | for f in os.listdir(path): # 搜索目标文件夹中的文件名(店铺及评价页面),输出在revp.json中 34 | 35 | # key为店铺id,对应的values为爬取到的店铺评价页 36 | revp_ret = revp_ptn.findall(f) 37 | for k,v in revp_ret: 38 | if k in revp_list: 39 | revp_list[k].append(v) 40 | else: 41 | revp_list[k] = [v] 42 | 43 | with open("revp.json",'w') as fp: 44 | json.dump(revp_list,fp) 45 | 46 | with open("uid.json",'r') as fd: 47 | data = json.load(fd) 48 | 49 | for k,v in revp_list.items(): # 找到每个店铺相应的评价最后一页的评价用户id,输出目标文件不存在(ret_ex)和有用户评价的 50 | file = k+'_'+str(len(v))+'.html' # 文件(ret_vac),最终输出保存在result.json中 51 | if file not in data.keys(): 52 | ret_ex.append(file) 53 | elif data[file]!=[]: 54 | ret_vac.append(file) 55 | else: 56 | pass 57 | 58 | js_dic = {'these are not exist!':ret_ex,'these are not empty!':ret_vac} 59 | with open("result.json",'w') as fr: 60 | json.dump(js_dic,fr, indent=4) -------------------------------------------------------------------------------- /crawler/deep.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | import os 3 | import re 4 | import json 5 | 6 | path = 'D:/github/data/shop_review' 7 | info_ptn = re.compile(ur'href="/member/(\d*)">.*?title="(.*?)"',re.DOTALL) # 匹配用户id 和他的贡献值 8 | 9 | err = [] 10 | id_sc = {} 11 | re_id = {} 12 | 13 | for f in os.listdir(path): # 进入一个店铺的一页评论。 14 | filename = path + '/'+f 15 | ids = [] 16 | try: 17 | with open(filename,'r') as fp: 18 | content = ''.join(fp.readlines()) 19 | except: 20 | err.append(filename) # 若打不开文件,将其放入 err 中 21 | else: 22 | info_ret = info_ptn.findall(content) 23 | for id,sc in info_ret: # 找出没有分数的用户,并放入到list,ids中 24 | id_sc[id] = sc 25 | if len(sc) == 0: 26 | ids.append(id) 27 | re_id[f] = ids # 店铺id为key, 最终所求(需要爬主页)的用户id为 values. 28 | 29 | 30 | with open('err.json','w') as fe: # 打不开的文件 31 | json.dump(err,fe,indent=4) 32 | with open('id_sc.json','w') as fi: # 用户及他的贡献值 33 | json.dump(id_sc,fi,indent=4) 34 | with open('re_id.json','w') as fd: # 没有贡献值的用户 35 | json.dump(re_id,fd,indent=4) 36 | -------------------------------------------------------------------------------- /crawler/job_engine.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | import redis 3 | from wechat import send 4 | 5 | from os.path import dirname, join 6 | from log4f import debug_logger 7 | 8 | BASE_DIR = dirname(__file__) 9 | log = debug_logger(join(BASE_DIR, 'log/download'), 'root.download') 10 | 11 | 12 | class JobPool: 13 | def __init__(self, job_name, 14 | host='localhost', port=6379, db=0, 15 | timeout=10): 16 | self.timeout = timeout 17 | self.db = redis.StrictRedis(host, port, db) 18 | self.total_tbl = '{}:total'.format(job_name) 19 | self.todo_tbl = '{}:todo'.format(job_name) 20 | self.name = job_name 21 | 22 | def init_data(self, total, done): 23 | self.db.delete(self.total_tbl) 24 | self.db.delete(self.todo_tbl) 25 | 26 | todo = set(total) - set(done) 27 | 28 | self.db.sadd(self.total_tbl, *total) 29 | self.db.rpush(self.todo_tbl, *todo) 30 | 31 | def count_todo(self): 32 | return self.db.llen(self.todo_tbl) 33 | 34 | def count_total(self): 35 | return self.db.scard(self.total_tbl) 36 | 37 | def run(self, callback, recursive=False): 38 | print '{} start.TODO/Total: {}/{}'.\ 39 | format(self.name, self.count_todo(), self.count_total()) 40 | key = self._next() 41 | while key: 42 | log.info('downloading {}-{}'.format(self.name, key)) 43 | try: 44 | items = callback(key) 45 | log.info( 46 | '{} items in {}-{}'.format( 47 | len(items), self.name, key)) 48 | if len(items) == 0: 49 | send(u'Warning! May be banned. key={}'.format(key)) 50 | if recursive: 51 | self._add(*items) 52 | except Exception as e: 53 | log.error('{}. ID={}'.format(e, key)) 54 | send(u'Info! meet exceptions. key={}, err={}'.format(key, e)) 55 | self.db.rpush(self.todo_tbl, key) 56 | key = self._next() 57 | 58 | info = '{} done. {} got'.format(self.name, self.count_total()) 59 | print(info) 60 | log.warning(info) 61 | 62 | def _next(self): 63 | key = self.db.blpop(self.todo_tbl, self.timeout) 64 | return key and key[1] 65 | 66 | def _add(self, *keys): 67 | for item in keys: 68 | if self.db.sadd(self.total_tbl, item): 69 | self.db.rpush(self.todo_tbl, item) 70 | 71 | 72 | if __name__ == '__main__': 73 | job_name = 'job_test' 74 | total = [str(i) for i in range(1, 9)] 75 | done = [str(i) for i in range(3, 9, 2)] 76 | 77 | job = JobPool(job_name, db=9, timeout=2) 78 | 79 | job.init_data(total, done) 80 | job.run(lambda key: [11, 12]) 81 | 82 | job.init_data(total, done) 83 | job.run(lambda key: [11, 12], recursive=True) 84 | -------------------------------------------------------------------------------- /crawler/log4f.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | """log in 4 files""" 3 | import logging 4 | import os 5 | 6 | 7 | DEFAULT_LOG_LEVEL = logging.DEBUG 8 | 9 | 10 | def get_4f_logger(formatter, path, name=''): 11 | log = logging.getLogger(name) 12 | log.setLevel(DEFAULT_LOG_LEVEL) 13 | 14 | if not os.path.exists(path): 15 | os.makedirs(path) 16 | 17 | lvls = ['debug', 'info', 'warn', 'error'] 18 | 19 | for lvl in lvls: 20 | logfile = os.path.join(path, '{}.log'.format(lvl.lower())) 21 | hdlr = logging.FileHandler(logfile) 22 | hdlr.setLevel(getattr(logging, lvl.upper())) 23 | hdlr.setFormatter(formatter) 24 | log.addHandler(hdlr) 25 | return log 26 | 27 | 28 | def debug_logger(log_dir='log', logger_name='debug'): 29 | log_format = ('%(asctime)s|%(levelname)s|%(message)s' 30 | '|%(filename)s-%(lineno)s') 31 | return get_4f_logger(logging.Formatter(log_format), log_dir, logger_name) 32 | 33 | 34 | if __name__ == '__main__': 35 | log = debug_logger() 36 | log.error('test log') 37 | log.info('info log') 38 | -------------------------------------------------------------------------------- /crawler/request.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | import re 3 | import redis 4 | import socket 5 | from httplib2 import Http 6 | 7 | import time 8 | import random 9 | 10 | from os.path import dirname, join 11 | from log4f import debug_logger 12 | import settings 13 | 14 | BASE_DIR = dirname(__file__) 15 | log = debug_logger(join(BASE_DIR, 'log/request'), 'root.request') 16 | 17 | r = redis.StrictRedis(**settings.REDIS_CONN) 18 | 19 | 20 | def wait(f): 21 | lock_name = 'http-lock' 22 | 23 | def _wrap_func(*args, **kwargs): 24 | t = r.ttl(lock_name) 25 | if t > 0: 26 | time.sleep(t) 27 | 28 | n_t = int(random.uniform(settings.DELAY_BOTTOM, settings.DELAY_TOP)) 29 | r.setex(lock_name, n_t, 'locking') 30 | return f(*args, **kwargs) 31 | return _wrap_func 32 | 33 | headers_templates = { 34 | 'Connection': 'keep-alive', 35 | 'User-Agent': ('Mozilla/5.0 (X11; Linux x86_64)' 36 | 'AppleWebKit/537.36 (KHTML, like Gecko)' 37 | 'Chrome/44.0.2403.125 Safari/537.36'), 38 | 'Content-type': 'application/x-www-form-urlencoded', 39 | 'Accept': '*/*', 40 | 'Accept-Charset': 'UTF-8,*;q=0.5', 41 | 'Accept-Encoding': 'gzip,deflate,sdch', 42 | 'Accept-Language': 'zh-CN,zh;q=0.8', 43 | 'Cache-Control': 'no-cache', 44 | 'Host': 'www.dianping.com', 45 | 'Referer': 'http://www.dianping.com/', 46 | 'DNT': '1', 47 | } 48 | 49 | 50 | @wait 51 | def request(url, timeout=2, method='GET', filename=None): 52 | """return None if timeout""" 53 | h = Http(timeout=timeout) 54 | try: 55 | log.debug('request {}'.format(url)) 56 | rsp, content = h.request(url, method, headers=headers_templates) 57 | except socket.timeout: 58 | return None 59 | 60 | if filename: 61 | with open(filename, 'w') as f: 62 | f.write(content) 63 | log.debug('response saved. filename={}'.format(filename)) 64 | 65 | return content 66 | 67 | 68 | def request_pages(key, page_range, url_ptn, find_items, resend=3, 69 | min_num=0, max_failed=5, filename_ptn=None): 70 | """request a list of pages in page_range 71 | 72 | """ 73 | items_total = set() # items will be out of order if some pages failed 74 | failed = set() 75 | 76 | for page in page_range: 77 | 78 | filename = filename_ptn and filename_ptn.format(key, page) 79 | page_url = url_ptn.format(key=key, page=page) 80 | content = request(page_url, filename=filename) 81 | 82 | if content is not None: 83 | items_page = find_items(content, key) 84 | if items_page and len(items_page) > min_num: 85 | items_total.update(items_page) 86 | else: 87 | log.debug('nothing in page {} of {}'.format(page, key)) 88 | break 89 | else: 90 | log.warning('failed to request page {} of {}'.format(page, key)) 91 | failed.add(page) 92 | if len(failed) > max_failed: 93 | log.error('more timeout than {}'.format(max_failed)) 94 | return 95 | 96 | if failed: 97 | if not resend: 98 | return None 99 | log.debug('resend failed pages of {}'.format(key)) 100 | items_more = request_pages(key, failed, url_ptn, find_items, 101 | resend-1, min_num, filename_ptn) 102 | if items_more is None: 103 | return None 104 | items_total.update(items_more) 105 | return items_total 106 | 107 | 108 | if __name__ == '__main__': 109 | 110 | url = 'http://www.dianping.com/shop/{key}/review_more?pageno={page}' 111 | find_uid = lambda content, key: \ 112 | re.compile(r'href="/member/(\d+)">(.+?)').findall(content) 113 | 114 | uid = '5195730' # 45 reviews on 2015.8.3 115 | pages = range(1, 9) 116 | 117 | ret = request_pages(uid, pages, url, find_uid, resend=3, 118 | min_num=0, max_failed=5, filename_ptn=None) 119 | for user, name in ret: 120 | print user, name 121 | print len(ret) 122 | -------------------------------------------------------------------------------- /crawler/scanner.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | import re 3 | import os 4 | from os.path import join 5 | import json 6 | 7 | 8 | class Scanner: 9 | def __init__(self, cache_filename, ptn): 10 | self.cache_name = cache_filename 11 | self.ptn = ptn 12 | self.data = self.load() 13 | 14 | def scan(self, path, save_period=2000): 15 | print 'scan {}'.format(path) 16 | total = {fn for fn in os.listdir(path) 17 | if os.path.isfile(join(path, fn))} 18 | todo = total - set(self.data.keys()) 19 | 20 | print 'scanning {}/{}'.format(len(todo), len(total)) 21 | for i, filename in enumerate(todo): 22 | with open(join(path, filename), 'r') as f: 23 | c = ''.join(f.readlines()) 24 | self.data[filename] = list(set(self.ptn.findall(c))) 25 | 26 | if i % save_period == 0: 27 | print '...saving. {} done.'.format(i+1) 28 | self.save() 29 | 30 | self.save() 31 | print 'scan finished. {} new files.'.format(len(todo)) 32 | 33 | def load(self): 34 | data = dict() 35 | if os.path.exists(self.cache_name): 36 | with open(self.cache_name, 'r') as fr: 37 | data = json.load(fr) 38 | return data 39 | 40 | def save(self): 41 | with open(self.cache_name, 'wb') as fw: 42 | json.dump(self.data, fw, indent=4) 43 | 44 | 45 | if __name__ == '__main__': 46 | fn = 'test.json' 47 | if os.path.exists(fn): 48 | os.remove(fn) 49 | 50 | ptn = re.compile(r'import (\w+)') 51 | s = Scanner(fn, ptn) 52 | 53 | s.scan('.', save_period=7) 54 | print '----------' 55 | s.scan('.', save_period=7) 56 | print '----------' 57 | s.scan('..', save_period=7) 58 | -------------------------------------------------------------------------------- /crawler/settings.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | REDIS_CONN = { 3 | 'host': '127.0.0.1', 4 | 'port': 6379, 5 | 'db': 8, 6 | } 7 | 8 | WECHAT_CONN = { 9 | 'username': '', 10 | 'password': '', 11 | } 12 | 13 | DELAY_BOTTOM = 5 14 | DELAY_TOP = 10 15 | 16 | NOTIFY_IDS = [ 17 | '2271762240', # k 18 | '98160640', # v 19 | ] 20 | 21 | MSG_SIGNATURE = 'AutoSend by Dianping Crawler' 22 | 23 | 24 | try: 25 | from local_settings import * 26 | except Exception as e: 27 | pass 28 | -------------------------------------------------------------------------------- /crawler/test_cl.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | __author__ = 'vivian' 3 | import re 4 | import os 5 | import json 6 | 7 | from scanner import Scanner 8 | 9 | revp_ptn = re.compile(r'(\d+)_(\d+)') 10 | revp_list = {} 11 | for f in os.listdir('D:\github\data\shop_review'): 12 | revp_ret = revp_ptn.findall(f) 13 | for k,v in revp_ret: 14 | if k in revp_list: 15 | revp_list[k].append(v) 16 | else: 17 | revp_list[k] = [v] 18 | with open("revp.json",'a') as fp: 19 | json.dump(revp_list,fp) 20 | 21 | 22 | 23 | 24 | #sid_ptn = re.compile('') -------------------------------------------------------------------------------- /crawler/wechat.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | import json 3 | import redis 4 | from os.path import join, dirname 5 | from wechat_sdk import WechatExt 6 | # from wechat_sdk.exceptions import NeedLoginError 7 | 8 | from log4f import debug_logger 9 | import settings 10 | 11 | 12 | LOGIN_TIMEOUT = 4 * 3600 # 4 hours 13 | r = redis.StrictRedis(**settings.REDIS_CONN) 14 | log = debug_logger(join(dirname(__file__), 'log/notify'), 'root.notify') 15 | 16 | 17 | def login(username, password): 18 | d = r.get(username) 19 | if d: 20 | log.info('lazy login. use cookie, username={}'.format(username)) 21 | return WechatExt(username, password, login=False, **json.loads(d)) 22 | else: 23 | print username, password 24 | wechat = WechatExt(username, password, login=False) 25 | wechat.login() 26 | log.info('login to wechat server. username={}'.format(username)) 27 | r.setex(username, LOGIN_TIMEOUT, 28 | json.dumps(wechat.get_token_cookies(), indent=4)) 29 | return wechat 30 | 31 | 32 | def init_info(): 33 | rsp_str = login(**settings.WECHAT_CONN).get_user_list() 34 | for u in json.loads(rsp_str)['contacts']: 35 | name = u['nick_name'].encode('utf8') 36 | fakeid = u['id'] 37 | r.set(fakeid, name) 38 | print '{:12} -- {}'.format(fakeid, name) 39 | 40 | 41 | def send(msg_text): 42 | msg = u'{}. {}'.format(msg_text, settings.MSG_SIGNATURE) 43 | for fakeid in settings.NOTIFY_IDS: 44 | name = r.get(fakeid) or fakeid 45 | try: 46 | login(**settings.WECHAT_CONN).send_message(fakeid, msg) 47 | log.info(u'msg sent. user={}'.format(name)) 48 | except: 49 | log.info(u'fail to send msg. user={}'.format(name)) 50 | 51 | 52 | if __name__ == "__main__": 53 | init_info() 54 | # send(u'亲爱的') 55 | -------------------------------------------------------------------------------- /dianping.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | import os 3 | from os.path import join, exists 4 | import re 5 | 6 | from crawler.request import request, request_pages 7 | from crawler.scanner import Scanner 8 | from crawler.job_engine import JobPool 9 | 10 | from settings import cache_root, db 11 | 12 | page_types = ['user_prof', 'shop_prof', 'reviews'] 13 | page_path = {name: join(cache_root, name) for name in page_types} 14 | for path in page_path.values(): 15 | if not exists(path): 16 | os.makedirs(path) 17 | 18 | uid_ptn = re.compile(r'href="/member/(\d+)(?:\?[^"]+)?"') 19 | sid_ptn = re.compile(r'href="/shop/(\d+)(?:\?[^"]+)?"') 20 | rev_ptn = re.compile(r'
67 | 小川里沙 68 | 69 | 70 |
71 |73 | 74 | 口味:3 75 | 环境:3 76 | 服务:3 77 | 人均:60 78 |
79 | 80 |周末晚上准备带老妈吃个啥,就说尝试下这个,是海鲜还不贵,提前用软件排了队,还剩三四桌的时候去了还是等了有四五十分钟,比起排了两三个小时的已经很不错了。
82 | 更多 83 |我们四个人,......
周末晚上准备带老妈吃个啥,就说尝试下这个,是海鲜还不贵,提前用软件排了队,还剩三四桌的时候去了还是等了有四五十分钟,比起排了两三个小时的已经很不错了。
86 | 收起 87 |我们四个人,要了【138大锅+20元牛蛙+5元年糕】还有三个凉菜类。使劲吃才吃完,大锅里鸡爪太多了,最后还剩了可多鸡爪和土豆。总共消费不到三百,人均60。
饮料要了16元一扎的【酸梅汤】很一般,但是便宜。结账说没有发票送了一罐冰峰,所以不要发票的亲可以提前要冰峰。
我觉得两个人小锅足够了大锅咋吃完啊,然后
要的微辣,第一口吃并不是太好吃、越吃越辣,后面比前面好吃,鸡爪很入味,土豆挺好吃,加的牛蛙分量很足,就是牛蛙可能需要调料重加的话略微淡了点。
年糕就算了吧,吃起来有点腥味。还以为是圆圆的年糕呢,结果是普通片片的。可有可无。
蟹肉,蟹钳是敲碎的太方便了,我不太会吃螃蟹这样很好剥,然后肉挺多的越吃越香。
【蓝莓山药】并不好吃太干了。不推荐。
【泰椒乌鸡爪好吃】22元,很爽很辣,就是好像和锅里的鸡爪太重复。
【蔬菜沙拉】很一般啊,感觉里面有超多芝麻酱,不是很清爽,我妈却说还可以。
服务态度都挺好的,靠窗的位置视野很棒,晚上看钟楼别有一番韵味。
和朋友聚餐可以考虑的一家。吃着热闹。
90 |- 喜欢的菜:
91 | -
92 | 鸡爪
93 | 泰椒乌鸡爪
94 | 餐具
95 | 肉蟹煲
96 |
97 |
98 | 99 |128 | 杰西萌_jessiemon 129 | 130 | 131 |
132 |134 | 135 | 口味:3 136 | 环境:3 137 | 服务:3 138 |
139 | 140 |很早以前就想吃啦,但是每次都被门口乌央乌央的排队大军吓了出来。最后电话咨询了店里,每天是5点5分,大众的客户端可以排号,所以定了闹钟抽了号,下了班赶紧过去,这才吃到。......
142 | 更多 143 |很早以前就想吃啦,但是每次都被门口乌央乌央的排队大军吓了出来。最后电话咨询了店里,每天是5点5分,大众的客户端可以排号,所以定了闹钟抽了号,下了班赶紧过去,这才吃到。可惜当时手一抖3个人选了个小桌,略挤,拍照都没地方,下次一定吸取经验。
146 | 收起 147 |地点就在南大街开元西门旁边的楼上,肯德基的旁边。坐电梯上楼,一开门便是。环境是有点工业风格的,桌子摆的很多,稍微有点挤,就这都容不下外面那些排队的。我到的时候小伙伴已经把菜点好了,要了肉蟹煲,加了鸡爪和牛蛙,点了尖椒小皮蛋和蓝莓山药。桌上有放骨头的盘子,也有消毒毛巾和筷子,但是我们桌子太小,摆的好拥挤。
蓝莓山药先上的,蓝莓味道一点都不腻,山药还很脆,不是完全泥状的,几分钟消灭的只剩蓝莓湖。
尖椒小皮蛋味道也很不错,不算辣,不用被尖椒吓到。量还挺大呢
肉蟹煲最后上的,因为小伙伴加的东西多,所以虽然要的小份,但是是按大份的餐具盛的。上面按大份盖了4只螃蟹壳。
其实小份里面的鸡爪已经很多了,加上我不吃鸡爪,所以鸡爪量超标,小伙伴们一直在啃鸡爪,都没时间聊天,我就只负责牛蛙了。牛蛙很新鲜也很嫩,一个人吃一份超过瘾。
肉蟹虽然都在腿和钳子里,但是肉也不少,味道超赞,香辣蟹就是这个味儿。
其他菜品融合了香辣蟹的味道,也都回味无穷,就是土豆这些都在很底下,要自己翻出来。
饮品要了美貌的来自星星的他和她,个人感觉像养乐多加入了绵绵冰的味道,不过还是很赞啦。但是肉蟹煲吃了很容易渴,这么貌美但是不解渴,得要柠檬茶才行。
服务一般,因为人太多了顾不过来,但是也没影响什么。
总体感觉不错,下次挑人少的时候再去。
话说什么时候人少?泪奔,改天翘班去吧。
178 | 小野草 179 | 180 | 181 |
182 |184 | 185 | 口味:4 186 | 环境:4 187 | 服务:4 188 | 人均:45 189 |
190 | 191 |这家拖了几周没写点评 赶紧补上 不然吃过的味道都忘记了~ 上月周末三天正好有65折的活动 于是周天早晨一早起床 随便吃了点就赶紧跑去 就担心人多要排很久的队 【地理位置】位......
193 | 更多 194 |这家拖了几周没写点评 赶紧补上 不然吃过的味道都忘记了~ 上月周末三天正好有65折的活动 于是周天早晨一早起床 随便吃了点就赶紧跑去 就担心人多要排很久的队 【地理位置】位置很好找 就在南大街 208车站下车往南走没多远 众汇美食广场三楼 上面还有王妃家 人真的很多呀 我们是十一点半到的 到了那里有很多人再等座 不过还好不全是等这家的 抽了一个号 显示前面还有两座 算是松了口气 不用等太久 可是谁知道还是等了半个小时 呵呵 很辛苦呀~还好在十二点整吃上啦~~~【服务】服务不错 门口有自助大麦茶 可能因为冲的次数太多 大麦茶没啥味道了 服务员的态度不错 我们就两个人 当说要加年糕时 很好的给我们建议说不用加 因为菜里面有 所以不建议多加 可能吃不完 【口味】刚开始吃 很不错 一共应该是四个螃蟹吧 肉很多 一只螃蟹八条腿 四只螃蟹三十二条腿 八只大钳子~~哈哈 鸡爪炖的很烂很烂 真的属于入口即化的那种 只是因为是肉鸡 我个人不喜欢那种饲料鸡 味道肯定不如土鸡美~~(本人有点太讲究了~~)土豆很烂 非常喜欢 还有年糕也很喜欢吃 豆腐相比较其他两个配菜比较少 没吃到几个 吃到最后有点点咸 但是整体是不错的 我们两人还是没吃完 呵呵提个小意见 就是年糕 可能因为年糕是最后放进去的 再加上时间比较短 所以很多都是两三个黏在一起没有分开的 吃的时候比较影响口味 因为汤汁没有入进去
197 | 收起 198 |201 |- 喜欢的菜:
202 | -
203 | 鸡爪
204 | 肉蟹煲
205 |
206 |
207 | 208 |237 | 奥莉奥莉 238 | 239 |
240 |242 | 243 | 口味:4 244 | 环境:4 245 | 服务:4 246 | 人均:60 247 |
248 | 249 |每天爆满要排队的店,自打知道以后计划要来吃已经过去起码一个多月了,上次去金地看到他家分店要开过来,心里想着一定要去吃啊,就来了。五个人消费了299。人均60。
251 | 更多 252 |地方不难找......
每天爆满要排队的店,自打知道以后计划要来吃已经过去起码一个多月了,上次去金地看到他家分店要开过来,心里想着一定要去吃啊,就来了。五个人消费了299。人均60。
255 | 收起 256 |地方不难找,就在南大街上,从肯德基的电梯上三楼就是。
【肉蟹煲】里面有鸡爪、螃蟹、年糕、土豆、嫩豆腐。
【明虾煲】内容是虾,鸡爪、土豆、豆芽。
两个煲都是小份微辣,味道一样,内容略有差异。分量很足,鸡爪超级软烂,螃蟹虾很新鲜,配菜也很入味好吃。
【凉菜】我们点了毛肚和皮蛋,皮蛋一小碗,上面小变蛋下面青瓜片,看起来小,份量也够吃,汁料味道足。毛肚略辣,也很爽口下饭。
【来自星星的他\她】男他女她分别是蓝柑和西柚口味,冰沙是酸奶的,略甜了…喝到最后有点腻。不过造型美丽,适合拍照。
【酸梅汤】老板实在,冲调的特别浓,足味儿!
火爆也是应该的,口味符合大众审美,服务也很棒,服务员全程笑脸,食材新鲜份量也足。期待曲江新店开业,一定去捧场!
259 |- 喜欢的菜:
260 | -
261 | 明虾煲
262 | 尖椒小皮蛋
263 | 肉蟹煲
264 |
265 |
266 | 267 |296 | 海晴whisper 297 | 298 | 299 |
300 |302 | 303 | 口味:3 304 | 环境:3 305 | 服务:3 306 | 人均:60 307 |
308 | 309 |很久都没有一个排队美食让大家如此不肯罢休。我是5:30到的,门口已经是一大堆人了,我前面有37桌,而且前两个小时几乎是没动过,我们也是不知死活的等到了8:00才进去,就这还不......
311 | 更多 312 |很久都没有一个排队美食让大家如此不肯罢休。我是5:30到的,门口已经是一大堆人了,我前面有37桌,而且前两个小时几乎是没动过,我们也是不知死活的等到了8:00才进去,就这还不是周末,终于等到了脸都气歪了,实在是不能放弃自己已经等的时间,所以大家都不放弃的等下去。众汇广场可谓是美食新天地,很多的有名的店家分店都选在这里。肉蟹煲不是第一家店了,这里的装修是现在最流行的工厂酒吧风,里面是黑漆漆的装修,有观景窗户,可以见到川流不息的南大街,是请外地朋友的好去处。我们就选了最推荐的肉蟹煲,没有另外加料。
315 | 收起 316 |【胖哥俩肉蟹煲】 小锅98元,大锅138元。上面是五只螃蟹,下面垫了鸡爪子、土豆块、豆腐。可以加别的东西明虾和牛蛙都是20块钱。鸡爪子软糯无比,绝对是入口即化的。上面的蟹拆了壳,劈成两半,和垫菜酱料一起煮在一起。有一点辣味儿,酒的味道很重,还加了豆瓣酱。煮过蟹和鸡爪子的汁水配上白饭超级美味。
【来自星星的他/她】 噱头大于味道了,喝到下端还有些甜腻。不推荐点了,觉得就是色素糖水儿配上冰沙。
【生菜沙拉】 给我们送的菜,生菜、西瓜、黄瓜、玉米……配上千岛酱和乌醋,我是不太习惯的,但是大大的一盆还是很有诚意的。
他们家上菜的速度是算快的,现在传照片到朋友圈可以送酸梅汤或者是生菜沙拉。服务还算是不错吧,随叫随到的。有Wi-Fi,停车可以到开元商场的楼下。
319 |- 喜欢的菜:
320 | -
321 | 肉蟹煲
322 |
323 |
324 | 325 |353 | 蓝小巫 354 | 355 | 356 |
357 |359 | 360 | 口味:2 361 | 环境:2 362 | 服务:2 363 | 人均:43 364 |
365 | 366 |最近巨火爆的胖哥俩,DP订座天天一百来桌排队让我望而却步,真心不喜欢凑热闹!昨天中午三点多刚好路过,想着周内人少又不是饭口就上去看看,嘿~果然门口没人排队,窃喜,赶紧......
368 | 更多 369 |最近巨火爆的胖哥俩,DP订座天天一百来桌排队让我望而却步,真心不喜欢凑热闹!昨天中午三点多刚好路过,想着周内人少又不是饭口就上去看看,嘿~果然门口没人排队,窃喜,赶紧告诉门口的服务员我们四位,那位小哥淡定的告诉我~你好,我们中午下班了,您可以抽个下午的号,五点开始营业!好吧,为了口吃的我真是拼了,直接拿号走人~
372 | 收起 373 |【位置】南大街靠近开元南侧的楼,众汇美食广场三楼
【环境】什么风格~求解!混搭吗?五颜六色的钢架,花色地板,涂鸦墙~我真的欣赏不来,有点乱哄哄的仓促感,不能安安静静坐下吃饭的那种~
【菜品】第一次来当然要尝尝招牌啊~肉蟹煲,4个人要了大份微辣138元,有不辣、微辣、中辣、重辣四种可选,可加鸡爪、年糕、明虾、牛蛙,我们又加了一份年糕5元,一份牛蛙20元,上菜速度挺快的,因为我们是第一批吗!一个大不锈钢盆,上面放了六个蟹壳,是表示里面有六只肉蟹吗?看大小和三两重的大闸蟹大小差不多,壳是空的,木有黄也木有肉,可以直接丢掉,尝了第一口我就知道为啥如此火爆了,味道以咸鲜为主,略带麻辣,还有一点回甜,绝对的重口味,接受人群广,应该是为了适应西安市场改良过,否则吃惯了甜口的南方人民能接受这么齁咸的味道!?但真的很有味,蟹脚上肉还算饱满,就是吃起来比较麻烦,好在壳提前拍碎过;鸡爪煮到入口即化,爱的人一定很爱;牛蛙肉还算紧实有弹性,年糕好像煮的欠点火候,锅底铺垫了大块的土豆,已经煮到口感绵软,但因为大所以里面没味,可以蘸汁子吃,吃土豆很容易有饱足感,建议先吃别的!我们没要米饭,所以越吃越咸,回家口渴了好久,不知道是咸还是味精多的缘故。没喝饮料,有自助大麦茶,四个人大份没吃完,剩了三分之一打包了,一共消费171元,人均43元,性价比可以!
376 |- 喜欢的菜:
377 | -
378 | 肉蟹煲
379 |
380 |
381 | 382 |411 | 翻山越岭只为吃 412 | 413 | 414 |
415 |417 | 418 | 口味:3 419 | 环境:3 420 | 服务:3 421 | 人均:80 422 |
423 | 424 |生意好到没朋友啊!去排队的人好多,看到前面等位的人数就醉了!以后去之前一定一定要先约号啊!
426 | 更多 427 |我就是按照大家推荐的菜品点的,肉蟹煲一个,加了虾和牛蛙,以为鸡爪要加的,结......
生意好到没朋友啊!去排队的人好多,看到前面等位的人数就醉了!以后去之前一定一定要先约号啊!
430 | 收起 431 |我就是按照大家推荐的菜品点的,肉蟹煲一个,加了虾和牛蛙,以为鸡爪要加的,结果服务员说里面有,没想到里面这么多,够吃了!很棒!
蟹肉很多,我喜欢吃蟹钳,蟹钳的肉更劲道些,而且不用费力去咬开,这个都是处理开的!白白的肉肉直接就可以吃到!
味道咸中带甜,酱汁味很浓厚!很大一盆,三个人吃吃不完的!大份我觉得4个人吃刚好,因为还要点小菜嘛
这个小菜我觉得蓝莓山药不错,豆干也挺好,点了个野菜,没怎么吃,大家现在都不爱吃野的!有点干~
来自星星的他和她!哈哈~这个名字取得真好!味道过甜!
434 |- 喜欢的菜:
435 | -
436 | 蓝莓山药
437 | 鸡爪
438 | 肉蟹煲
439 |
440 |
441 | 442 |472 | 淡淡de枫枫 473 | 474 | 475 |
476 |478 | 479 | 口味:3 480 | 环境:3 481 | 服务:3 482 |
483 | 484 |首先确实要怪自己太天真,想着五点多到那里应该不用排队了,就没有用那个美味不用等的排队软件,,,结果等到了八点。。。。所以大家一定要用那个提前排队!提前排队!提前排队......
486 | 更多 487 |首先确实要怪自己太天真,想着五点多到那里应该不用排队了,就没有用那个美味不用等的排队软件,,,结果等到了八点。。。。所以大家一定要用那个提前排队!提前排队!提前排队!重要的事情说三遍!
490 | 收起 491 |【地点】钟楼的那个众汇广场,电梯一下来就看到一群人坐在那里排队,旁边就是王妃家的年糕火锅
【环境】整体环境特别的昏暗,也没有注意看到底算是个什么装修风格,不过坐下来后桌子上还挺亮堂的
【服务】服务态度正常吧,点菜上菜买单,好像也没有需要什么服务。我们四个女生要了两个煲,还反复确认我们真的是要两个煲嘛?哈哈
【菜品】之前听说肉蟹煲并不好吃,所以要的是牛蛙煲和明虾煲,个人非常喜欢吃牛蛙,而且小块小块很是入味,肉质也比较鲜美。但是明虾的味道都在壳壳上,虾肉没有什么味道。。。个人非常喜欢吃那个鸡爪,软软糯糯的,用舌头轻轻一剥,肉肉就下来了,超级好吃的!
个人都属于重口味的了,但是吃这个还是得要配米饭吃,伴着酱汁吃,就像一大份黄焖鸡米饭一样,超级赞的嘞~
525 | 回忆怎么取名字 526 | 527 | 528 |
529 |531 | 532 | 口味:3 533 | 环境:3 534 | 服务:3 535 |
536 | 537 |终于终于终于吃到了传说中的胖哥俩肉蟹煲,实在实在实在是太太太不容易了!!!现在都流行重要的说三遍,觉得只有这样才足以表达我的心情。
539 | 更多 540 |早在胖哥俩刚开业的时候就很想去吃,......
终于终于终于吃到了传说中的胖哥俩肉蟹煲,实在实在实在是太太太不容易了!!!现在都流行重要的说三遍,觉得只有这样才足以表达我的心情。
543 | 收起 544 |早在胖哥俩刚开业的时候就很想去吃,因为很多小伙伴发的图觉得这样一锅超赞的哎,而且又不远啊,钟楼辣么方便,可惜,现实往往距离想象那么遥远,每次去人都是多到爆,真的是要用爆这个词来形容,想我也是经历过炉鱼绿茶王妃很高兴遇见你的人,却真心觉得没有哪家有胖哥俩那么火爆,持续性火爆。。。
1.位置:在钟楼开元广场后面的众汇美食广场的3楼,这是一家美食城,同层的还有王妃和味千拉面
2.环境:蓝紫光的格调,标志的胖哥俩头像萌萌的
3.服务:可以在大众点评上排号,过号3个有用,他家没有WIFI很不好
4.菜品: 点了推荐的经典的肉蟹煲,里面螃蟹大概六七个吧,都掰开了很方便吃,剩下的大多数是鸡爪,非常烂非常好吃哎,用嘴一吮肉就都下来了,配菜还有土豆和年糕片,土豆比较多,同样也很烂,超级好吃,因为他家的汤汁味道配得很赞,香辣的带点麻麻的味道,要中辣就好,还稍微带点甜的味道,配一碗米饭,淋上去汤汁,拌着饭吃实在太香了~~
酸梅汤有点太甜了,不是很喜欢
感觉两个人如果不是饭量特别大的话点一个煲就够了,不需要再加什么配菜
人均60左右,性价比可以,就是等太久,基本点评排号也是等3小时以上
547 |- 喜欢的菜:
548 | -
549 | 鸡爪
550 | 肉蟹煲
551 |
552 |
553 | 554 |580 | 小日青日青日青 581 | 582 | 583 |
584 |586 | 587 | 口味:3 588 | 环境:3 589 | 服务:3 590 | 人均:70 591 |
592 | 593 |可算是吃上了慕名已久的胖哥俩肉蟹煲了 盼星星盼月亮盼到了今天啊。跟两个朋友约到周一下午 想着人不会多 可是五点准时到的我们 还是被眼前的人流量惊呆了 超级多人 门口坐的满......
595 | 更多 596 |可算是吃上了慕名已久的胖哥俩肉蟹煲了 盼星星盼月亮盼到了今天啊。跟两个朋友约到周一下午 想着人不会多 可是五点准时到的我们 还是被眼前的人流量惊呆了 超级多人 门口坐的满满的 才五点啊 还是周一…貌似从四点半开始就可以排号了 然后五点放客
599 | 收起 600 |【地址】南大街 众汇广场三层 一上电梯 开门就是 一排排彩色小凳子 密密麻麻都是人 和王妃家是邻居。
【服务】服务员都是挺年轻的 所以干活啥也都比较机灵 态度挺好的 不用担心生意好 服务不行的这种事。
【环境】环境吗 就是现在比较流行的复古工厂风 灯光整体偏暗 我们被安排在靠窗户的位置 虽然拉着窗帘 但是还是很晒 而且相对于木有在窗边的座位 热了许多。
【肉蟹煲】大份138 小份98 我们三个人点了小份 还加了一份明虾 20rmb 一份年糕 5rmb 一份牛蛙 20rmb 但是 重点来了 量 依旧跟其他没加东西的看上去一样大!!! 意思就是你加了东西后 反而减少了锅里本来有的鸡爪 年糕等 所以 真的 强烈建议别加 或者吃完再加 但另加出来! 这次加了东西 比上次没加的鸡爪子和年糕少了特别多 年糕就几片 鸡爪子也是寥寥 土豆量到没减 这点让我非常不满意 。
【小菜】总共要了四份菜 量普遍偏很小 注意是很小 价格看着不贵呢但是对比上量 那就贵的一逼 味道一般 山杏仁野菜还不错吧。
【饮料】要了一杯来自星星的她 像极了优酸乳的口感 酸梅汤一扎 大概能倒四五杯的样子 味道有些淡
总体还是不错的 但是希望店家不要因为生意好就偷工减料 不如之前开业的时候好了 如果想去早早去 避免高峰排队 辣度 能吃辣的就选择特辣吧 会辣的挺happy的。