利用requests+分析ajax+mogodb爬取并存储携程酒店数据

版权声明:原创不易,如若转载,请注明出处! https://blog.csdn.net/MG1723054/article/details/81865681

以前就利用selenium爬取协程酒店信息,但是我们知道利用selenium抓取信息有个缺点就是效率不高,于是这几天重新打开网页,从基本的网页和源代码中寻找一些值得利用的数据。

话不多说,我们直接说抓取携程酒店数据的思路,声明:本节只做爬虫交流技术所用,不得用于商业用途,如有侵犯他人权利,联系本作者删除

首先我们打开携程所有南京酒店链接http://hotels.ctrip.com/hotel/nanjing12#ctm_ref=ctr_hp_sb_lst

简简单单,源代码中包含我们需要的酒店数据,你以为这样就结束了?携程的这些数据这么廉价地就给我们得到了?事实并不是如此,当我们点击第二页的时候出现问题:虽然酒店的数据改变了,但是我们发现该网页的网址却没有改变,这也就造成了源代码中酒店的数据不改变,还是第一页的数据,如下图所示。我们遇到的第一个问题就是怎么获取所有数据的url,于是我们要换种思路,看看能不能从源代码中再获取一些有用的信息,比如输入网址让其页面改变,且源代码也改变显示我们需要的数据。

http://hotels.ctrip.com/hotel/nanjing12#ctm_ref=ctr_hp_sb_lst

 

扫描二维码关注公众号,回复: 4733017 查看本文章

如下图所示,在翻页所对应的源代码中,我们发现在不同的页面对应不同的链接,比如第二页,第三页,第四页分别为

href="http://hotels.ctrip.com/hotel/nanjing12/p2" ,

href="http://hotels.ctrip.com/hotel/nanjing12/p3",

href="http://hotels.ctrip.com/hotel/nanjing12/p4"

点开这些链接我们看到酒店别的数据,不同的链接数据不同,而且在源代码中也得到了所需要爬取的数据结果,于是我们可以得到了在不同的数据的ur链接规律。然后我们还需要找到总共多少页数据,这个简单,在节点type="text" value="1"data-pagecount=222 name="" />中可以利用正则表达式直接提取。

 分析到这里,我们写出部分代码:

import requests,re
urls=[]
origin_url='http://hotels.ctrip.com/hotel/nanjing12' 
def infor_pages():    ####查找总共多少页 
    origin_infor=requests.get(origin_url,headers={'User-Agent':'Mozilla/5.0' })
    origin_infor.encoding='utf-8'   ####注意:这个编码很奇怪,源代码中是gb2312,但是用该编码却
###是中文乱码,利用utf-8不会乱码
    res=re.compile('<a rel="nofollow" data-dopost="T" href=".*?" data-type="page" data-value=".*?">(.*?)</a>')
    pages=re.findall(res,origin_infor.text)###提取总页数
    return pages
def url(pages): #将所有的链接放在列表中
    for i in range (1,int(pages[0])+1):
        url=origin_url+'/p'+str(i)##构造链接
        urls.append(url)        
    return urls

后面就是数据提取的问题了,由于数据繁多,有的数据出现与正常数据不同的情况,如下图所示,在标准的数据里面具有评分标准以及程度(极赞),还有地址具有大概地址与详细地址,但是异常数据却没有这些内容,这在利用正则表达式提取的时候有一定的难度,我的思路是先粗提取再利用字符串的相关知识进行过滤

我们比对正常数据与异常数据的源代码

正常数据:

title="客户点评:4.9分,总分5分。" data-href="http://hotels.ctrip.com/hotel/dianping/5451854.html?isFull=F"><span class="hotel_level">极赞</span><span class="hotel_value">4.9</span><span class="total_judgement_score"><span style="color:#009933;">99%</span>用户推荐</span><span class="hotel_judgement">源自<span style="color:#FF9900;">13356</span>位住客点评

异常数据:

title="客户点评:0.0分,总分5分。" data-href="http://hotels.ctrip.com/hotel/dianping/21695629.html?isFull=F"><span class="no_grade">暂无评分</span><span class="total_judgement_score"><span style="color:#009933;">100%</span>用户推荐</span><span class="hotel_judgement">源自<span style="color:#FF9900;">1</span>位住客点评

对于该情况,我们将红色字体部分利用(.*?)提取出来,给根据属于哪一个字符,在给予重新排版信息区

