Fork me on GitHub 返回顶部

爬取大众点评美食频道店铺信息实践

0x00 需求与思路##

  和老板去天津出差,为老板定制美食攻略。老板要求吃饭的地方最好别离下榻的酒店(位于河东区)太远。
  为了体现吃货本质,又来去方便,在点评网上抓取中心城区以内邻近的几个行政区的餐厅信息,通过添加过滤条件初步筛选出符合我们要求的餐厅,再对这些餐厅的一些属性值进行加权,计算每个餐厅的得分并排名。

0x01 过滤条件##

  • 行车距离:以我们住宿的酒店为原点,行车距离半径8公里以内的餐厅
  • 星级:大于等于4星
  • 行政区:河东区、河西区、河北区、和平区以内的餐厅

0x02 网页解构分析##

2.1 策略###

  选择【天津】【美食】【行政区】【点评最多排序

  观察页面,可以看到每一个行政区从第2页开始,url=第1页的URL+p+页码
  每一页默认有15家餐厅,每一家餐厅都有星级点评数量人均消费地理位置,这些信息我们都需要抽取出来。

2.2 操作###

  使用python的requests包发送页面请求,通过BeautifulSoup来解析。获得页面的html之后,通过正则来抽取以上信息。

0x03 获取行车距离##

  使用百度提供了LBS的API(需要申请开发者认证),使用python的requests包进行接口调用。

0x04 源码实例##

#! /usr/bin/env python3
# -*- coding:utf-8 -*-
import requests
import time
from bs4 import BeautifulSoup as bs
import re
import json

def getDistance(apiurl):# 获取两个地点间的行程距离
    res = requests.get(apiurl)
    js = json.loads(res.text)
    if js["status"] == 0:
		try:
		    if js["result"]["error"] == 0:
				return js["result"]["taxi"]
		except Exception as e:
		    print('CannotGetDistance:' + apiurl, e)
		    return 0
	else:
    	return 0
    	
def getInfo(targeturl):# 解析网页,抽取信息
    starpattern = re.compile(r'sml-str\d\d')  # 星级
    npattern = re.compile(r'<b>[0-9]{1,}</b>')  # 点评数
    with open('result.csv', 'a') as f:
		response = requests.get(targeturl, headers=myheaders)#
		soup = bs(response.text, "lxml")
		shoplist = soup.find_all(class_='txt')
		for eachshop in shoplist:
		    try:
				stars = re.search(starpattern, str(eachshop)).group(0)[7:]
				commentnum = re.search(npattern, str(eachshop)).group(0).split('<b>')[-1].split('</b>')[0]
		    except:
				continue
		    else:
				if int(stars) >= 40:
				    expense = str(eachshop).split('¥')[-1].split('</b>')[0]
				    shopname = str(eachshop).split(r'<h4>')[-1].split('</h4>')[0]
				    addr = str(eachshop).split(r'class="addr">')[-1].split('</span>')[0]

				    origin = '索亚风尚酒店'# 酒店位置
				    ak='这里是你的百度应用AK'
				    # 设置起点即酒店、终点即餐厅、起点所在城市、终点所在城市
				    apiurl = "http://api.map.baidu.com/direction/v1?mode=transit&origin=%s&destination=%s&origin_region=%s&&destination_region=%s&output=json&ak=%s" % (origin, addr, '天津', '天津', ak)
				    queryrslt=getDistance(apiurl)

				    if 0==queryrslt or None==queryrslt:
						continue
				    else:
						if 8.0 >(queryrslt["distance"] / 1000):
						    newline = '' + shopname + ',' + stars + ',' + commentnum + ',' + expense + ',"' + addr + '",'+str(queryrslt["distance"] / 1000)
						    f.write(newline+'\n')
					    
						else:
						    continue



if __name__=='__main__':
    myheaders = {
	"Host": "www.dianping.com",
	"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36",
	"Referer": "http://www.dianping.com/tianjin/food"
    }
    hedongbaseurl = 'http://www.dianping.com/search/category/10/10/r54o10'#河东区url
    hexibaseurl = 'http://www.dianping.com/search/category/10/10/r53o10'#河西区url
    hepingbaseurl = 'http://www.dianping.com/search/category/10/10/r51o10'#和平区url
    hebeibaseurl = 'http://www.dianping.com/search/category/10/10/r55o10'#河北区url
    baseurllist = []
    baseurllist.append(hepingbaseurl)
    baseurllist.append(hexibaseurl)
    baseurllist.append(hedongbaseurl)
    baseurllist.append(hebeibaseurl)

    f = open('result.csv', 'a')
    f.write('店名,星级,点评数,人均消费,地址,距离\n')
    f.close()
    for eacharea in baseurllist:
		getInfo(eacharea)
		for page_index in range(2, 51):
	    	#time.sleep(2)必要的时候控制一下速度
	    	getInfo(eacharea + 'p' + str(page_index))# 构造每个行政区的从第2页到第50页的url

0x05 结果##

posted @ 2017-11-15 13:39  d0main  阅读(663)  评论(0编辑  收藏  举报