【旅游景点项目日记 | 第二篇】基于Selenium爬取携程网景点详细数据

文章目录

  • 3.基于Selenium爬取携程网景点详细数据
    • 3.1前提环境
    • 3.2思路
    • 3.3代码详讲
      • 3.3.1查询指定城市的所有景点
      • 3.3.2获取详细景点的访问路径
      • 3.3.3获取景点的详细信息
    • 3.4数据库设计
    • 3.5全部代码
    • 3.6效果图

3.基于Selenium爬取携程网景点详细数据

3.1前提环境

  1. 确保安装python3.x环境
  2. 以管理员身份打开cmd,安装selenium、pymysql、datetime,默认安装最新版即可
pip install selenium
pip install pymysql
pip install datetime
  1. 确保chrome安装对应版本的驱动(将该驱动放在chrome安装路径下),用于控制chrome浏览器,并将路径添加到环境变量的Path变量中,如图所示!

    #安装chrome驱动教程链接:
    https://blog.csdn.net/linglong_L/article/details/136283810
    

    image-20240324223035454

3.2思路

  1. 搜索指定城市景点,网站通过分页进行展示
  2. 使用selenium每个景点的详细访问路径,并点击该路径获取详细景点信息,再通过正则表达式获取需要的内容

image-20240324220832823

  1. 如下图,景点的详细信息有:景点名称、景点等级(1-5A)、景点地址、开放时间(有两种,我们采用下面的)、联系电话、景点介绍、景点图片等内容

    image-20240324221249083

3.3代码详讲

3.3.1查询指定城市的所有景点

  • 控制打开chrome,并访问指定查询所有景点路径
    def __init__(self):options = Options()options.add_argument('--headless')service = Service()self.chrome = Chrome(service=service)self.chrome.get('https://huodong.ctrip.com/things-to-do/list?pagetype=city&citytype=dt&keyword=%E6%A2%85%E5%B7%9E&id=523&name=%E6%A2%85%E5%B7%9E&pshowcode=Ticket2&kwdfrom=srch&bookingtransactionid=1711160613361_6064')time.sleep(3)self.page = 1self.headers = {'cookie': 'suid=lh/P1+4RKuhAYg684ErS+g==; suid=lh/P1+4RKuhAYg684ErS+g==','user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',}

3.3.2获取详细景点的访问路径

  • 使用selenium的根据class定位元素方法,找到详细景点的href属性,即为该景点的访问路径
  • 并通过page属性控制访问的页数
	#获取景点请求路径def get_url(self):while True:content = self.chrome.find_element(By.CLASS_NAME, "right-content-list").get_attribute('innerHTML')cons = re.findall(r'href="(.*?)" title="(.*?)"', content)for con in cons:self.detail_url = 'https:' + con[0]self.title = con[1]print(self.detail_url, self.title)self.get_detail()self.chrome.find_element(By.CLASS_NAME,'u_icon_enArrowforward').click()time.sleep(1)self.page += 1if self.page == 120:break

image-20240324222130900

