Booking缤客网酒店搜索页信息爬取实例

1. 前期准备

1.1 软件安装
1.2 模块安装

要安装的模块有两个,分别是 :

  • Requests
  • BeautifulSoup
    打开CMD后在命令行分别输入以下两行代码即可。
    pip install requests
    pip install beautifulsoup4
2. 网站分析

目标功能是实现对于缤客(Booking.com)网搜索页面酒店信息页的爬取,
我们首先要了解缤客网是怎么样提供酒店信息的。

首先打开缤客网 www.booking.com

1. 缤客网主页

我们打算在 3月1日至 3月2日在纽约住一晚,点击搜索,得到以下页面

2. booking 搜索页

为了提取信息,我们可以利用Requests命令获取网页信息:

import requests
url = “https://www.booking.com/searchresults.zh-cn.html?label=gen173nr-1DCAQoggJCDWNpdHlfMjAwODgzMjVIK1gEaHWIAQGYATLCAQp3aW5kb3dzIDEwyAEM2AED6AEB-AEDkgIBeagCAw&sb=1&src=searchresults&src_elem=sb&error_url=https%3A%2F%2Fwww.booking.com%2Fsearchresults.zh-cn.html%3Flabel%3Dgen173nr-1DCAQoggJCDWNpdHlfMjAwODgzMjVIK1gEaHWIAQGYATLCAQp3aW5kb3dzIDEwyAEM2AED6AEB-AEDkgIBeagCAw%3Bcheckin_month%3D3%3Bcheckin_monthday%3D1%3Bcheckin_year%3D2018%3Bcheckout_month%3D3%3Bcheckout_monthday%3D2%3Bcheckout_year%3D2018%3Bclass_interval%3D1%3Bdest_id%3D20088325%3Bdest_type%3Dcity%3Bdtdisc%3D0%3Bfrom_sf%3D1%3Bgroup_adults%3D1%3Bgroup_children%3D0%3Binac%3D0%3Bindex_postcard%3D0%3Blabel_click%3Dundef%3Bno_rooms%3D1%3Boffset%3D0%3Bpostcard%3D0%3Braw_dest_type%3Dcity%3Broom1%3DA%3Bsb_price_type%3Dtotal%3Bss_all%3D0%3Bssb%3Dempty%3Bsshis%3D0%26%3B&ss=纽约&ssne=纽约&ssne_untouched=纽约&city=20088325&checkin_year=2018&checkin_month=3&checkin_monthday=1&checkout_year=2018&checkout_month=3&checkout_monthday=2&group_adults=1&group_children=0&no_rooms=1&from_sf=1”
r = requests.get(url)

print(r.text)

在分析具体返回结果之前,我们看到这一串 url 实在太长了,看到眼花缭乱,有没有办法可以缩短一点并提取关键信息呢?
答案是可以的,仔细分析后,我们看到了结尾处写的信息似乎有点玄机:

  • city = 20088325
  • checkin_year = 2018 ...
  • group_adults = 1

不正好是我们之前搜索的信息吗,并且缤客网用代号的方式储存城市名字,此外还要输入入住和退房的年月日以及人数。
为了验证我们的想法,尝试去删除在“&city”之前至问号为止的大段乱码,回车,发现得到的网页与原来一致,看来我们的猜想是正确了。
在多次尝试后,我们发现,城市代码,入住与退房日期是必填的,而大人与小孩人数与房间个数等如果不输入的话,会默认为1名大人,0个小孩和1间房间。

至此,整段网址就被缩短为:

url = “https://www.booking.com/searchresults.zh-cn.html?city=20088325&checkin_year=2018&checkin_month=3 &checkin_monthday=1&checkout_year=2018&checkout_month=3&checkout_monthday=2

我们再来看看之前网站的输出结果:


3. 返回的结果

