Scrapy + Django爬虫可视化项目实战(一)

目录

一、项目介绍

(一) 项目背景

(二) 项目介绍

二、系统实现

(一) 爬虫

1. 实现步骤

一、爬取字段

二、分析页面

三、具体实现

2. 爬虫结果


系列文章

Python升级打怪—Django入门

Python升级打怪—Scrapy零基础小白入门

实现技术

  • Scrapy
  • Django
  • Echarts

一、项目介绍

(一) 项目背景

在信息技术高速发展的今天,数据已经成为决策的重要依据。旅游业作为服务性行业的重要支柱,其数据资源尤为丰富。去哪儿网作为中国领先的在线旅游平台,拥有大量的景点数据,这些数据对于分析旅游市场动态、游客行为以及景点管理策略等具有极高的价值。通过对去哪儿网景点数据的分析,我们可以了解游客的偏好、旅游市场的趋势以及景点的竞争力等信息。同时,数据可视化可以将复杂的数据信息以直观、易懂的方式呈现出来,有助于决策者更好地理解数据背后的含义

(二) 项目介绍

本项目采用Scray框架爬取去哪儿网的景点数据以及景点的评论数据,将爬取到的数据存储为csv,再通过Django Web框架技术将数据存储到Mysql,然后通过编写接口、分析数据,通过接口将数据返回前端,前端结合Echarts制作可视化表

二、系统实现

(一) 爬虫

爬取网址:去哪儿网

1. 实现步骤

一、爬取字段

本项目爬取的数据分为两部分:【景点数据、景点评论数据】,并将爬取的数据分别存入两个CSV文件中

景点字段

# 景点名称
name = scrapy.Field()
# 景点价格
price = scrapy.Field()
# 所属城市
province = scrapy.Field()
# 评级
star = scrapy.Field()
# 地址
address = scrapy.Field()
# 详情url
detail_url = scrapy.Field()
# 评论数
comment_total = scrapy.Field()
# 短评
short_intro = scrapy.Field()
# 详评
detail_intro = scrapy.Field()
# 封面
cover = scrapy.Field()
# 销售额
sale_count = scrapy.Field()
# 地区
districts = scrapy.Field()
# 评分
score = scrapy.Field()

景点评论字段

# 景点名称
travel_name = scrapy.Field()
# 内容
content = scrapy.Field()
# 评论时间
date = scrapy.Field()
二、分析页面

以地区为北京的景点为例子,搜索结果如下

景点数据

通过分析页面得出,景点数据是通过发送Ajax请求获得,那么我们就不用解析页面,可以直接通过请求获取景点数据即可

当然请求里的景点数据有些字段是没有的,需要我们进入到景点的详情页去爬取

第一个景点:故宫博物院详情页路由

故宫博物院门票,故宫博物院门票预订,故宫博物院门票价格,去哪儿网门票

第二个景点:八达岭长城详情页路由

八达岭长城门票,八达岭长城门票预订,八达岭长城门票价格,去哪儿网门票

通过对比路由地址得出

景点的详情页路由是由基本的路由地址加上景点Id拼接得出,那么在Ajax请求的景点数据字段就有景点id,
那么如果获取指定的景点详情地址,就可以通过拼接该景点id获得

进入到景点详情页,解析页面,获取景点的【评分、评论人数、评论数据

这里我们可以通过Xpath解析页面 ,获取景点的评分以及评论人数

景点评论

请求URL示例:https://piao.qunar.com/ticket/detailLight/sightCommentList.json?sightId=38170&index=2&page=2&pageSize=10&tagType=0

景点评论数据也是通过发送Ajax请求获取,但不同的是需要携带上景点的id,在这个景点的id不同于进入景点详情页的景点id,它是在景点详情页中的,在查看网页源代码中,我们也是可以找到这个id的,后面我们就可以通过页面解析得到这个id,再拼接请求地址就可以去获取景点评论数据了

三、具体实现

基础的项目搭建就不在赘述,如有不懂的请看系列文章