3.3.3获取景点的详细信息

  • 景点的详细信息有:景点名称、景点等级(1-5A)、景点地址、开放时间(有两种,我们采用下面的)、联系电话、景点介绍、景点图片等内容
  • 通过正则表达式获取,详细代码如下:
  • 并每次获取详细信息之后,将信息保存到mysql数据库中
    def get_detail(self):detail_con = requests.get(self.detail_url, verify=False, headers=self.headers).text# time.sleep(2)'''使用正则获取信息'''self.title = ''.join(re.findall(r'<div class="title"><h1>(.*?)<', detail_con, re.DOTALL))print('景点名称:'+self.title)#self.rank = ''.join(re.findall(r'rankText">(.*?)<', detail_con, re.DOTALL))self.address = ''.join(re.findall(r'地址</p><p class="baseInfoText">(.*?)<', detail_con, re.DOTALL))self.mobile = ''.join(re.findall(r'官方电话</p><p class="baseInfoText">(.*?)<', detail_con, re.DOTALL))self.quality_grade= ''.join(re.findall(r'<div class="titleTips"><span>(.*?)<!--', detail_con, re.DOTALL))#self.openTime = ''.join(re.findall(r'开放时间</div><div class="moduleContent">(.*?)<', detail_con, re.DOTALL))first_three_characters = self.address[:3]print('所在省份城市:'+'广东省'+first_three_characters)print('详细地址:'+self.address)#print('开放时间:'+self.openTime)print('电话:'+self.mobile)print('等级:'+self.quality_grade)if self.quality_grade=='':self.quality_grade=0'''使用xpath获取信息'''ret = etree.HTML(detail_con)desc_cons = ret.xpath('//div[@class="detailModule normalModule"]//div[@class="moduleContent"]')desc_titles = ret.xpath('//div[@class="detailModule normalModule"]//div[@class="moduleTitle"]')desc_list = []desc_title_list = []for d in desc_cons:des = ''.join(d.xpath('.//text()'))desc_list.append(des)for d in desc_titles:des = ''.join(d.xpath('.//text()'))desc_title_list.append(des)desc_dict = dict(zip(desc_title_list, desc_list))#print(desc_dict)first_value = list(desc_dict.values())[:2]  # 获取前两个值if len(first_value) >= 1:introduction = first_value[0]else:introduction = ''if len(first_value) >= 2:opening_hours = first_value[1]else:opening_hours = ''print('介绍:'+introduction)print('开放时间:'+ opening_hours)'''获取图片链接'''img_list = []imgs = re.findall(r'background-image:url\((.*?)\)', detail_con, re.DOTALL)for img in imgs:'''匹配到的同一张图片会有两种尺寸,我们只要大图,所以把尺寸为521*391的匹配出来即可'''image = re.search(r'521_391', img)if image:img_list.append(img)print(",".join(img_list))conn = pymysql.connect(host='localhost', user='root', password='root',database='travel_ams', charset='utf8mb4')cursor = conn.cursor()sql = "INSERT INTO ams_attraction (attraction_name, quality_grade, province_city, location, open_hour, phone, introduction, images, add_time) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)"values = (self.title, self.quality_grade, '广东省'+first_three_characters, self.address, opening_hours, self.mobile, introduction,",".join(img_list)  ,datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))cursor.execute(sql, values)conn.commit()conn.close()#self.get_ticket()

3.4数据库设计

travel_ams数据库的ams_attraction表

字段名字段类型是否为主键是否有唯一约束是否有非空约束注释
attraction_idint景点id,自增
attraction_namevarchar(20)景点名称
resource_type_idint景点资源类型id
quality_gradeint景点等级
province_cityvarchar(20)景点所在省份城市
locationvarchar(1000)详细位置
open_hourvarchar(1000)开放时间
phonevarchar(1000)电话
introductionvarchar(10000)景点介绍
imagesvarchar(1000)景点图片列表
stausint状态【1为显示,0为不显示】
add_timedatetime添加时间
update_timedatetime修改时间

创建表语句如下:

CREATE TABLE ams_attraction (attraction_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '景点id,自增',attraction_name VARCHAR(20) COMMENT '景点名称',resource_type_id INT COMMENT '景点资源类型id',province_city VARCHAR(20) COMMENT '景点所在省份城市',location VARCHAR(1000) COMMENT '详细位置',open_hour VARCHAR(1000) COMMENT '开放时间',phone VARCHAR(1000) COMMENT '电话',introduction VARCHAR(10000) COMMENT '景点介绍',images VARCHAR(1000) COMMENT '景点图片列表',status INT COMMENT '状态【1为显示,0为不显示】',add_time DATETIME COMMENT '添加时间',update_time DATETIME COMMENT '修改时间'
);

3.5全部代码

  • 执行该main方法,即可完成导入指定访问路径的景点数据
  • 可以在控制台查询是否导入成功