从返回的结果中仔细分析,发现了 sr-hotel__name 类中储存了酒店的名字,但是搜索结果个数只有15个,且第一个为 Park West Hotel(公园西酒店),与之前浏览器中的第一个酒店名字 Hotel Pensylvania(宾夕法尼亚酒店)不相符。
我们在直接在刚才浏览器页面中右键,点击查看源代码。


4. 浏览器中的源代码

可以看到此时同样搜索 hotel__name,产生了46个结果,并且第一个与页面相符,为Hotel Pensylvania(宾夕法尼亚酒店)。看来缤客网没打算这么轻易把信息交给我们。

说明在发送请求时,并不是简单的发送了一个 Request,而是附加了一些信息进行辨认。
为了分析具体发送了什么,我们在刚才的搜索页面中按 F12 打开控制台,点击Network,然后点击 F5 进行页面刷新。


5. 刷新结果

可以看到产生了许多信息,一般情况下,动态的网页都是由AJAX请求然后返回一个json页面进行调取,那么缤客网也是如此吗,这两个请求主要在XHR和JS中,我们点击上方的XHR,筛选XHR项,并点击其中一页,选取Preview进行页面查看,在页面中搜索hotel,并没有得到结果。
将XHR选项卡和JS选项卡中的页面逐个分析后,都没有搜索到相应的信息,我们可以判定酒店的信息不是来自这里。


6. XHR结果

我们接着查看了其他可能的选项卡,最终发现在Doc选项卡中找到了一个叫做Searchresults的文件,点开preview后搜索hotel__name,发现同样得到了46个结果,且第一个结果与之前看到的 Hotel Pennsylvania(宾夕法尼亚酒店)一致。
也就是说,酒店的信息就储存在这个页面中。

7. Doc结果

接下来我们要做的就是用Requests指令获取这个页面的信息。
点击Headers,查看Request Headers。

8. Request Headers

可以点开Request Headers左上角的 X 按掉,可以看到这个页面的请求的方式是GET
那么我们就可以将其中信息复制,并用Requests指令中的
requests.get(url, headers=headers)
方式发送GET请求,其中可以尝试删除部分Headers让代码简化,在几次尝试后发现,除了

  • User-Agent
  • Cookies

这两部分是必不可缺之外,其他部分均可删除。

那么如何进行下一页的访问呢?

在之前的搜索页下打开F12控制台,点击搜索页中的下一页,发现页面只有中间部分进行了刷新,那么很有可能是一个AJAX请求,这时在Doc中没有找到相应的文件,仔细查找后,发现在XHR选项卡中新生成了一个同样叫Searchresults的页面,查看Preview,其中内容正是第二页中的酒店信息。

9. 2nd page

10. 3rd page

查看 Headers 中的信息,发现其中rows:50和offset:50十分可疑,因为一页中共显示50个酒店,点击第三页查看一下,果然在offset处变成了offset: 100,看来我们可以通过改变请求中的offset 来改变页数。

https://www.booking.com/searchresults.zh-cn.html?aid=304142&label=gen173nr-1DCAQoggJCDWNpdHlfMjAwODgzMjVIK1gEaHWIAQGYATLCAQp3aW5kb3dzIDEwyAEM2AED6AEB-AEDkgIBeagCAw&checkin_month=3&checkin_monthday=1&checkin_year=2018&checkout_month=3&checkout_monthday=2&checkout_year=2018&city=20088325&class_interval=1&dest_id=20088325&dest_type=city&from_sf=1&group_adults=1&group_children=0&label_click=undef&no_rooms=1&raw_dest_type=city&room1=A&sb_price_type=total&src=searchresults&src_elem=sb&ss=%E7%BA%BD%E7%BA%A6&ssb=empty&ssne=%E7%BA%BD%E7%BA%A6&ssne_untouched=%E7%BA%BD%E7%BA%A6&rows=50&offset=100

观察此时的url结尾,可以看到这个参数是通过params传递的。

至此我们就摸清了缤客网的爬取原理。

3. 代码实现

先贴上完整代码,然后逐行解释。

import requests
import re
from bs4 import BeautifulSoup

