100行代码爬取全国所有必胜客餐厅信息

阅读文本大概需要 10 分钟。

当我刚接触 Python 时,我已经被 Python 深深所吸引。Python 吸引我的地方不仅仅能用其编写网络爬虫,而且能用于数据分析。我能将大量的数据中以图形化方式呈现出来,更加直观的解读数据。

数据分析的前提是有数据可分析。如果没有数据怎么办?一是可以去一些数据网站下载相关的数据,不过数据内容可能不是自己想要的。二是自己爬取一些网站数据。

今天,我就爬取全国各地所有的必胜客餐厅信息,以便后续做数据分析。

01

抓取目标

我们要爬取的目标是必胜客中国。打开必胜客中国首页,进入“餐厅查询”页面。

我们要爬取的数据内容有城市、餐厅名字、餐厅地址以及餐厅联系电话。因为我看到页面中有地图,所以页面一定有餐厅地址的经纬度。因此,餐厅的经纬度也是我们需要爬取的数据。

至于全国有必胜客餐厅的城市列表,我们可以通过页面的“切换城市”获取。

02

分析目页面

在编写爬虫程序之前,我都是先对页面进行简单分析,然后指定爬取思路。而且对页面结构进行分析往往会有一些意想不到的收获。

我们使用浏览器的开发者工具对页面结构进行简单分析。

我们在 StoreList 页面中能找到我们所需的数据。这个能确定数据提取的 Xpath 语法。

StoreList 页面的 Response 内容比较长。我们先不着急关闭页面,往下看看,找找看是否有其他可利用的内容。最后,我们找到调用获取餐厅列表信息的 JavaScript 函数代码。

我们接着搜索下GetStoreList函数,看看浏览器如何获取餐厅列表信息的。

从代码中,我们可以了解到页面使用 Ajax 方式来获取数据。页面以 POST 方式请求地址http://www.pizzahut.com.cn/StoreList/Index。同时,请求还携带参数 pageIndexpageSize

03

爬取思路

经过一番页面结构分析之后,我们指定爬取思路。首先,我们先获取城市信息。然后将其作为参数,构建 HTTP 请求访问必胜客服务器来获取当前城市中所有餐厅数据。

为了方便数据爬取,我将所有城市全部写入到 cities.txt 中。等要爬取数据时,我们再从文件中读取城市信息。

爬取思路看起来没有错,但是还是有个难题没有搞定。我们每次打开必胜客的官网,页面每次都会自动定位到我们所在的城市。如果无法破解城市定位问题,我们只能抓取一个城市数据。

于是乎,我们再次浏览首页,看看能不能找到一些可用的信息。最终,我们发现页面的 cookies 中有个 iplocation 字段。我将其进行 Url 解码,得到 深圳|0|0 这样的信息。

看到这信息,我恍然大悟。原来必胜客网站根据我们的 IP 地址来设置初始城市信息。如果我们能伪造出 iplocation 字段信息,那就可以随便修改城市了。

04

代码实现

第一步是从文件中读取城市信息。

# 全国有必胜客餐厅的城市, 我将城市放到文件中, 一共 380 个城市
cities = []

def get_cities():
    """ 从文件中获取城市 """  file_name = 'cities.txt'
  with open(file_name, 'r', encoding='UTF-8-sig') as file:
        for line in file:
            city = line.replace('\n', '')
            cities.append(city)

第二步是依次遍历 cities 列表,将每个城市作为参数,构造 Cookies 的 iplocation 字段。

# 依次遍历所有城市的餐厅
for city in cities:
    restaurants = get_stores(city, count)
    results[city] = restaurants
    count += 1
  time.sleep(2)

然后,我们再以 POST 方式携带 Cookie 去请求必胜客服务器。最后再对返回页面数据进行提取。