import pandas
import re
import time
import requests
import urllib3
from lxml import etree
from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import pymysql
import datetimeurllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
class Jy_jd(object):def __init__(self):options = Options()options.add_argument('--headless')service = Service()self.chrome = Chrome(service=service)self.chrome.get('https://huodong.ctrip.com/things-to-do/list?pagetype=city&citytype=dt&keyword=%E6%A2%85%E5%B7%9E&id=523&name=%E6%A2%85%E5%B7%9E&pshowcode=Ticket2&kwdfrom=srch&bookingtransactionid=1711160613361_6064')time.sleep(3)self.page = 1self.headers = {'cookie': 'suid=lh/P1+4RKuhAYg684ErS+g==; suid=lh/P1+4RKuhAYg684ErS+g==','user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',}#获取景点请求路径def get_url(self):while True:content = self.chrome.find_element(By.CLASS_NAME, "right-content-list").get_attribute('innerHTML')cons = re.findall(r'href="(.*?)" title="(.*?)"', content)for con in cons:self.detail_url = 'https:' + con[0]self.title = con[1]print(self.detail_url, self.title)self.get_detail()self.chrome.find_element(By.CLASS_NAME,'u_icon_enArrowforward').click()time.sleep(1)self.page += 1if self.page == 120:breakdef get_detail(self):detail_con = requests.get(self.detail_url, verify=False, headers=self.headers).text# time.sleep(2)'''使用正则获取信息'''self.title = ''.join(re.findall(r'<div class="title"><h1>(.*?)<', detail_con, re.DOTALL))print('景点名称:'+self.title)#self.rank = ''.join(re.findall(r'rankText">(.*?)<', detail_con, re.DOTALL))self.address = ''.join(re.findall(r'地址</p><p class="baseInfoText">(.*?)<', detail_con, re.DOTALL))self.mobile = ''.join(re.findall(r'官方电话</p><p class="baseInfoText">(.*?)<', detail_con, re.DOTALL))self.quality_grade= ''.join(re.findall(r'<div class="titleTips"><span>(.*?)<!--', detail_con, re.DOTALL))#self.openTime = ''.join(re.findall(r'开放时间</div><div class="moduleContent">(.*?)<', detail_con, re.DOTALL))first_three_characters = self.address[:3]print('所在省份城市:'+'广东省'+first_three_characters)print('详细地址:'+self.address)#print('开放时间:'+self.openTime)print('电话:'+self.mobile)print('等级:'+self.quality_grade)if self.quality_grade=='':self.quality_grade=0'''使用xpath获取信息'''ret = etree.HTML(detail_con)desc_cons = ret.xpath('//div[@class="detailModule normalModule"]//div[@class="moduleContent"]')desc_titles = ret.xpath('//div[@class="detailModule normalModule"]//div[@class="moduleTitle"]')desc_list = []desc_title_list = []for d in desc_cons:des = ''.join(d.xpath('.//text()'))desc_list.append(des)for d in desc_titles:des = ''.join(d.xpath('.//text()'))desc_title_list.append(des)desc_dict = dict(zip(desc_title_list, desc_list))#print(desc_dict)first_value = list(desc_dict.values())[:2]  # 获取前两个值if len(first_value) >= 1:introduction = first_value[0]else:introduction = ''if len(first_value) >= 2:opening_hours = first_value[1]else:opening_hours = ''print('介绍:'+introduction)print('开放时间:'+ opening_hours)'''获取图片链接'''img_list = []imgs = re.findall(r'background-image:url\((.*?)\)', detail_con, re.DOTALL)for img in imgs:'''匹配到的同一张图片会有两种尺寸,我们只要大图,所以把尺寸为521*391的匹配出来即可'''image = re.search(r'521_391', img)if image:img_list.append(img)print(",".join(img_list))conn = pymysql.connect(host='localhost', user='root', password='root',database='travel_ams', charset='utf8mb4')cursor = conn.cursor()sql = "INSERT INTO ams_attraction (attraction_name, quality_grade, province_city, location, open_hour, phone, introduction, images, add_time) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)"values = (self.title, self.quality_grade, '广东省'+first_three_characters, self.address, opening_hours, self.mobile, introduction,",".join(img_list)  ,datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))cursor.execute(sql, values)conn.commit()conn.close()#self.get_ticket()#获取门票def get_ticket(self):id = self.detail_url.split('/')[-1]print(id)ticket_url = f'https://piao.ctrip.com/ticket/dest/{id}?onlyContent=true&onlyShelf=true'ticket_res = requests.get(ticket_url, verify=False, headers=self.headers).text# time.sleep(1)ticket_ret = etree.HTML(ticket_res)ticket = ticket_ret.xpath('//table[@class="ticket-table"]//div[@class="ttd-fs-18"]/text()')price = ticket_ret.xpath('//table[@class="ticket-table"]//td[@class="td-price"]//strong[@class="ttd-fs-24"]/text()')print(ticket)print(price)'''拿到的列表里可能存在不确定数量的空值,所以这里用while True把空值全部删除,这样才可以确保门票种类与价格正确对应上'''while True:try:ticket.remove(' ')except:breakwhile True:try:price.remove(' ')except:break'''这里多一个if判断是因为我发现有些详情页即便拿到门票信息并剔除掉空值之后仍然存在无法对应的问题,原因是网页规则有变动,所以一旦出现这种情况需要使用新的匹配规则,否则会数据会出错(不会报错,但信息对应会错误)'''if len(ticket) != len(price):ticket = ticket_ret.xpath('//table[@class="ticket-table"]/tbody[@class="tkt-bg-gray"]//a[@class="ticket-title "]/text()')price = ticket_ret.xpath('//table[@class="ticket-table"]//strong[@class="ttd-fs-24"]/text()')while True:try:ticket.remove(' ')except:breakwhile True:try:price.remove(' ')except:breakprint(ticket)print(price)ticket_dict = dict(zip(ticket, price))print(ticket_dict)if __name__ == '__main__':jy_jd = Jy_jd()jy_jd.get_url()

