美文网首页Python3自学 爬虫实战Python爬虫作业爬虫专题
Booking缤客网酒店搜索页信息爬取实例

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

作者: 是凡_El | 来源:发表于2018-02-05 21:10 被阅读114次

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

    相关文章

      网友评论

      本文标题:Booking缤客网酒店搜索页信息爬取实例

      本文链接:https://www.haomeiwen.com/subject/ucjizxtx.html