Python网络爬虫(三):Selenium--以携程酒店为例

news2024/11/24 7:57:12

1 Selenium简介

        Selenium是一个用于网站应用程序自动化的工具,它可以直接运行在浏览器中,就像真正的用户在操作一样。它相当于一个机器人,可以模拟人类在浏览器上的一些行为,比如输入文本、点击、回车等。Selenium支持多种浏览器,本文以Chrome浏览器为例。chromedriver是一个驱动Chrome浏览器的驱动程序,针对不同的浏览器有不同的driver。

        1.1 Selenium的优缺点

        优点:浏览器能请求到的数据,Selenium同样能请求到,爬虫稳定,适用于所有类型的动态渲染网页。

        缺点:代码量大、容易被反爬、性能低。笔者认为性能低、速度慢是其最大缺点。

2 浏览器基本操作

        浏览器基本操作包括打开浏览器、设置窗口大小、设置打开浏览器位置、关闭浏览器、前进、后退、刷新、获取网页代码等。下面先通过代码来演示如何打开网页并设置浏览器窗口的大小以及打开位置:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options

url = 'https://hotels.ctrip.com/hotels/396376.html#ctm_ref=hp_htl_pt_pro_01'  # 携程上海虹桥宾馆主页
service = Service(executable_path=r'D:\anaconda\Scripts\chromedriver.exe')  # 指定chromedriver位置
opt = Options()
opt.add_argument(
    'user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"')
opt.add_argument('--disable-blink-features=AutomationControlled')  # 隐藏浏览器痕迹
driver = webdriver.Chrome(service=service, options=opt)  # 实例化浏览器对象
# driver.maximize_window()  # 浏览器窗口最大化
# driver.set_window_position(1000, 20)    # 设置浏览器打开位置
# driver.set_window_size(800,800)    # 设置浏览器窗口大小
driver.get(url)  # 打开网页

        接下来演示如何前进、后退、刷新网页。需要注意的是,Selenium打开不同的网页或者进行前进、后退时,都是在同一个窗口下操作的,不会打开新的窗口:

driver.get('https://hotels.ctrip.com/hotels/396376.html#ctm_ref=hp_htl_pt_pro_01')  # 打开携程
time.sleep(1)

url2 = 'https://www.jd.com'    # 打开京东
driver.get(url2)
time.sleep(1)

driver.back()    # 回退
time.sleep(1)

driver.forward()    # 前进
time.sleep(1)

driver.refresh()    # 刷新页面
time.sleep(1)

source = driver.page_source    # 获取当前页面源代码

         接下来用一个表格展示Selenium浏览器的基本操作:

浏览器基本操作
方法说明
get()打开浏览器

maximize_window()

浏览器窗口最大化

set_window_position()

设置浏览器打开位置

set_window_size()

设置浏览器窗口大小
back()回退
forward()前进
        refresh()刷新页面
page_source获取网页源代码
close()关闭当前标签页
quit()退出浏览器

3 网页元素定位

        Selenium抓取网页信息是在开发者工具的Elements选项卡里,Selenium定位网页元素主要通过元素的属性值或者元素在HTML里的路径位置,主要的定位方式如下:

定位方式方法
ID定位driver.find_element(By.ID, 'ID')
name定位driver.find_element(By.NAME, 'NAME')
class定位driver.find_element(By.CLASS_NAME, 'CLASS_NAME')
标签名定位                driver.find_element(By.TAG_NAME, 'TAG_NAME')
xpath定位driver.find_element(By.XPATH, 'XPATH')
CSS选择器定位driver.find_element(By.CSS_SELECTOR, 'CSS_SELECTOR')

        下面来演示如何定位评论标签,并点击,先看下图:

         打开携程任意一个酒店页面,这里以上海虹桥宾馆为例,打开开发者工具,点击Elements选项卡左侧的箭头,然后将鼠标悬停在页面“显示所有...条点评”链接上,点击,开发者工具中就自动定位到了选中的标签,在选中的标签上右击--Copy--Copy XPath,这样就复制了该标签的XPath路径,为“//*[@id="ibu-hotel-detail-head"]/div[2]/div[2]/div[1]/div/div/div[1]/p[2]”,然后调用click()方法点击,代码如下:

element_comment = driver.find_element(By.XPATH,
                                      '//*[@id="ibu-hotel-detail-head"]/div[2]/div[2]/div[1]/div/div/div[1]/p[2]')