爬虫前必看

  1. 一定要设置休眠时间!!!这对网站和你都好
  2. 因为爬取的数据量很大,爬虫时间会很长,大家可以根据自己的需求合理改造,比如选择合适时间爬取、爬取少量城市或每个城市爬取1-2页数据等

问题一:爬取的数据(景点数据、评论数据)分开存储

可以通过scrapy框架提供的pipelines文件中解决,根据定义数据结构存储到指定文件中,还可以进行数据处理等等操作

问题二:爬取数据层层嵌套

通过前面的页面分析,我们所要爬取的数据层层嵌套,爬取起来比较麻烦,当然也是难不倒我们的

首先准备基础数据

name = "Quanar"
allowed_domains = ["piao.qunar.com"]
start_urls = ["https://piao.qunar.com/daytrip/list.htm"]# 所要爬取景点的城市
province_list = ['北京', '天津', '河北', '山西', '内蒙古', '辽宁', '吉林', '黑龙江', '上海', '江苏','浙江', '安徽', '福建', '江西', '山东', '河南', '湖北', '湖南', '广东','广西', '海南', '重庆', '四川', '贵州', '云南', '西藏', '陕西', '甘肃','青海', '宁夏', '新疆', '台湾', '香港', '澳门']# 城市景点列表的ajax请求网址:keyword:城市名称 page:第几页 sort:pp=》按人气排名
url = 'https://piao.qunar.com/ticket/list.json?keyword=%s&region=&from=mpl_search_suggest&page=%s&sort=pp'
# 景点url
travel_url = 'https://piao.qunar.com/ticket/detail_%s.html'
# 景点评论url
comment_url = 'https://piao.qunar.com/ticket/detailLight/sightCommentList.json?sightId=%s&index=1&page=%s&pageSize=10&tagType=0'

发起请求,获取指定城市的指定页的景点数据

def start_requests(self):# 遍历每个城市列表for index, province in enumerate(self.province_list, 1):# 每个城市爬取 多少页 数据for page in range(5):yield Request(url=(self.url % (province, page)), callback=self.parse_travel_list,meta={"province": province})return

解析景点数据,拼接景点详情页地址,继续发起请求

# 解析单个城市里的多个景点数据
def parse_travel_list(self, response):# 城市名称province = response.meta['province']# 城市景点列表travel_list = response.json()['data']['sightList']for index, travel in enumerate(travel_list):try:travel_item = TravelItem()# 景点名称name = travel['sightName']print("正在爬取该页 %s 条数据,景点名称为:%s" % (str(index + 1), name))# 门票价格try:price = travel['qunarPrice']except:price = 0# 有点景点可能没有评等级,所以需要判断一下try:star = travel['star']except:star = '未评'# 详细地址address = travel['address']# 短评short_intro = travel['intro']# 封面cover = travel['sightImgURL']# 销售额sale_count = travel['saleCount']# 地区districts = travel['districts']# ======================================= 详情爬虫# 景点idsightId = travel['sightId']# 详情地址detail_url = self.travel_url % sightIdtravel_item['name'] = nametravel_item['province'] = provincetravel_item['price'] = pricetravel_item['star'] = startravel_item['address'] = addresstravel_item['short_intro'] = short_introtravel_item['cover'] = covertravel_item['sale_count'] = sale_counttravel_item['districts'] = districtstravel_item['detail_url'] = detail_url# 生成新的Request,并传递给下一个解析函数yield scrapy.Request(detail_url, callback=self.parse_travel_details, meta={'travel_item': travel_item})returnexcept:continue

