当前位置: 首页 > news >正文

爬虫学习--18.反爬斗争 selenium(3)

操作多窗口与页面切换

  • 有时候窗口中有很多子tab页面。这时候肯定是需要进行切换的。selenium提供了一个叫做switch_to.window来进行切换,具体切换到哪个页面,可以从driver.window_handles中找到。

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
import time

# 加载驱动
driver = webdriver.Chrome()

# 拿到目标url # 这个时候发现同时拿到两个url 不能够打开两个窗口
# 访问百度
driver.get("https://www.baidu.com")
# driver.get("https://www.douban.com")
time.sleep(2)

# 访问豆瓣
driver.execute_script("window.open('https://www.douban.com')")
time.sleep(2)

# driver.close()  # 此时发现百度被关闭了
# 检测当前驱动执行的url
print(driver.current_url)
# # 那这个时候我们操作多窗口防护变了没有了意义 因为我们只能操作第一个百度 那这个时候我就可以切换一下界面
# # 切换界面
driver.switch_to.window(driver.window_handles[1])
# # [1] 0代表的第一个最开始打开的那个 1代表的第二个  -1切换到最新打开的窗口   -2 倒数第二个打开的窗口
print(driver.current_url)  # 检测看是否切换到豆瓣的url了
time.sleep(1)
# driver.switch_to.window(driver.window_handles[0])
# time.sleep(1)
# # 检测看是否能对百度进行操作
# driver.find_element(By.ID,"kw").send_keys("python")

# 切换iframe
login_iframe = driver.find_element(By.XPATH,'//*[@id="anony-reg-new"]/div/div[1]/iframe')
driver.switch_to.frame(login_iframe)
time.sleep(2)
# 1 切换登录方式 定位到 密码登录(但是在这一步操作之前 要确实是否要切换iframe)
driver.find_element(By.CLASS_NAME,"tab-start").click()
time.sleep(2)
# 2 输入账号和密码
user_input = driver.find_element(By.ID,"username").send_keys("123456789")
time.sleep(2)
pwd_input = driver.find_element(By.ID,"password").send_keys("123456789")
time.sleep(2)
# 3 点击登录豆瓣
# 定位登录按钮点击 我们在定位元素的时候 如果属性出现空格的状态 形如:btn btn-account
# 解决方式 第一种我们选择属性当中的一部分(需要测试)
driver.find_element(By.CLASS_NAME,'btn-account').click()
time.sleep(3)

Selenium执行js语法

有时候selenium提供的方法会出现一些问题,或者执行起来非常麻烦,我们就可以考虑通过selenium执行javascript来实现,使复杂的操作简单化。 selenium执行js脚本的方法:

execute_script(script, *args)
描述:用来执行js语句
参数:
script:待执行的js语句,如果有多个js语句,使用英文分号;连接

常见selenium下执行js代码

1 滚动页面:您可以使用 JavaScript 滚动网页以将元素显示在视图中或在页面上移动
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)') 

2 js点击: 
button = driver.find_element(By.CLASS_NAME),'my-button')
driver.execute_script("arguments[0].click();", button)

3 等待元素出现:有时候,您需要等待一个元素出现或变为可见状态后再与它进行交互。
您可以使用JavaScript等待元素出现或变为可见状态后再进行交互。
# 等待元素在页面上可见
element = driver.find_element(By.CSS_SELECTOR,'#my-element')
driver.execute_script("""
    var wait = setInterval(function() {
        if (arguments[0].offsetParent !== null) {
            clearInterval(wait);
            // 元素现在可见,可以对其进行操作
        }
    }, 100);
""", element)

4 执行自定义JavaScript:使用execute_script方法可以执行您编写的任何自定义 JavaScript 代码,
以完成测试或自动化任务。
driver.execute_script("console.log('Hello, world!');")

5 打开多窗口 
driver.execute_script("window.open('https://www.douban.com')")

** 这一块的只是示例 不用同学们进行记忆 但是我们可以积累 **

Selenium高级语法

  • page_source (elements源代码)

  • find() (在网页源码中寻找某个字符串是否存在)

  • find_element(By.LINK_TEXT) (根据链接文本获取 一般处理翻页)

  • node.get_attribute (node 代表的是节点名 get_attribute代表的是获取属性名)

  • node.text() (获取节点的文本内容 包含子节点和后代节点)

from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
import time

# 加载驱动
driver = webdriver.Chrome()

# 访问百度
# driver.get('https://www.baidu.com/')

