• 爬虫之selenium


    selenium基本操作

    • 概念:基于浏览器自动化的模块

      • appnium:基于手机自动化的模块的应用
    • 环境的安装

      • pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
    • 跟爬虫之间的关联?

      • 可以实现模拟登陆
      • 便捷的捕获动态加载数据(可见即可得)
    • 基本操作

      • 导包:from selenium import webdriver(web浏览器,driver驱动)

      • 必须提供对应浏览器的驱动程序(谷歌,火狐...)

      • 实例化一个浏览器对象

        bro = webdriver.Chrome(executable_path='./chromedriver.exe')
        # Chrome 谷歌浏览器 executable_path 浏览器驱动路径
        
      • 标签定位

        • find系列的函数
      • 标签对象.send_keys():向指定标签中录入数据

      • 提交标签.click()

      • js注入:浏览器对象.execute_script("js代码")

      • 浏览器对象.page_source :返回当前页面的页面源码数据,包含动态加载数据

      • 关闭浏览器:浏览器对象.quit()

    • 缺点

      • 爬取的效率比较低下
    • 什么时候用selenium

      • 动态加载的数据requests模块实在爬取不到,使用selenium

    示例代码

    • 登陆京东,搜索商品
    from selenium import webdriver
    from time import sleep
    
    # 实例化浏览器对象
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')   # Chrome 谷歌浏览器 executable_path 浏览器驱动地址 
    # 制定一些自动化的操作
    
    # 发起请求
    bro.get('https://www.jd.com')
    # 如何进行标签定位
    search_tag = bro.find_element_by_id('key')
    # 向文本框中录入数据
    search_tag.send_keys('mac pro')
    sleep(2)
    btn = bro.find_element_by_xpath('//*[@id="search"]/div/div[2]/button')
    btn.click()
    sleep(2)
    # 注入JS代码
    bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    sleep(2)
    # page_source :返回当前页面的页面源码数据,包含动态加载数据
    print(bro.page_source)
    
    # 关闭浏览器
    bro.quit()
    

    案例:使用selenium捕获要药监总局的动态加载数据

    • 该网站的数据是动态加载的,来测试selenium如何便捷的捕获动态加载数据
    • 网址:http://125.35.6.84:81/xk/
    from selenium import webdriver
    from time import sleep
    from lxml import etree
    
    # 实例化浏览器对象
    bro = webdriver.Chrome(executable_path='./chromedriver.exe')
    # 发起请求
    bro.get('http://125.35.6.84:81/xk/')
    sleep(1)
    # 第一页的页面源码数据
    page_text = bro.page_source
    all_page_text = [page_text]
    for i in range(1,5):
        # 找到下一页对应的标签
        a_tag = bro.find_element_by_xpath('//*[@id="pageIto_next"]')
        # 对下一页的标签发起点击
        a_tag.click()
        sleep(1)
        # page_source 获取当前页面的源码数据(涵动态加载)
        page_text = bro.page_source
        all_page_text.append(page_text)
    for page_text in all_page_text:
        tree = etree.HTML(page_text)
        # xpath解析到name对应的标签
        li_lst = tree.xpath('//*[@id="gzlist"]/li')
        for li in li_lst:
            name = li.xpath('./dl/@title')[0]
            print(name)
    sleep(2)
    bro.quit()
    

    动作链

    动作链:一系列连续的动作

    • 导包:from selenium.webdriver import ActionChains
    • NoSuchElementException报错:没有定位到指定的标签
      • 定位的标签是存在于一张嵌套的子页面中,如果想定位之页面中的指定标签的话需要:
        • 浏览器对象.switch_to.frame('iframe标签id的属性值'):将当前浏览器页面切换到指定的子页面范围中
    • 针对指定的浏览器实例化一个动作链对象
      • action = ActionChains(bro)
    • 点击且长按指定的标签
      • action.click_and_hold(tagName)
    • 偏移
      • action.move_by_offset(xoffset, yoffset) 一点一点偏移
      • action.move_to_element(to_element)
      • action.move_to_element_with_offset(to_element, xoffset, yoffset)
    • 偏移.perform():动作链立即执行

    示例代码

    from selenium import webdriver
    from selenium.webdriver import ActionChains
    from time import sleep
    
    bro = webdriver.Chrome("./chromedriver.exe")
    bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
    
    # 标签定位
    bro.switch_to.frame('iframeResult')
    div_tag = bro.find_element_by_id('draggable')
    
    # 需要使用ActionChains定制好的行为动作
    
    # 针对当前浏览器页面实例化了一个动作链对象
    action = ActionChains(bro)
    # 点击且长按一个指定的标签
    action.click_and_hold(div_tag)
    
    for i in range(1,7):
        # 一点一点迁移
        action.move_by_offset(10,15).perform()  # perform() 是动作链立即执行
        action.move_to_element
        action.move_to_element_with_offset
        sleep(0.5)
    

    无头浏览器

    • 概念:没有可视化界面的浏览器
    • phantomJS无头浏览器,几乎不用了,停止更新维护了,现在不用了

    谷歌无头浏览器

    • 就是本机安装的谷歌浏览器,只是需要通过代码进行相关配置就可以变成无头浏览器
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    
    # 无头浏览器开整
    # 实例化options对象
    chrome_options = Options()
    # 调用add_argument方法,进行自定义配置
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--disable-gpu')
    
    bro = webdriver.Chrome(executable_path="./chromedriver.exe",chrome_options=chrome_options)
    bro.get('https://www.baidu.com')
    # 截屏
    bro.save_screenshot('./1.png')
    print(bro.page_source)
    

    规避检测

    • webServer是如何检测到我们的请求是否使用了selenium

      • 网站开发者工具Consloe中注入js代码:window.navigator.webdriver
        • true:请求是基于selenium发起的(异常请求)
        • undefined:请求是基于浏览器发起的(正常请求)
    • 环境配置

      • 本机谷歌浏览器的驱动程序所在的目录路径添加到环境变量中

      • 使用本机谷歌的驱动程序开启一个浏览器

        • chrome.exe --remote-debugging-port=9222 --user-data-dir="D:selenumAutomationProfile"

          9222:端口(任意空闲端口)

          "D:selenumAutomationProfile":已经事先存在的一个空目录

    使用托管机制

    • Consloe中注入js代码:window.navigator.webdriver,虽然会返回true,但不会提示请停用以开发者模式运行的扩展程序,相当于自己打开的浏览器
    # 终端先运行如下代码
    chrome.exe --remote-debugging-port=9222 --user-data-dir="D:selenumAutomationProfile"
    
    from selenium import webdriver
    from selenium.webdriver.chrome.options import Options
    
    chrome_options = Options()
    chrome_options.add_experimental_option('debuggerAddress','127.0.0.1:9222')
    
    # 代码托管打开的浏览器,不会实例化一个新的浏览器
    driver = webdriver.Chrome(executable_path="./chromedriver.exe",chrome_options=chrome_options)
    driver.get('http://www.taobao.com')
    
    • 老版本的selenium规避检测的操作
      • 这个目前会被检测到
    from selenium import webdriver
    from selenium.webdriver import ChromeOptions
     
    option = ChromeOptions()     #实例化一个ChromeOptions对象
    option.add_experimental_option('excludeSwitches', ['enable-automation'])  #以键值对的形式加入参数
     
    bro = webdriver.Chrome(executable_path='./chromedriver.exe',options=option)  #在调用浏览器驱动时传入option参数就能实现undefined
    

    模拟登陆

    12306模拟登陆

    • URL:12306登陆

    • 分析:

      • 识别的验证码图片必须通过截图获取验证码然后存储到本地
        • 登陆操作和唯一的验证码图片一一对应
    • 基于超级鹰识别验证码登录,类型9004

    # 超级鹰的包
    import requests
    from hashlib import md5
    
    class Chaojiying_Client(object):
    
        def __init__(self, username, password, soft_id):
            self.username = username
            password =  password.encode('utf8')
            self.password = md5(password).hexdigest()
            self.soft_id = soft_id
            self.base_params = {
                'user': self.username,
                'pass2': self.password,
                'softid': self.soft_id,
            }
            self.headers = {
                'Connection': 'Keep-Alive',
                'User-Agent': 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
            }
    
        def PostPic(self, im, codetype):
            """
            im: 图片字节
            codetype: 题目类型 参考 http://www.chaojiying.com/price.html
            """
            params = {
                'codetype': codetype,
            }
            params.update(self.base_params)
            files = {'userfile': ('ccc.jpg', im)}
            r = requests.post('http://upload.chaojiying.net/Upload/Processing.php', data=params, files=files, headers=self.headers)
            return r.json()
    
        def ReportError(self, im_id):
            """
            im_id:报错题目的图片ID
            """
            params = {
                'id': im_id,
            }
            params.update(self.base_params)
            r = requests.post('http://upload.chaojiying.net/Upload/ReportError.php', data=params, headers=self.headers)
            return r.json()
    
    # 封装一个验证码识别的函数
    def transform_code(imgPath,imgType):
        chaojiying = Chaojiying_Client('超级鹰用户名', '超级鹰用户名对应的密码', '软件ID')
        im = open(imgPath, 'rb').read()
        return chaojiying.PostPic(im, imgType)['pic_str']
    
    
    # 模拟登陆实现代码
    
    from time import sleep
    from PIL import Image	# pip install Pillow
    from selenium import webdriver
    from selenium.webdriver import ActionChains
    
    # 实例化一个谷歌浏览器对象
    bro = webdriver.Chrome(executable_path="./chromedriver.exe")
    # 发起请求
    bro.get('https://kyfw.12306.cn/otn/resources/login.html')
    # 登录页面第一个展示的是扫码,点击帐号密码登录
    bro.find_element_by_xpath('/html/body/div[2]/div[2]/ul/li[2]/a').click()
    sleep(2) # 等待2秒,加载验证码图片
    # 定位到用户名密码框,输入帐号密码
    bro.find_element_by_id('J-userName').send_keys('xxxxxxxx')  # 12306用户名
    bro.find_element_by_id('J-password').send_keys('********')  # 12306用户名对应的密码
    
    # 验证码的点击操作
    bro.save_screenshot('./12306.png')# 将页面当作图片保存到本地
    # 将验证码图片的标签定位到
    img_tag = bro.find_element_by_id('J-loginImg')
    # 验证码的坐标和大小
    location = img_tag.location
    size = img_tag.size
    
    # 裁剪的范围,这个根据截图自己情况调整,自己调试的(699, 284, 1015, 472)
    rangle = (int(location['x'])-65,int(location['y']),int(location['x']+size['width'])-49,int(location['y']+size['height']))
    
    # 使用Image类根据rangle裁剪范围进行验证码图片的裁剪
    i = Image.open('./12306.png')  # bytes类型数据
    frame = i.crop(rangle)  # 验证码对应的二进制数据
    frame.save('./code.png')
    img_coor = transform_code('./code.png',9004)  # 返回坐标值 274,146|37,147
    
    # 将坐标字符串转换为嵌套的列表
    all_lst = []	# [[274,146],[37,147]...]
    if '|' in img_coor:
        lst_1 = img_coor.split("|")
        count_1 = len(lst_1)
        for i in range(count_1):
            xy_lst = []
            x = int(lst_1[i].split(',')[0])
            y = int(lst_1[i].split(',')[1])
            xy_lst.append(x)
            xy_lst.append(y)
            all_lst.append(xy_lst)
    else:
        x = int(img_coor.split(',')[0])
        y = int(img_coor.split(',')[1])
        xy_lst = []
        xy_lst.append(x)
        xy_lst.append(y)
        all_lst.append(xy_lst)
    
    for data in all_lst:
        # 每个data都是一个列表中有2个元素
        x = data[0]
        y = data[1]
        # 实例化一个动作链,在指定范围(验证码标签范围),找到x,y坐标,点击,动作链立即执行
        ActionChains(bro).move_to_element_with_offset(img_tag,x,y).click().perform()
        # 执行一次等待0.5秒,防止过快
        sleep(0.5)
    
    # 点击登录按钮,实现登录
    bro.find_element_by_id('J-login').click()
    sleep(2)
    # 关闭浏览器
    bro.quit()
    

    Pyppeteer

  • 相关阅读:
    SSAS维度成员中的非法XML字符[转]
    Java 的sun.jdbc.odbc桥连接的使用!
    SSAS全半角空格导致的AS处理错误[转]
    【原创】C# 如何自定义代码模版
    TO_DATE函数
    JDK Windows环境变量配置
    SSAS异常字符导致找不到属性键错误[转]
    SQL SERVER 数据库日期算法总结
    章节 2.1 可靠的软件 – 灵活,可靠的软件 使用设计模式和敏捷开发
    软件架构设计和Scrum潜在可交付产品,我(scrum master)和他(架构师)的讨论
  • 原文地址:https://www.cnblogs.com/Golanguage/p/12549798.html
Copyright © 2020-2023  润新知