解析页面,获取景点的评分以及评论人数、请求景点评论所需的id,拼接获取景点评论的url,继续发起请求

    # 解析单个景点里的详情def parse_travel_details(self, response):travel_item = response.meta['travel_item']name = travel_item['name']travel_detail_xpath = Selector(response)# 评论总数comment_total = travel_detail_xpath.xpath('//span[@class="mp-description-commentCount"]/a/text()')[0].get().replace('条评论', '')# 详情介绍detail_intro = travel_detail_xpath.xpath('//div[@class="mp-charact-desc"]//p/text()').get()# 评分score = travel_detail_xpath.xpath("//span[@id='mp-description-commentscore']/span/text()").get()if not score:score = 0else:score = score[0]travel_item['comment_total'] = comment_totaltravel_item['detail_intro'] = detail_introtravel_item['score'] = score# print("爬取存储的travel_item:%s" % travel_item)yield travel_item# ======================================= 评论爬虫data_sight_id = travel_detail_xpath.xpath('//div[@class="mp-tickets-new"]/@data-sightid')[0].get()comment_url = self.comment_url % (data_sight_id, 1)# 生成新的Request,并传递给下一个解析函数yield scrapy.Request(comment_url, callback=self.parse_comments, meta={"name": name})

解析评论数据

# 解析单个景点里的评论
def parse_comments(self, response):try:print("正在爬取%s的评论数据" % response.meta['name'])comment_json = response.json()['data']['commentList']name = response.meta['name']for comment in comment_json:item = CommentItem()if comment['content'] != '用户未点评,系统默认好评。':item['travel_name'] = nameitem['content'] = str(comment['content'])item['date'] = comment['date']yield itemexcept:return

2. 爬虫结果

整个爬虫代码结束,让我们看看爬取到结果

爬取1958个景点数据

每个景点对应评论6213

好的,爬虫部分实现,接下来就是项目可视化,请看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/385676.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HDMI的等长要求到底是多少?

四对差分走线对内误差最好做到 5mil 范围之内,对与对的差分误差最好控制在 10mil 范围之内。同时,对与对之间的间距要求做到 15mil,空间准许的情况下尽量拉开,减小串扰。 作者:凡亿教育 https://www.bilibili.com/rea…

数据丢失不用愁!这四款数据恢复大师免费版助你找回珍贵回忆

我们在办公或者是生活中常常会遇到不小心将手机设备或者计算机当中的重要数据误删除/格式化/或其他不小心丢失的情况,但是不用紧张,这篇文章就是给大家分享如何恢复他们,以下带来除易我数据恢复外的其他好用的数据恢复软件: 第一…

进程关系与守护进程

进程关系与守护进程 1. 进程组2. 会话3. 控制终端4. 作业控制5. 守护进程 1. 进程组 什么是进程组 之前我们提到了进程的概念, 其实每一个进程除了有一个进程 ID(PID)之外 还属于一个进程组。进程组是一个或者多个进程的集合, 一个进程组可以包含多个进…

猫头虎分享:PyTorch异常ModuleNotFoundError: No module named ‘torch’解决方案

🐯 猫头虎分享:PyTorch异常ModuleNotFoundError: No module named ‘torch’解决方案 💻 摘要 在本篇博客中,我们将深入探讨如何解决PyTorch中常见的“ModuleNotFoundError: No module named ‘torch’”错误。通过详细的步骤指…

如何在 VitePress 中自定义logo,打造精美首页 #home-hero-image

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storm…

【matlab】使用movefile批量修改命名,并保留原命名中指定的数字

【matlab】使用movefile批量修改命名,并保留原命名中指定的数字 文章目录 【matlab】使用movefile批量修改命名,并保留原命名中指定的数字一、情况说明二、代码示例通配符正则表达式匹配 (regexp 函数):提取捕获组中的数字 (number 变量): 一、情况说明 …

CTF之网站被黑

简单看一下网页和源码没发现什么明显漏洞 那就扫描一下目录 发现了/shell.php文件,访问一下,发现是一个后台管理登录页面 别无他法只能爆破喽,爆破后发现密码是hack flag{25891d9e9d377f006eda3ca7d4c34c4d}

rust学习——move关键字

示例讲解 在闭包章节中,有讲过 move 关键字在闭包中的使用可以让该闭包拿走环境中某个值的所有权,同样地,你可以使用 move 来将所有权从一个线程转移到另外一个线程。 首先,来看看在一个线程中直接使用另一个线程中的数据会如何…

22.备份交换机-处理无法投递的消息