def SearchInfo():
    kv = {
        'city':'20088325',
        'checkin_year':'2018',
        'checkin_month':'3',
        'checkin_monthday':'1',
        'checkout_year':'2018',
        'checkout_month':'3',
        'checkout_monthday':'2',
        'offset':'0',
    }
    return kv

def Headers():
    headers = {
        "Cookie":"输入你自己的cookies",
        "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
    }
    return headers

def getHTMLText(url, **kwargs):
    try:
        r = requests.get(url, **kwargs)
        r.raise_for_status()
        return r.text
    except:
        return None

def main():
    #input url
    url = 'https://www.booking.com/searchresults.zh-cn.html?'
    for i in range(10):
        kv = SearchInfo()
        headers = Headers()
        try:
            kv['offset']=i*50
            r = getHTMLText(url, params=kv, headers=headers)
            soup = BeautifulSoup(r, 'lxml')
            Hotels = soup.find_all(class_="sr-hotel__name")
            print("page %s" %(i+1))
            for name in Hotels:
                print(re.sub(r'\n', '', name.text))
        except:
            continue

main()
  1. 首先分别调用requests,re和BeautifulSoup三个模组,其中BeautifulSoup注意大小写。
  2. 定义SearchInfo()在字典 kv 之中输入之前提到的搜索信息,此处以纽约为例,输入城市代码20088325,入住日期2018年3月1日,退房日期为2018年3月2日,加上一个页数的起始参数 offset: 0。
  3. 定义Headers(),在字典 Headers 之中将Cookies和User-Agent信息传递进去。
  4. 定义 getHTMLText()来获取页面信息,加上一个try,except结构让代码更安全,通过requests.get() 函数获取页面,r.raise_for_status()为检查页面是否获取成功,如果成功就返回 r.text 即页面内容。
  5. 主函数中先输入起始页面,用for循环下载前10页共500条酒店信息,加入try结构跳过错误,在每一次循环中通过 i*50 改变offset的值来改变页数,通过 BeautifulSoup 解析 r.text 文件,并用 .find_all()搜索“sr-hotel__name”类来查找包含酒店名字的标签,因为产生的结果中首尾各包含一个换行符,用正则式中的re.sub()命令来删除换行符,最后用for循环打印出每一个包含酒店名字标签中的text,即酒店的名字。
11. 输出结果
4. 小结

本文中还未提到如何将得到的文本信息输出至系统文档中,如csv文件等。在下一次的文章中将会尝试去获取对应酒店详情页的信息(评论,地址,房间种类以及价格等),并且储存在文件中。
博主前几天刚接触爬虫,专业是高分子化学,如果写的有疏漏还望大家海涵。在学习的过程中发现网上讲爬虫主要讲爬取静态网页,在学习爬取动态网页的过程中碰了不少壁,希望分享分析的过程给大家。具体函数怎么使用方面网上写的很多就不多阐述了。
欢迎大家在下方留言和提建议!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,084评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,623评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,450评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,322评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,370评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,274评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,126评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,980评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,414评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,599评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,773评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,470评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,080评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,713评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,852评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,865评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,689评论 2 354

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,654评论 18 139
  • 作业代码: 项目地址 保存爬取结果的文件 总结 BeautifulSoup 的使用 学习了一下 Beautiful...
    超net阅读 457评论 0 1
  • 我在等啊, 等西窗的余晖消失, 等东方的月牙轻上树梢。 我在等啊, 等柳树下的你, 以及亭子里那壶温热的酒渐凉。 ...
    烧仙草123阅读 123评论 0 0
  • 天津的霾越来越重了,脚下的路也越来越不好走了,我越小心,却越容易跌倒,后来,我不怕了,越是悲怆,越是嬉皮,我似乎...
    我怀念的是整整一个曾经阅读 234评论 0 0
  • 是该让才华横溢,被世人认可, 在当下名声大噪,然后 沉默于历史之中? 还是该让思想的花朵绽放, 谦卑的俯...
    静留庭阅读 320评论 0 2