def get_stores(city, count):
    """ 根据城市获取餐厅信息 """
    session = requests.Session()
    # 对【城市|0|0】进行 Url 编码
    city_urlencode = quote(city + '|0|0')
    # 用来存储首页的 cookies
    cookies = requests.cookies.RequestsCookieJar()

    headers = {
        'User-agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.3964.2 Safari/537.36',
        'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Host': 'www.pizzahut.com.cn',
        'Cache-Control': 'max-age=0',
        'Connection': 'keep-alive',
    }

    print('============第', count, '个城市:', city, '============')
    resp_from_index = session.get('http://www.pizzahut.com.cn/', headers=headers)
    # print(resp_from_index.cookies)
    # 然后将原来 cookies 的 iplocation 字段,设置自己想要抓取城市。
    cookies.set('AlteonP', resp_from_index.cookies['AlteonP'], domain='www.pizzahut.com.cn')
    cookies.set('iplocation', city_urlencode, domain='www.pizzahut.com.cn')
    # print(cookies)

    page = 1
    restaurants = []

    while True:
        data = {
            'pageIndex': page,
            'pageSize': "50",
        }

        response = session.post('http://www.pizzahut.com.cn/StoreList/Index', headers=headers, data=data, cookies=cookies)
        html = etree.HTML(response.text)
        # 获取餐厅列表所在的 div 标签
        divs = html.xpath("//div[@class='re_RNew']")
        temp_items = []
        for div in divs:
            item = {}
            content = div.xpath('./@onclick')[0]
            # ClickStore('22.538912,114.09803|城市广场|深南中路中信城市广场二楼|0755-25942012','GZH519')
            # 过滤掉括号和后面的内容
            content = content.split('(\'')[1].split(')')[0].split('\',\'')[0]

            if len(content.split('|')) == 4:
                item['coordinate'] = content.split('|')[0]
                item['restaurant_name'] = content.split('|')[1] + '餐厅'
                item['address'] = content.split('|')[2]
                item['phone'] = content.split('|')[3]
            else:
                item['restaurant_name'] = content.split('|')[0] + '餐厅'
                item['address'] = content.split('|')[1]
                item['phone'] = content.split('|')[2]
            print(item)
            temp_items.append(item)

        if not temp_items:
            break
        restaurants += temp_items
        page += 1
        time.sleep(5)
    return restaurants

第三步是将城市以及城市所有餐厅信息等数据写到 Json 文件中。

with open('results.json', 'w', encoding='UTF-8') as file:
    file.write(json.dumps(results, indent=4, ensure_ascii=False))

05

爬取结果

程序运行完之后, 就会在当前目录下生成一个名为「results.json」文件。

原文发布于微信公众号 - 极客猴(Geek_monkey)

原文发表时间:2018-11-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python中文社区

100行代码爬取全国所有必胜客餐厅信息

极客猴,热衷于 Python,目前擅长利用 Python 制作网络爬虫以及 Django 框架。

37220
来自专栏自然语言处理

微博话题爬取与存储分析(上)

本文基于python以新浪微博为数据平台,从数据采集、关键字提取、数据存储三个角度,用最简单的策略来挖掘我们的“黄金”。

39820
来自专栏小詹同学

同样是追星 ,他们是这样做的 。

最近我朋友疯狂迷恋韩国的偶像团体防弹少年团,于是拜托我帮忙写一段程序实时检测韩国新闻网站instiz旗下两个板块pt和clip,当出现自家idol的新闻时,程序...

15160
来自专栏吴伟祥

生词篇-Shiro官网 的笔记_0114

xml  [ˌeks em ˈel ] abbr. Extensible Markup Language 可扩展标记语言

7410
来自专栏数据和云

DBA生存警示:系统级误删除案例及防范建议

编辑手记:对于资深的老DBA们,他们在漫长的职业生涯中养成了很多稀奇古怪的守则,以在复杂多变的环境中“幸存”,这源于无数血泪的教训,我曾经在《数据安全警示录》...

29040
来自专栏一个爱吃西瓜的程序员

爬取许嵩的所有微博并存入MongoDB

我很喜欢许嵩的音乐,我以前基本上他的每首歌都会唱,比如《素颜》、《灰色头像》、《玫瑰花的葬礼》、《清明雨上》、《庐州月》等等,打开播放器,基本上都是循环播放许嵩...

8820
来自专栏木子昭的博客

往"某度文库"上传资源之前,请先做好这些...想到一句好玩的话:知道是你干的,只是懒得抓你!如果你喜欢python,喜欢故事,请点赞或关注我!您的支持是对作者最大的鼓励!

先讲个相关的故事:匿名黑客的"复仇行动" 2010年12月10日,黑客组织匿名者发布了一条消息,解释了他们发起最近一次代号为”复仇行动”的攻击的大致动机(Pr...

389130
来自专栏FSociety

Python爬取猫眼「碟中谍」全部评论

评论算保存完了,近期会再做一个关于此次数据的可视化分析。另外阿汤哥真心太帅了,全程打肾上腺素,各位还没去看的赶紧~

8800
来自专栏程序猿

性能优化的磁盘阵列

上题讲到mysql的硬件优化的时候,有提到磁盘阵列(Redundant Arrays of Independent Disks,RAID )...

42880
来自专栏云计算D1net

如何应对Heartbleed安全漏洞

? 本周早些时候,一个名为Heartbleed的大型安全漏洞浮出水面。该漏洞可让入侵者诱使服务器泄漏你的个人数据。 Heartbleed漏洞的危险性...

28750

扫码关注云+社区

领取腾讯云代金券