【Python3 爬虫、数据清洗与可视化实战】大型爬虫案例:抓取某电商网站的商品数据

观察页面特征和解析数据

实现一个大型爬虫,抓取某旅游电商网站中某个频道的所有商品数据。

实现爬虫的第一步是观察页面特征和解析数据。通过对比PC端和无线端,这里决定数据采集自无线端,原因是无线端返回的数据是JSON格式的。JSON格式的数据比较容易处理,所以在获取数据的时候最好选择JSON格式的数据。

这里以某旅游电商网站:https://www.qunar.com/为例
通过浏览器访问该旅游电商官网,如下图所示:
在这里插入图片描述
接下来按【F12】键进入开发者模式,单击“自由行”选项进入自由行频道,如下图所示:

在这里插入图片描述
在这里插入图片描述
在自由行频道中点击搜索框,如下图所示:

在这里插入图片描述
在Network下,点击JS,选取一js文件单击,在文件的Preview(预览)界面可以观察到树状结构,如下图:

在这里插入图片描述
切换到Headers(请求头)页面,在General(总体)信息中有以下两条重要信息:
(1)Request URL(请求链接):将通过这个链接访问服务器获取数据。
(2)Request Method(请求方式):决定使用的函数方法和上传参数。常见的请求方式有GET方式和POST方式,其中GET方式权限单一,只有查询数据的权限,只要访问URL就可以返回数据;POST方式需要权限验证和请求内容,服务器通过权限放行,通过请求内容返回客户端请求的数据,POST方式具有查询和修改数据的权限。

如下图所示,请求方式为GET方式

在这里插入图片描述
在获取数据的时候,需要将Request URL(请求链接)的最后一个callback参数删掉,即目标URL如下:

https://touch.dujia.qunar.com/golfz/sight/arriveRecommend?dep=%E5%8C%97%E4%BA%AC&exclude=&extensionImg=255,175

单击推荐列表中的任意一个城市,通过观察可以发现数据在XHR(用XMLHttpRequest方法来获取JavaScript)中

在这里插入图片描述
切换到Headers页面,观察Request URL(请求链接)和Request Method(请求方式),如图所示:

在这里插入图片描述
其中Request URL(请求链接)如下:

https://touch.dujia.qunar.com/list?modules=list%2CbookingInfo%2CactivityDetail&dep=%E5%8C%97%E4%BA%AC&query=%E5%8E%A6%E9%97%A8%E8%87%AA%E7%94%B1%E8%A1%8C&dappDealTrace=true&mobFunction=%E6%89%A9%E5%B1%95%E8%87%AA%E7%94%B1%E8%A1%8C&cfrom=zyx&it=dujia_hy_destination&date=&needNoResult=true&originalquery=%E5%8E%A6%E9%97%A8%E8%87%AA%E7%94%B1%E8%A1%8C&width=480&height=320&quality=90&limit=0,24&includeAD=true&qsact=search&filterTagPlatform=mobile_touch

这个地址中以%开头的字符串是中文编译成的字符串,由于服务器不能识别中文字符,所以必须将中文以某种编码方式进行编译后才能提交到服务器。在此笔者使用在线编码转换进行解码

在这里插入图片描述

通过该工具还原后的URL如下:

https://touch.dujia.qunar.com/list?modules=list%2CbookingInfo%2CactivityDetail&dep=北京&query=厦门自由行&dappDealTrace=true&mobFunction=扩展自由行&cfrom=zyx&it=dujia_hy_destination&date=&needNoResult=true&originalquery=厦门自由行&width=480&height=320&quality=90&limit=0,24&includeAD=true&qsact=search&filterTagPlatform=mobile_touch

经过解码还原后,可以观察到这里使用的是utf-8编码,其中dep参数表示出发地(北京),query和originalquery表示目的地(厦门),通过修改这两个参数就可以控制遍历整个平台的自由行产品。

由于目标是获取整个自由行的产品列表,因此还需要获取出发地站点的列表,从不同的城市出发,会有不同的产品。

如下图,单击“北京出发”,如下图所示:

在这里插入图片描述
可以看到,全国各地出发地站点按字母排序,在右侧的开发者页面中可以找到对应的数据包,如下图所示:

在这里插入图片描述
在这里插入图片描述
然后切换到Headers页面,观察Request URL(请求链接)和Request Method(请求方式),如下图所示:
在这里插入图片描述
此时的目标URL如下:

https://touch.dujia.qunar.com/depCities.qunar

工作流程分析

完成上述的解析后,接下来实施这个爬虫,步骤如下:
(1)获取出发站点列表
(2)获取旅游景点列表
(3)获取景点产品列表
(4)存储数据

构建类目树

首先获取出发站点列表,输入以下代码:

import requests
url = 'https://touch.dujia.qunar.com/depCities.qunar'   # 出发站点列表链接
strhtml = requests.get(url)     # GET方式,获取网页数据
dep_dict = strhtml.json()       # requests库返回的数据编码成JSON格式的数据
for dep_item in dep_dict['data']:
    for dep in dep_dict['data'][dep_item]:
        print(dep)


代码运行结果为:

在这里插入图片描述
然后根据出发地站点列表获取旅游景点列表(目的地列表),继续输入以下代码:

import requests
import urllib
import time
url = 'https://touch.dujia.qunar.com/depCities.qunar'   # 出发站点列表链接
strhtml = requests.get(url)     # GET方式,获取网页数据
dep_dict = strhtml.json()       # requests库返回的数据编码成JSON格式的数据
for dep_item in dep_dict['data']:
    for dep in dep_dict['data'][dep_item]:
        print(dep)
        #新加入的代码
        url = 'https://touch.dujia.qunar.com/golfz/sight/arriveRecommend?dep={}&exclude=&extensionImg=255,175'.format(dep)
        time.sleep(1)
        strhtml = requests.get(url)
        arrive_dict = strhtml.json()
        for arr_item in arrive_dict['data']:
            for arr_item_1 in arr_item['subModules']:
                for query in arr_item_1['items']:
                    print(query['query'])

运行结果如下:

在这里插入图片描述

通过观察打印结果发现,目的地列表有多个重复项(在网页上也可以发现),如果基于这个有重复项的类目树获取数据,就会造成资源浪费,因此要先对目的地列表进行去重。接下来,在上段代码中补充去重的代码:

import requests
import urllib
import time
url = 'https://touch.dujia.qunar.com/depCities.qunar' #出发点列表的链接
strhtml = requests.get(url)
dep_dict = strhtml.json()
for dep_item in dep_dict['data']:
    for dep in dep_dict['data'][dep_item]:
        a=[]        #新加入的代码
        print(dep)
        url = 'https://touch.dujia.qunar.com/golfz/sight/arriveRecommend?dep={}&exclude=&extensionImg=255,175'.format(dep)
        time.sleep(1)
        strhtml = requests.get(url)
        arrive_dict = strhtml.json()
        for arr_item in arrive_dict['data']:
            for arr_item_1 in arr_item['subModules']:
                for query in arr_item_1['items']:
                    if query["query"] not in a:
                        a.append(query["query"])
        print(a)

运行结果如下:
在这里插入图片描述
由于去重针对的是每个出发地站点下的目的地,因此需要在获取出发站点的位置定义一个空的列表a,每次循环都会重置a。
最后判断目的地是否在列表a中,如果没有,就用appand()(合并)方法将目的地加入列表a中,代码如下:

if query["query"] not in a:
	a.append(query["query"])

获取景点产品列表

完成出发点站点列表和目的地列表的构建后,输入以下代码以便获取景点产品列表:

import requests
import urllib
import time
import pymongo
client = pymongo.MongoClient('localhost',27017) #建立连接
book_qunar = client['qunar'] #建立名为“zijiqi” 的数据库
sheet_qunar = book_qunar['sheet_qunar'] #在数据库中创建新表 “sheet_zijiqi”
url = 'https://touch.dujia.qunar.com/depCities.qunar' #出发点列表的链接
strhtml = requests.get(url)
dep_dict = strhtml.json()
for dep_item in dep_dict['data']:
    for dep in dep_dict['data'][dep_item]:
        a=[]
        url = 'https://touch.dujia.qunar.com/golfz/sight/arriveRecommend?dep={}&exclude=&extensionImg=255,175'.format(dep)
        time.sleep(1)
        strhtml = requests.get(url)
        arrive_dict = strhtml.json()
        for arr_item in arrive_dict['data']:
            for arr_item_1 in arr_item['subModules']:
                for query in arr_item_1['items']:
                    if query['query'] not in a: #使得当前出发点对应的目的地不重复
                        a.append(query['query'])

        for item in a:
            url = 'https://touch.dujia.qunar.com/list?modules=list%2CbookingInfo%2CactivityDetail&dep={}&query={}&dappDealTrace=true&mobFunction=%E6%89%A9%E5%B1%95%E8%87%AA%E7%94%B1%E8%A1%8C&cfrom=zyx&it=dujia_hy_destination&date=&needNoResult=true&originalquery={}&width=480&height=320&quality=90&limit=0,24&includeAD=true&qsact=search&filterTagPlatform=mobile_touch'.format(urllib.parse.quote(dep),urllib.parse.quote(item),urllib.parse.quote(item))

            time.sleep(1)
            strhtml = requests.get(url)
            routeCount = int(strhtml.json()['data']['limit']['routeCount']) #取出产品数
            for limit in range(0,routeCount,20): #获取产品信息
                url = 'https://touch.dujia.qunar.com/list?modules=list%2CbookingInfo%2CactivityDetail&dep={}&query={}&dappDealTrace=true&mobFunction=%E6%89%A9%E5%B1%95%E8%87%AA%E7%94%B1%E8%A1%8C&cfrom=zyx&it=dujia_hy_destination&date=&needNoResult=true&originalquery={}&width=480&height=320&quality=90&limit={},24&includeAD=true&qsact=search&filterTagPlatform=mobile_touch'.format(urllib.parse.quote(dep),urllib.parse.quote(item),urllib.parse.quote(item),limit)
                time.sleep(1)
                strhtml = requests.get(url)
                #产品的数据类型
                result = {
                    'date': time.strftime('%Y-%m-%d',time.localtime(time.time())),
                    'dep': dep,
                    'arrive': item,
                    'limit': limit,
                    'result': strhtml.json()
                }
                sheet_qunar.insert_one(result)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你是誰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值