Python3自学 爬虫实战Python爬虫作业爬虫专题

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

2018-02-05  本文已影响114人  是凡_El

1. 前期准备

1.1 软件安装
1.2 模块安装

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

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”之前至问号为止的大段乱码,回车,发现得到的网页与原来一致,看来我们的猜想是正确了。
在多次尝试后,我们发现,城市代码,入住与退房日期是必填的,而大人与小孩人数与房间个数等如果不输入的话,会默认为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让代码简化,在几次尝试后发现,除了

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

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

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

上一篇下一篇

猜你喜欢

热点阅读