element_comment.click()

 4 网页元素操控

        操控网页元素在网页元素定位后才能执行,Selenium可以模拟任何操作,比如单机、右击、拖拉、滚动、复制粘贴或者文本输入等,操作方式可分为三大类:常规操作、鼠标事件操作和键盘事件操作。

        4.1 常规操作

        常规操作包含文本清除、文本输入、单击元素、提交表单、获取元素值等。下面以打开京东首页并在搜索框输入mate60Pro,按回车搜索为例:

import time

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

url = 'https://jd.com'
driver = webdriver.Chrome()
driver.get(url)
driver.maximize_window()
# 输入昵称和密码
input_element = driver.find_element(By.XPATH, '//*[@id="key"]')
input_element.send_keys('mate60Pro', Keys.ENTER)
time.sleep(3)

         上述例子分别执行了打开京东首页、窗口最大化、定位搜索框位置、输入文本“mate60Pro”、键盘按下回车操作。

        下面列出一些实际开发中常见的操作方式:

代码作用
driver.find_element(By.ID, 'X').clear()清除X标签的内容
driver.find_element(By.ID, 'X').location获取元素在网页中的坐标位置,坐标格式:{'y':20, 'x':100}
driver.find_element(By.ID, 'X').get_attribute('id')获取元素的某个属性值
driver.find_element(By.ID, 'X').is_displayed()判断X元素在网页上是否可见
driver.find_element(By.ID, 'X').is_selected()判断X元素是否被选,通常用于checkbox和radio标签,返回值为True或False
“”“selected标签的选值”“”    from selenium.webdriver.support.select import Select
Select(driver.find_element(By.ID, 'X')).select_by_index('2')根据下拉框的索引来选取
Select(driver.find_element(By.ID, 'X')).select_by_index('book')根据下拉框的value属性来选取
Select(driver.find_element(By.ID, 'X')).select_by_visible_text('beijing')根据下拉框的值来选取

 4.2 鼠标事件

        鼠标事件操作由Selenium的ActionChains类来实现。ActionChains类定义了多种鼠标操作方法,具体的操作方法如下表所示:

ActionChains类的鼠标操作方法
操作方法说明示例
perform        执行鼠标事件click(element).perform(),click是鼠标单击事件,perform是执行这个单击事件
reset_actions取消鼠标事件

click(element).reset_actions(),click

是鼠标单击事件,reset_actions是取消单击事件

click鼠标单击click(element),element是某个元素对象
click_and_hold长按鼠标左键click_and_hold(element),element是某个元素对象
context_click长按鼠标右键context_click(element),element是某个元素对象
double_click鼠标双击        double_click(element),element是某个元素对象
drag_and_drop对元素长按左键并移动到另一个元素的位置后释放鼠标左键drag_and_drop(element,element1),element是某个元素对象,element1是目标元素对象
drag_and_drop_by_offset对元素长按左键并移动到指定的坐标位置drag_and_drop_by_offset(element, x, y),element是某个元素对象,x是偏移的x坐标, y是偏移的y坐标
key_down对元素长按键盘中的某个按键        key_down(Keys.CONTROL, element),Keys.CONTROL是由Keys定义的键盘事件,element是某个元素对象
key_up对元素释放键盘中的某个按键key_up(Keys.CONTROL, element),Keys.CONTROL是由Keys定义的键盘事件,element是某个元素对象
move_by_offset对当前鼠标所在位置进行偏移move_by_offset(x, y),x是偏移的x坐标, y是偏移的y坐标
move_to_element将鼠标移动到某个元素所在的位置move_to_element(element),element是某个元素对象
move_to_element_with_offset将鼠标移动到某个元素并偏移一定位置move_to_element_with_offset(element, x, y),element是某个元素对象,x是偏移的x坐标, y是偏移的y坐标
pause设置暂停执行时间pause(60)
release释放鼠标长按操作release(element),element是某个元素对象,如果element为空,对当前鼠标的位置长按操作进行释放
send_keys执行文本输入send_keys(value),value是输入的内容
send_keys_to_element对当前元素执行文本输入send_keys_to_element(element, value), element是某个元素对象,value是输入的内容

        以上方法都是在ActionChains类所定义的类方法,若想使用这些操作方法,必须将ActionChains类实例化后才能调用。以B站的登录页面为例,通过鼠标操作方法去双击网页中的“登录”按钮。

        

import time

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains

url = 'https://passport.bilibili.com/login'
driver = webdriver.Chrome()
driver.get(url)
driver.maximize_window()
time.sleep(1)
# 输入昵称和密码
element = driver.find_element(By.CLASS_NAME, 'btn_primary disabled')
ActionChains(driver).double_click(element).perform()
time.sleep(3)

        上述代码中,首先将ActionChains实例化,实例化的时候传入driver对象。实例化之后就可以直接调用鼠标事件操作方法,这些方法需要传入element对象,element是网页中某个标签元素。最后再调用perform方法,这是一个执行命令,因为鼠标可以执行拖拉、长按等持久性的操作,调用perform方法可以让这个鼠标操作马上执行。

        4.3 键盘事件

        键盘事件是模拟人为按下键盘的某个按键,主要通过send_keys方法来实现。以百度搜索为例,利用键盘的快捷键实现搜索内容的变换。代码如下:

import time

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

url = 'https://www.baidu.com'
driver = webdriver.Chrome()
driver.get(url)

# 获取输入框标签对象
element = driver.find_element(By.XPATH, '//*[@id="kw"]')
element.send_keys('我爱python')
time.sleep(2)

# 删除最后的一个文字
element.send_keys(Keys.BACK_SPACE)
time.sleep(2)

# 添加输入空格键和“教程”
element.send_keys(Keys.SPACE)
element.send_keys('教程')
time.sleep(2)

# ctrl+a 全选输入框内容
element.send_keys(Keys.CONTROL, 'a')
time.sleep(2)

# ctrl+x 剪切输入框内容
element.send_keys(Keys.CONTROL, 'x')
time.sleep(2)

# ctrl+v 粘贴内容到输入框
element.send_keys(Keys.CONTROL, 'v')
time.sleep(2)

# 通过回车键来代替单击操作
driver.find_element(By.ID, 'su').send_keys(Keys.ENTER)

 5 携程酒店评论采集

        先看一下采集的评论:

        附上完整代码:

import csv
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.common.action_chains import ActionChains
from lxml import etree


class XcSpider:
    def __init__(self):
        self.opt = Options()
        self.opt.debugger_address = '127.0.0.1:8888'
        self.opt.add_argument(
            'user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36"')
        self.opt.add_argument('--incognito')
        self.opt.add_argument('--disable-blink-features=AutomationControlled')  # 隐藏浏览器痕迹
        self.service = Service(executable_path=r'D:\anaconda\Scripts\chromedriver.exe')
        self.driver = webdriver.Chrome(options=self.opt, service=self.service)
        self.driver.implicitly_wait(10)
        self.f = open('携程酒店评论.csv', 'a', encoding='utf-8-sig', newline='')
        self.writer = csv.DictWriter(self.f,
                                     fieldnames=['score', 'brief_comment', 'content', 'time_location', 'username',
                                                 'room_type', 'room_type2', 'checkin', 'comment_num'])
        self.writer.writeheader()

    def fetch_source(self, url):

        self.driver.get(url)
        time.sleep(3)
        self.driver.find_element(by=By.XPATH,
                                 value='//*[@id="ibu-hotel-detail-head"]/div[2]/div[2]/div[1]/div/div/div[1]/p[2]').click()
        source = self.driver.page_source
        self.parse_html(source)
        ActionChains(driver=self.driver).move_by_offset(400, 400).perform()
        time.sleep(3)
        # 执行js代码,滚动条往下拉500像素
        js = "window.scrollTo(0,500);"
        self.driver.execute_script(js)
        count = 1
        while count < 235:
            print(f'正在爬取第{count}页数据...')
            count += 1
            next_button = self.driver.find_element(by=By.XPATH,
                                                   value='//*[@id="ibu_hotel_review"]/div/ul[2]/li/div/div[2]/div[2]/div[12]/ul/li[3]/a/i')
            next_button.click()
            time.sleep(1)
            source = self.driver.page_source
            self.parse_html(source)
            self.driver.execute_script(js)

    def parse_html(self, source):
        tree = etree.HTML(source)
        div_list = tree.xpath('//*[@id="ibu_hotel_review"]/div/ul[2]/li/div/div[2]/div[2]/div[position() < 11]')
        for div in div_list:
            score = div.xpath('./div/div[2]/div[1]/div/div[1]/strong/text()')
            score = self.handle_list(score)
            brief_comment = div.xpath('./div/div[2]/div[1]/div/div[2]/text()')
            brief_comment = self.handle_list(brief_comment)
            content = div.xpath('./div/div[2]/div[2]/p/text()')
            content = self.handle_list(content)
            time_location = div.xpath('./div/div[2]/div[3]/div[2]/text()')
            time_location = self.handle_list(time_location)
            username = div.xpath('./div/div[1]/div[1]/div/p/text()')
            username = self.handle_list(username)
            room_type = div.xpath('./div/div[1]/div[2]/ul/li[1]/span/text()')
            room_type = self.handle_list(room_type)
            checkin = div.xpath('./div/div[1]/div[2]/ul/li[2]/span/text()')
            checkin = self.handle_list(checkin)
            room_type2 = div.xpath('./div/div[1]/div[2]/ul/li[3]/span/text()')
            room_type2 = self.handle_list(room_type2)
            comment_num = div.xpath('./div/div[1]/div[2]/ul/li[4]/span/text()')
            comment_num = self.handle_list(comment_num)
            dit = {
                'score':score,
                'brief_comment': brief_comment,
                'content': content,
                'time_location': time_location,
                'username': username,
                'room_type': room_type,
                'room_type2': room_type2,
                'checkin': checkin,
                'comment_num': comment_num,
            }
            self.writer.writerow(dit)

    def handle_list(self, xpath_list):
        if xpath_list:
            xpath_list = xpath_list[0].strip()
            return xpath_list
        else:
            return ''

    def main(self):
        self.fetch_source('https://hotels.ctrip.com/hotels/396376.html#ctm_ref=hp_htl_pt_pro_01')
        self.f.close()