""" 
1拿到百度的数据结构源码 page_source  
这个指的不是网页源代码而是我们前端页面最终渲染的结果也就是我们element中的数据
"""
# html = driver.page_source
# print(html)

"""
2 find() 在html源码中查找某个字符是否存在
如果存在则会返回一段数字  如果不存在 不会报错 但是会返回-1
find应用场景 比如翻页爬取 
"""
# print(html.find("kw"))
# print(html.find("kwwwwwwwwwwwwwwwwwww"))

""" 3 find_element_by_link_text("链接文本") 
# driver.get('https://www.gushiwen.cn/')
# time.sleep(3)
# # 根据链接文本内容定位按钮
# driver.find_element(By.LINK_TEXT,'下一页').click()  # 点击豆瓣第一页的下一页
# # 画面会跳转到第二页 打印的是第二页的源码
# time.sleep(3)
# print(driver.page_source)

"""4 node.get_attribute("属性名")  node代表的是你想获取的节点 """

# url = 'https://movie.douban.com/top250'
# driver.get(url)
# a_tag = driver.find_element(By.XPATH,'//div[@class="item"]/div[@class="pic"]/a')
# print(a_tag.get_attribute('href'))

""" 5 node.text 获取节点的文本内容 包含子节点和后代节点 """
# driver.get('https://movie.douban.com/top250')
# time.sleep(2)
# div_tag = driver.find_element(By.XPATH,'//div[@class="hd"]')
# print(div_tag.text)

Selenium设置无界面模式

绝大多数服务器是没有界面的,selenium控制谷歌浏览器也是存在无界面模式的(又称之为无头模式) 开启无界面模式的方法

  • 实例化配置对象

options = webdriver.ChromeOptions()

  • 配置对象添加开启无界面模式的命令

options.add_argument("--headless")

  • 配置对象添加禁用gpu的命令

options.add_argument("--disable-gpu")

  • 实例化带有配置对象的driver对象

driver = webdriver.Chrome(chrome_options=options)

from selenium import webdriver

# 创建一个配置对象
options = webdriver.ChromeOptions()
# 开启无界面模式
options.add_argument('--headless')
# 实例化带有配置的driver对象
driver = webdriver.Chrome(options=options)

driver.get('http://www.baidu.com/')
html = driver.page_source
print(html)
driver.quit()

Selenium被识别问题解决方案

selenium做爬虫能解决很多反爬问题,但是selenium也有很多特征可以被识别,比如用selenium驱动浏览器后window.navigator.webdriver值是true,而正常运行浏览器该值是未定义的(undefined)

 

import time

from selenium import webdriver

# 使用chrome开发者模式
options = webdriver.ChromeOptions()
options.add_experimental_option('excludeSwitches', ['enable-automation'])

# 禁用启用Blink运行时的功能
options.add_argument("--disable-blink-features=AutomationControlled")

# Selenium执行cdp命令  再次覆盖window.navigator.webdriver的值
driver = webdriver.Chrome(options=options)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
    "source": """
                    Object.defineProperty(navigator, 'webdriver', {
                      get: () => undefined
                    })
                  """
})


driver.get('https://www.baidu.com/')

time.sleep(3)

Selenium综合案例之当当网书籍信息爬取

import csv
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
"""
爬取当当网python爬虫书籍信息并保存到csv文件中 
"""

class DDspider:
    # 初始化方法
    def __init__(self):
        # 加载驱动
        self.driver = webdriver.Chrome()

        # 发起请求
        self.driver.get('http://www.dangdang.com/')

        # 窗口最大化
        # self.driver.maximize_window()

        # 定位输入框
        ipt_tag = self.driver.find_element(By.ID, 'key_S')
        ipt_tag.send_keys('python爬虫')
        time.sleep(1)

        # 定位搜索框
        serach_ipt = self.driver.find_element(By.CLASS_NAME, 'button')
        serach_ipt.click()
        time.sleep(1)

    # 解析目标数据
    def Getitem(self):
        # 将滚轮拉到底部为的是让全部的source进行加载完全
        """想办法把滚轮拖动到最后"""
        # window.scrollTo 拖动滚轮 第一个参数0 表示从起始位置开始拉 第二个参数表示的是整个窗口的高度
        self.driver.execute_script(
            'window.scrollTo(0,document.body.scrollHeight)'  # 这一点属于js代码 不需要死记 但是需要积累
        )
        time.sleep(1)

        lilist = self.driver.find_elements(By.XPATH, '//ul[@id="component_59"]/li')
        print(len(lilist))

        # 定义列表用于存放一页中所有书的信息
        books = []
        for i, item in enumerate(lilist):
            try:
                # 定义字典用于存放每一本书的信息
                book = {}
                # 书图
                if i == 0:
                    book['img'] = item.find_element(By.XPATH, './a/img').get_attribute('src')
                else:
                    book['img'] = 'https:' + item.find_element(By.XPATH, './a/img').get_attribute('data-original')

                # 书名
                book['name'] = item.find_element(By.XPATH, './p[@class="name"]/a').get_attribute('title')

                # 价格
                book['price'] = item.find_element(By.XPATH, './p[@class="price"]/span').text

                # 作者
                book['author'] = item.find_element(By.XPATH, './p[@class="search_book_author"]/span[1]').text

                # 出版时间
                book['Publication_time'] = item.find_element(By.XPATH, './/p[@class="search_book_author"]/span[2]').text

                # 出版社
                book['Publishing_house'] = item.find_element(By.XPATH, './/p[@class="search_book_author"]/span[3]').text

                books.append(book)
            except Exception as e:
                print(e.__class__.__name__)

        # print(books,len(books))
        return books

    # 翻页函数
    def Next_page(self):
        alldata = []
        while True:
            books = self.Getitem()
            alldata += books
            print(len(alldata),"*" * 50)
            if self.driver.page_source.find("next none") == -1:
                next_tag = self.driver.find_element(By.XPATH, '//li[@class="next"]/a')
                self.driver.execute_script("arguments[0].click();", next_tag)
                time.sleep(1)
            else:
                self.driver.quit()
                break
        return alldata

    # 写入数据
    def WriteData(self,alldata):
        headers = ('img', 'name', 'price', 'author','Publication_time','Publishing_house')
        with open('当当.csv', mode='w', encoding='utf-8', newline="")as f:
            writer = csv.DictWriter(f, headers)
            writer.writeheader()  # 写入表头
            writer.writerows(alldata)

if __name__ == '__main__':
    DD = DDspider()
    alldata = DD.Next_page()
    DD.WriteData(alldata)
 

相关文章:

  • Inno Setup磁盘跨越必须启用,因为程序大于21000000000
  • 解析Java中1000个常用类:Error类,你学会了吗?
  • 考CCIE的难点在哪?英语不好?
  • 等保系列之——网络安全等级保护测评工作流程及工作内容
  • 解决 git 命令 Problem with the SSL CA cert (path? access rights?)
  • 反射、类加载、静态代理,jdk动态代理,cglib代理
  • java8 stream流的用法
  • 命令模式(行为型)
  • spring分析工具_springboot startup analyze的部署和使用
  • 「vue同一个组件,不同路由切换时界面没有更新问题」
  • mysql - 为什么MySQL不建议使用NULL作为列默认值?
  • git仓库迁移
  • 【Linux】操作系统之冯诺依曼体系
  • 用HAL库改写江科大的stm32入门-6-3 PWM驱动LED呼吸灯
  • html中 table的 colspan和rowspan
  • 03Go 类型总结
  • Apache Zeppelin在Apache Trafodion上的可视化
  • echarts的各种常用效果展示
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • IP路由与转发
  • JavaScript HTML DOM
  • React中的“虫洞”——Context
  • Redis中的lru算法实现
  • Vue ES6 Jade Scss Webpack Gulp
  • Wamp集成环境 添加PHP的新版本
  • 成为一名优秀的Developer的书单
  • 飞驰在Mesos的涡轮引擎上
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 来,膜拜下android roadmap,强大的执行力
  • 深入 Nginx 之配置篇
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 我与Jetbrains的这些年
  • 译米田引理
  • 智能合约开发环境搭建及Hello World合约
  • 中文输入法与React文本输入框的问题与解决方案
  • Play Store发现SimBad恶意软件,1.5亿Android用户成受害者 ...
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • #大学#套接字
  • (16)Reactor的测试——响应式Spring的道法术器
  • (2.2w字)前端单元测试之Jest详解篇
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (分布式缓存)Redis持久化
  • (紀錄)[ASP.NET MVC][jQuery]-2 純手工打造屬於自己的 jQuery GridView (含完整程式碼下載)...
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • (转)树状数组
  • *上位机的定义
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .NET牛人应该知道些什么(2):中级.NET开发人员
  • .NET企业级应用架构设计系列之应用服务器
  • .Net下的签名与混淆
  • /deep/和 >>>以及 ::v-deep 三者的区别