还有一个异常就是酒店地址信息,有的是具有大概区街道和详细地址,有的直接就是详细地址,比如下面的数据:

正常数据:

<p class="hotel_item_htladdress">【 <a tracekey="nhtllistroomclick" tracevalue="clicktype=zonename;hotelid=5451854;roomid=;isdefaultdisplay=;defaultdisplaypos=;htlpos=1;rompos=;" title="新街口地区(市中心)酒店预订" onclick="window.bizMap(68); return false;" href="//hotels.ctrip.com/hotel/Nanjing12/zone68">新街口地区(市中心)</a> <a tracekey="nhtllistroomclick" tracevalue="clicktype=zonename;hotelid=5451854;roomid=;isdefaultdisplay=;defaultdisplaypos=;htlpos=1;rompos=;" title="夫子庙地区酒店预订" onclick="window.bizMap(71); return false;" href="//hotels.ctrip.com/hotel/Nanjing12/zone71">夫子庙地区</a>】秦淮区汉中路101号金鹰新街口店B座,近新街口螺丝转弯。地铁一号线新街口站20-22出口,地铁2号线上海路站1号出口。 <a href="javascript:

异常数据:

<p class="hotel_item_htladdress">雨花台区应天大街677-2号(雨花台区,长江装饰城对面) <a href="javascript:;"

对于这些数据,我们直接利用正则表达式提取<p class="hotel_item_htladdress">(.*?) <a href="javascript:;"这样对于正常数据,提取出类似于下面数据

【 <a tracekey="nhtllistroomclick" tracevalue="clicktype=zonename;hotelid=5451854;roomid=;isdefaultdisplay=;defaultdisplaypos=;htlpos=1;rompos=;" title="新街口地区(市中心)酒店预订" onclick="window.bizMap(68); return false;" href="//hotels.ctrip.com/hotel/Nanjing12/zone68">新街口地区(市中心)</a> <a tracekey="nhtllistroomclick" tracevalue="clicktype=zonename;hotelid=5451854;roomid=;isdefaultdisplay=;defaultdisplaypos=;htlpos=1;rompos=;" title="夫子庙地区酒店预订" onclick="window.bizMap(71); return false;" href="//hotels.ctrip.com/hotel/Nanjing12/zone71">夫子庙地区</a>】秦淮区汉中路101号金鹰新街口店B座,近新街口螺丝转弯。地铁一号线新街口站20-22出口,地铁2号线上海路站1号出口。()

我们利用字符查找以及split方法得到详细地址

夫子庙地区</a>】秦淮区汉中路101号金鹰新街口店B座,近新街口螺丝转弯。地铁一号线新街口站20-22出口,地铁2号线上海路站1号出口。

这样我们的数据处理就结束

该部分代码如下:

def items(urls):    ####酒店信息获取
    for url in urls :
        response=requests.get(url,headers={'User-Agent':'Mozilla/5.0' })
        response.encoding='utf-8'
        res1=re.compile('<a target="_blank" class="hotel_item_pic  haspic" title="(.*?)" href=".*?" data-hotel=".*?" data-ctm=".*?" tracekey=".*?" tracevalue=".*?" >',re.S)
        title=re.findall(res1,response.text)
        res2=re.compile('''<p class="hotel_item_htladdress">(.*?) <a href="javascript''',re.S)
        address=re.findall(res2,response.text)
        res3=re.compile(''' title="客户点评:(.*?),总分5分。">(.*?)<span class="(.*?)">.*?</span><span class="total_judgement_score"><span style='color:#009933;'>(.*?)</span>用户推荐</span><span class="hotel_judgement">源自<span style='color:#FF9900;'>(.*?)</span>位住客点评</span>''',re.S)
        socre=re.findall(res3,response.text)
        res4=re.compile('<span class="J_price_lowList">(.*?)</span>',re.S)
        price=re.findall(res4,response.text)
        yield [title,address,socre,price] 
       # yield address