3.6效果图

image-20240324223358077

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

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

相关文章

React高阶组件(HOC)

高阶组件的基本概念 高阶组件&#xff08;HOC&#xff0c;Higher-Order Components&#xff09;不是组件&#xff0c;而是一个函数&#xff0c;它会接收一个组件作为参数并返回一个经过改造的新组件&#xff1a; const EnhancedComponent higherOrderComponent(WrappedCompo…

腾讯云GPU云服务器_GPU云计算_异构计算_弹性计算

腾讯云GPU服务器是提供GPU算力的弹性计算服务&#xff0c;腾讯云GPU服务器具有超强的并行计算能力&#xff0c;可用于深度学习训练、科学计算、图形图像处理、视频编解码等场景&#xff0c;腾讯云百科txybk.com整理腾讯云GPU服务器租用价格表、GPU实例优势、GPU解决方案、GPU软…

HarmonyOS实战开发-如何使用首选项能力实现一个简单示例。

介绍 本篇Codelab是基于HarmonyOS的首选项能力实现的一个简单示例。实现如下功能&#xff1a; 创建首选项数据文件。将用户输入的水果名称和数量&#xff0c;写入到首选项数据库。读取首选项数据库中的数据。删除首选项数据文件。 最终效果图如下&#xff1a; 相关概念 首选…

学习vue3第十节(插槽v-slot)

本节主要介绍一下 v-slot 插槽指令&#xff0c;以及插槽相关内容 1、定义&#xff1a; 子组件给父组件提供使用的一个位置&#xff0c;使用<slot></slot>表示&#xff0c;父组件可以在这个位置填充任何代码&#xff1b; 2、默认插槽 匿名插槽&#xff1a;会自定…

简单使用Swagger