if __name__ == '__main__':
    XS = XcSpider()
    XS.main()

                

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据分析之POWER BI Desktop可视化应用案列

在power bi中导入数据 导入前期建好的模型 简单介绍&#xff08;power bi desktop&#xff09; 将右边字段全部展开 各类数据 所作的模型 在excel中是单向的&#xff0c;power bi 中可以是双向的 右键单击----点击属性 选择两个---在两个方向上应用安全筛选器 变为双向的…

wireshark解析grpc/protobuf的方法

1&#xff0c;wireshark需要安装3.20以上 下载地址&#xff1a;https://www.wireshark.org/ 2&#xff0c;如果版本不对&#xff0c;需要卸载&#xff0c;卸载方法&#xff1a; sudo rm -rf /Applications/Wireshark.app sudo rm -rf $HOME/.config/wireshark sudo rm -rf /…

c++|vector使用及模拟实现

目录 一、vector的介绍 二、vector的使用(常用接口) 2.1string类的成员函数 2.1.1构造函数 2.1.2析构函数 2.1.3“”运算符重载函数 2.2 迭代器(iterator) 及 对象的遍历访问 2.2.1iterator 2.2.2 operator[] && at() 2.2.4 back() && front() 2.2…

认识什么是Git

目录 1. 认识Git 1.1. 问题引入 1.2. 概念 1.3. 作用 1.4. 如何学 1.5. Git 安装 1.6. Git配置用户信息 2. Git仓库 2.1. Git 仓库&#xff08;repository&#xff09; 2.2. 创建 2.3. 需求 3. Git的三个区域 3.1. Git 使用时的三个区域 3.2. 工作区的内容&#…

5.动态规划

1.背包问题 (1)0/1背包问题 01背包问题即每个物品只能选1个 考虑第i件物品&#xff0c;当j<w[i]时&#xff0c;f[i][j]f[i-1][j]&#xff0c;当j>w[i]时&#xff0c;此时有两种选择&#xff0c;选择第i件物品和不选第i件物品。此时f[i][j]max(f[i-1][j],f[i-1][j-w[i]]v…

c++20协程详解(一)

前言 本文是c协程第一篇&#xff0c;主要是让大家对协程的定义&#xff0c;以及协程的执行流有一个初步的认识&#xff0c;后面还会出两篇对协程的高阶封装。 在开始正式开始协程之前&#xff0c;请务必记住&#xff0c;c协程 不是挂起当前协程&#xff0c;转而执行其他协程&a…

789. 数的范围 (二分学习)左端大右,右端小左

题目链接https://www.acwing.com/file_system/file/content/whole/index/content/4317/ 当求左端点时&#xff0c;条件是a【mid】大于等于x&#xff0c;并把右端点缩小。 当求右端点时&#xff0c;条件是a【mid】小于等于x&#xff0c;并把左端点扩大。 1.确定一个区间&…

面试复盘1 - 测试相关(实习)

写在前&#xff1a;hello&#xff0c;大家早中晚上好~这里是西西&#xff0c;最近有在准备测试相关的面试&#xff0c;特此开设了新的篇章&#xff0c;针对于面试中的问题来做一下复盘&#xff0c;会把我自己遇到的问题进行整理&#xff0c;除此之外还会进行对一些常见面试题的…

CentOSPython使用openpyxl、pandas读取excel报错

一、openpyxl报错 由于本人在centos7下使用python的openpyxl报错,所以决定使用强大的pandas。 pandas是一个快速、强大、灵活且易于使用的开源数据操作和分析工具,建立在Python语言之上。 pandas是一个广泛使用的数据分析库,它提供了高效的数据结构和数据分析工具。pandas…

