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

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

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

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

利用requests+分析ajax+mogodb爬取并存储携程酒店数据_第1张图片

 

利用requests+分析ajax+mogodb爬取并存储携程酒店数据_第2张图片

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

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

利用requests+分析ajax+mogodb爬取并存储携程酒店数据_第3张图片

 利用requests+分析ajax+mogodb爬取并存储携程酒店数据_第4张图片

 

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

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="" />中可以利用正则表达式直接提取。

利用requests+分析ajax+mogodb爬取并存储携程酒店数据_第5张图片

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

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('(.*?)')
    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

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

利用requests+分析ajax+mogodb爬取并存储携程酒店数据_第6张图片

利用requests+分析ajax+mogodb爬取并存储携程酒店数据_第7张图片

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

正常数据:

title="客户点评:4.9分,总分5分。" data-href="http://hotels.ctrip.com/hotel/dianping/5451854.html?isFull=F">hotel_level">极赞4.999%用户推荐源自13356位住客点评

异常数据:

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

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

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

正常数据:

新街口地区(市中心) 夫子庙地区】秦淮区汉中路101号金鹰新街口店B座,近新街口螺丝转弯。地铁一号线新街口站20-22出口,地铁2号线上海路站1号出口。 雨花台区应天大街677-2号(雨花台区,长江装饰城对面)

对于这些数据,我们直接利用正则表达式提取

(.*?) 

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

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

夫子庙地区】秦淮区汉中路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('',re.S)
        title=re.findall(res1,response.text)
        res2=re.compile('''

(.*?) (.*?).*?(.*?)用户推荐源自(.*?)位住客点评''',re.S) socre=re.findall(res3,response.text) res4=re.compile('(.*?)',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('(.*?)',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('(.*?)')
    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('',re.S)
        title=re.findall(res1,response.text)
        res2=re.compile('''

(.*?) (.*?).*?(.*?)用户推荐源自(.*?)位住客点评''',re.S) socre=re.findall(res3,response.text) res4=re.compile('(.*?)',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('(.*?)',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()

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

利用requests+分析ajax+mogodb爬取并存储携程酒店数据_第8张图片

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

你可能感兴趣的:(利用requests+分析ajax+mogodb爬取并存储携程酒店数据)