def process_strings(item) :#####数据处理
    for m in range(len(item[2])):
        if '】'in item[1][m]:
            item[1][m]=item[1][m].split('】')[1] 
        if item[2][m][1] == '' :
            level=item[2][m][1]     
        else :
            lev=re.findall('<span class="hotel_level">(.*?)</span>',item[2][m][1])
            level=lev[0]
       # print(item[2][m])
        if item[2][m][2] == 'no_grade':
            level='暂无'
        quality=level+'评分'+item[2][m][0]+',总分5.0分,'+item[2][m][3]+'推荐,'+'源自'+item[2][m][4]+'顾客评分'
        reps={'name':item[0][m],
               'address' : item[1][m],
               'quality' : quality,
                'price' : item[3][m]  }
        yield reps


最后将爬取到的数据保存在MongoDB数据库中,这里简单说下MongoDB数据库

MongoDB数据库是一个基于分布式文件存储的开源数据库系统,其内容储存形式类似于JSON格式,相对于MySQL来说,MongoDB相对灵活。具体的MongoDB安装以及用法参考下面文档

详细图解mongodb 3.4.1 win7x64下载、安装、配置与使用2017/01/16  原创作者 李学凯

https://blog.csdn.net/qq_27093465/article/details/54574948

该部分代码如下:

def insert(infor) :
    client=MongoClient()
    db=client['ctrip_company']
    collection=db['hotels information in Nanjing']
    collection.insert_one(infor)  

附:完整代码

# -*- coding: utf-8 -*-
"""
Created on Sun Aug 19 15:19:40 2018

@author: NJUer
"""
import requests,re
from pymongo import MongoClient
origin_url='http://hotels.ctrip.com/hotel/nanjing12' 
urls=[]
def infor_pages():     
    origin_infor=requests.get(origin_url,headers={'User-Agent':'Mozilla/5.0' })
    origin_infor.encoding='utf-8'
    res=re.compile('<a rel="nofollow" data-dopost="T" href=".*?" data-type="page" data-value=".*?">(.*?)</a>')
    pages=re.findall(res,origin_infor.text)
    return pages
def url(pages):
    for i in range (1,int(pages[0])+1):
        url=origin_url+'/p'+str(i)
        urls.append(url)
    return urls
def items(urls):
    for url in urls :
        response=requests.get(url,headers={'User-Agent':'Mozilla/5.0' })
        response.encoding='utf-8'
        res1=re.compile('<a target="_blank" class="hotel_item_pic  haspic" title="(.*?)" href=".*?" data-hotel=".*?" data-ctm=".*?" tracekey=".*?" tracevalue=".*?" >',re.S)
        title=re.findall(res1,response.text)
        res2=re.compile('''<p class="hotel_item_htladdress">(.*?) <a href="javascript''',re.S)
        address=re.findall(res2,response.text)
        res3=re.compile(''' title="客户点评:(.*?),总分5分。">(.*?)<span class="(.*?)">.*?</span><span class="total_judgement_score"><span style='color:#009933;'>(.*?)</span>用户推荐</span><span class="hotel_judgement">源自<span style='color:#FF9900;'>(.*?)</span>位住客点评</span>''',re.S)
        socre=re.findall(res3,response.text)
        res4=re.compile('<span class="J_price_lowList">(.*?)</span>',re.S)
        price=re.findall(res4,response.text)
        yield [title,address,socre,price] 
       # yield address
def process_strings(item) :#####数据处理
    for m in range(len(item[2])):
        if '】'in item[1][m]:
            item[1][m]=item[1][m].split('】')[1] 
        if item[2][m][1] == '' :
            level=item[2][m][1]     
        else :
            lev=re.findall('<span class="hotel_level">(.*?)</span>',item[2][m][1])
            level=lev[0]
       # print(item[2][m])
        if item[2][m][2] == 'no_grade':
            level='暂无'
         quality=level+'评分'+item[2][m][0]+',总分5.0分,'+item[2][m][3]+'推荐,'+'源自'+item[2][m][4]+'顾客评分'
        reps={'name':item[0][m],
               'address' : item[1][m],
               'quality' : quality,
                'price' : item[3][m]  }
        yield reps
def insert(infor) :
    client=MongoClient()
    db=client['ctrip_company']
    collection=db['hotels information in Nanjing']
    collection.insert_one(infor)       
def main () :
    pages=infor_pages()
    urls=url(pages)
    for item in items(urls) :
        for infor in process_strings(item):
            insert(infor)
if __name__=='__main__' :
    main()

运行之后的部分结果截图如下:

原创不易,如若转载,请注明出处和作者,谢谢! 

猜你喜欢

转载自blog.csdn.net/MG1723054/article/details/81865681