new mars3d.layer.HeatLayer({实现动态修改热力图半径

1.使用热力图插件的时候&#xff0c;实现动态修改热力图效果半径 2.直接修改是不可以的&#xff0c;因为这个是热力图本身的参数。 因此我们需要拿到这个热力图对象之后&#xff0c;参考api文档&#xff0c;对整个 heatLayer.heatStyle进行传参修改。 heatStyle地址&#x…

SSL通配符证书怎么选?看这里

通配符证书&#xff0c;作为一种特殊的数字证书类型&#xff0c;以其独特的优势在网络安全领域扮演着重要角色。相较于传统的单一域名证书&#xff0c;通配符证书能够为同一主域名下的所有子域名提供安全保护&#xff0c;显著提升管理效率&#xff0c;简化证书部署流程&#xf…

【深度学习】sdwebui的token_counter,update_token_counter,如何超出77个token的限制?对提示词加权的底层实现

文章目录 前言关于token_counter关于class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing)如何超出77个token的限制&#xff1f;对提示词加权的底层实现Overcoming the 77 token limit in diffusers方法1 手动拼方法2 compel 问询、帮助请看&#xff1a; 前言 …

[已解决] slam_gmapping: undefined symbol: _ZN8GMapping14sampleGaussianEdm问题

之前用的好好的gampping建图功能包&#xff0c;今天突然不能用了&#xff0c;运行报错如下&#xff1a; /opt/ros/noetic/lib/gmapping/slam_gmapping: symbol lookup error: /opt/ros/noetic/lib/gmapping/slam_gmapping: undefined symbol: _ZN8GMapping14sampleGaussianEdm …

首场直播,就在4月11日!

2024年的第一场直播&#xff0c;我们把目光聚焦到“大会员”。 这一次我们想聊聊&#xff0c;当大会员遇上泛零售企业&#xff0c;会产生怎样的“火花”。泛零售企业突破增长压力的机会在哪里&#xff1f;又有哪些挑战必须直面&#xff1f; 本次直播将结合泛零售企业“多业态、…

双机 Cartogtapher 建图文件配置

双机cartogtapher建图 最近在做硕士毕设的最后一个实验&#xff0c;其中涉及到多机建图&#xff0c;经过调研最终采用cartographer建图算法&#xff0c;其中配置多机建图的文件有些麻烦&#xff0c;特此博客以记录 非常感谢我的同门 ”叶少“ 山上的稻草人-CSDN博客的帮助&am…

Chrome 设置在新窗口中打开链接(已登录google账号版)

Chrome的链接默认是在原标签页中打开的&#xff0c;如果要在新窗口中打开&#xff0c;需要自己自行设置&#xff0c;在此&#xff0c;针对已经登录google账号的chrome浏览器怎么进行设置进行说明。 一、点击登录图标->更多设置 二、选择其他设置->在新窗口中打开搜索结果…

Linux上管理文件系统

Linux上管理文件系统 机械硬盘 机械硬盘由多块盘片组成&#xff0c;它们都绕着主轴旋转。每块盘片上下方都有读写磁头悬浮在盘片上下方&#xff0c;它们与盘片的距离极小。在每次读写数据时盘片旋转&#xff0c;读写磁头被磁臂控制着不断的移动来读取其中的数据。 所有的盘片…

一套C#自主版权+应用案例的手麻系统源码

手术麻醉信息管理系统源码&#xff0c;自主版权应用案例的手麻系统源码 手术麻醉信息管理系统包含了患者从预约申请手术到术前、术中、术后的流程控制。手术麻醉信息管理系统主要是由监护设备数据采集子系统和麻醉临床系统两个子部分组成。包括从手术申请到手术分配&#xff0c…

SSM框架学习——JSP语法入门

JSP语法入门 前提 在前一节中我们已经写过JSP的代码了&#xff0c;这一节将单独介绍JSP一些基础语法。当然&#xff0c;你可以跳过这一节&#xff0c;当后面有代码不太理解的时候再回来阅读。 中文编码问题 如果中文乱码&#xff0c;看看JSP是否是以UTF8的方式编码&#xf…

mysql建表必须知道的18个重点(荣耀典藏版)

大家好&#xff0c;我是月夜枫&#xff0c;又和大家见面了&#xff01;&#xff01;&#xff01;&#xff01; 目录 前言 1.名字 1.1 见名知意 1.2 大小写 1.3 分隔符 1.4 表名 1.5 字段名称 1.6 索引名 2.字段类型 3.字段长度 4.字段个数 5. 主键 6.存储引擎 7.…