0x00 需求与思路

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

0x01 过滤条件

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

0x02 网页解构分析

  2.1 策略

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

python大众点评数据爬取 大众点评数据采集_python

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

  2.2 操作

python大众点评数据爬取 大众点评数据采集_python大众点评数据爬取_02

  使用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 结果

python大众点评数据爬取 大众点评数据采集_xml_03