前面提到当消息发送给交换机,交换机出故障,或者队列出现故障,会反馈给生产者。 如果交换机备份,将无法投递的消息发送给备份交换机,再由备份交换机给备份队列和告警队列的思路,来防止消息不丢失。 小提示…

探索LLM世界:新手小白的学习路线图

随着人工智能的发展,语言模型(Language Models, LLM)在自然语言处理(NLP)领域的应用越来越广泛。对于新手小白来说,学习LLM不仅能提升技术水平,还能为职业发展带来巨大的机遇。那么,…

BGP路由反射器

原理概述 缺省情况下,路由器从它的一个 IBGP对等体那里接收到的路由条目不会被该路由器再传递给其他IBGP对等体,这个原则称为BGP水平分割原则,该原则的根本作用是防止 AS内部的BGP路由环路。因此,在AS内部,一般需要每台…

SAP PP学习笔记31 - 计划运行的步骤2 - Scheduling(日程计算),BOM Explosion(BOM展开)

上一章讲了计划运行的5大步骤中的前两步,计算净需求和计算批量大小。 SAP PP学习笔记30 - 计划运行的步骤1 - Net requirements calculation 计算净需求(主要讲了安全库存要素),Lot-size calculation 计算批量大小-CSDN博客 本章继续讲计划运行的后面几…

Golang | Leetcode Golang题解之第283题移动零

题目&#xff1a; 题解&#xff1a; func moveZeroes(nums []int) {left, right, n : 0, 0, len(nums)for right < n {if nums[right] ! 0 {nums[left], nums[right] nums[right], nums[left]left}right} }

vue3前端开发-小兔鲜项目-使用pinia插件完成token的本地存储

vue3前端开发-小兔鲜项目-使用pinia插件完成token的本地存储&#xff01;实际业务开发中&#xff0c;token是一个表示着用户登录状态的重要信息&#xff0c;它有自己的生命周期。因此&#xff0c;这个参数值必须实例化存储在本地中。不能跟着pinia。因为pinia是基于内存设计的模…

使用法国云手机进行面向法国的社媒营销

在当今数字化和全球化的时代&#xff0c;社交媒体已经成为企业营销和拓展市场的重要工具。对于想进入法国市场的企业来说&#xff0c;如何在海外社媒营销中脱颖而出、抓住更多的市场份额&#xff0c;成为了一个关键问题。法国云手机正为企业提供全新的营销工具&#xff0c;助力…

photoshop学习笔记——移动工具

移动工具&#xff0c;可以对图层进行移动&#xff0c;快捷键 V 使用的素材已经放上了&#xff0c;直接下载即可 按住ctrl 可以自动选取&#xff0c;鼠标点击哪个对象&#xff0c;自动选中哪个图层 按住 shift 校正角度&#xff08;只能沿着直线移动&#xff09; 按住 alt 拖…

Redis的分布式锁

目录 一、定义与原理 基于Redis的分布式锁 获取锁 释放锁 锁误删问题&#xff1a;因为key值一样,将别人的锁删掉了 锁误判问题二&#xff1a;判断锁和释放锁不是原子性的 Lua脚本 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁 分布式锁的优点…

Linux驱动开发——字符设备驱动开发

1 概述 1.1 说明 本文是学习rk3568开发板驱动开发的记录&#xff0c;代码依托于rk3568开发板 1.2 字符设备介绍 字符设备是 Linux 驱动中最基本的一类设备驱动&#xff0c;字符设备就是一个一个字节&#xff0c;按照字节流进行读写操作的设备&#xff0c;读写数据是分先后顺…

Navicat Charts Creator for Mac:数据可视化利器

Navicat Charts Creator for Mac是一款专为Mac用户设计的数据可视化工具&#xff0c;它将复杂的数据转化为直观、易懂的图表&#xff0c;帮助用户更好地理解和分析数据。 该软件支持连接到多种数据库&#xff0c;如MySQL、MariaDB、PostgreSQL等&#xff0c;轻松获取实时数据&…