文章目录 1、介绍2、 使用步骤3、 常用注解 1、介绍 Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务(https://swagger.io/)。 它的主要作用是&#xff1a; 使得前后端分离开发更加方便&#xff0c;有利于团队协作 接口的文…

基于SSM非遗视域下喀什旅游网站

ssm非遗视域下喀什旅游网站的设计与实现 摘要 我们的生活水平正在不断的提高&#xff0c;然而提高的一个重要的侧面表现就是更加注重我们的娱乐生活。旅行是我们都喜欢的一种娱乐方式&#xff0c;各式各样的旅行经历给我们带来的喜悦也是大不相同的。带来快乐的同时也因为其复…

微信小程序实现多张照片上传

hello hello~ &#xff0c;这里是 code袁~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;code袁 &#x1f4a5; 所属专栏&…

第一篇:概述、 目录、适用范围及术语 --- IAB/MRC《增强现实(AR)广告(效果)测量指南1.0 》

第一篇&#xff1a;概述、目录、适用范围及术语 - IAB与MRC及《增强现实广告效果测量指南1.0》 --- 我为什么要翻译美国IAB科技公司系列标准 ​​​​​​​​​​​​​​ 翻译计划 第一篇概述—IAB与MRC及《增强现实广告效果测量指南》之目录、适用范围及术语第二篇广告效…

6.3 BP神经网络

在多层感知器被引入的同时&#xff0c;也引入了一个新的问题&#xff1a;由于隐藏层的预期输出并没有在训练样例中给出&#xff0c;隐藏层结点的误差无法像单层感知器那样直接计算得到。 为了解决这个问题&#xff0c;反向传播&#xff08;BP&#xff09;算法被引入&#xff0…

推荐一种Bean注入方式——开发经验

我们都知道三种Bean注入的方式分别是属性注入&#xff0c;setter方法注入&#xff0c;构造器注入。这三种Bean注入的方式各有优缺点&#xff0c;但是相对来说更推荐使用构造器注入的方式。 1、构造器注入的优缺点 优点&#xff1a; 1、可以注入不可变对象 因为构造方法注入是…

Redis技术学习|实战项目记录|商户缓存

学习资料声明 黑马程序员的Redis学习视频&#xff1a;黑马程序员Redis入门到实战教程 需要用到的知识&#xff1a;linux&#xff08;推荐韩顺平老师的教程&#xff0c;学到p30&#xff0c;创建好虚拟机和简单的几个命令就好。&#xff09;SSM。SpringBoot。 还用到了MybatisPl…

mac 解决随机出现的蓝色框

macbookair为什么打字的时候按空格键会出现蓝色框? - 知乎

c#矩阵求逆

目录 一、矩阵求逆的数学方法 1、伴随矩阵法 2、初等变换法 3、分块矩阵法 4、定义法 二、矩阵求逆C#代码 1、伴随矩阵法求指定3*3阶数矩阵的逆矩阵 &#xff08;1&#xff09;伴随矩阵数学方法 &#xff08;2&#xff09;代码 &#xff08;3&#xff09;计算 2、对…

橘子疾病检测4种YOLOV8

橘子检测YOLOV8&#xff0c;检测4种疾病&#xff0c;采用YOLOV8-NANO&#xff0c;训练得到PT模型转换成ONNX&#xff0c;最后OPENCV调用&#xff0c;支持C/PYTHON/ANDROID 橘子检测YOLOV8&#xff0c;检测4种疾病

阿里云4核16G服务器优惠价格26元1个月、149元半年

阿里云4核16G服务器优惠价格26.52元1个月、79.56元3个月、149.00元半年。2024年腾讯云服务器优惠价格表&#xff0c;一张表整理阿里云服务器最新报价&#xff0c;阿里云服务器网整理云服务器ECS和轻量应用服务器详细CPU内存、公网带宽和系统盘详细配置报价单&#xff0c;大家也…

Ubuntu18.04桌面版设置静态IP地址

引用: Ubuntu配置静态IP_ubuntu配置静态ip地址-CSDN博客 正文 默认Unbuntu 18.04 Desktop桌面版使用 netplan 管理网卡网络地址。使用Unbuntu 18.04 桌面版配置&#xff0c;可以通过桌面上的设置图标配置网卡的静态IP地址。 点击桌面右上角下拉框&#xff0c;点击“设置”按…

206.反转链表

刷算法题&#xff1a; 第一遍&#xff1a;1.看5分钟&#xff0c;没思路看题解 2.通过题解改进自己的解法&#xff0c;并且要写每行的注释以及自己的思路。 3.思考自己做到了题解的哪一步&#xff0c;下次怎么才能做对(总结方法) 4.整理到自己的自媒体平台。 5.再刷重复的类…

yolov5训练并生成rknn模型部署在RK3588开发板上,实现NPU加速推理

简介 RK3588是瑞芯微&#xff08;Rockchip&#xff09;公司推出的一款高性能、低功耗的集成电路芯片。它采用了先进的28纳米工艺技术&#xff0c;并配备了八核心的ARM Cortex-A76和Cortex-A55处理器&#xff0c;以及ARM Mali-G76 GPU。该芯片支持多种接口和功能&#xff0c;适…

Python Flask 将数据传递给前端

from flask import Flask, render_templateapp Flask(__name__)app.route("/index") def index():data {name: "张三","age": 18,}return render_template("index2.html", datadata)if __name__ __main__:app.run()<!DOCTYPE ht…

【python 装饰器 - 重试】做一个简易重试装饰器,如果函数执行错误则会自动重新执行,可设置重试次数,对爬虫比较友好

文章日期&#xff1a;2024.03.19 使用工具&#xff1a;Python 类型&#xff1a;装饰器 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&#xff08;直接解密即可&#xff09;&#xff08;crypto-js.js 标准算法&#xff09;&…