Selenium - 截图

about

在selenium中,截取网页的图片有多种方式,这里简单介绍三种截屏:

  • 截整个网页。
  • 截取可见区域。
  • 截取指定区域,即截取网页中的指定图片,如截取验证码部分的图片。

PS:后续会用到phantomjs,使用之前先按装:https://www.cnblogs.com/Neeo/articles/11837053.html#phantomjs

截取可见区域

可见区域,也就是你打开浏览器,看到的网页,我们通过selenium对这个范围的网页进行截图:

from selenium import webdriver

def get_img():

    driver = webdriver.Chrome()
    driver.implicitly_wait(time_to_wait=10)
    driver.get('http://www.neeo.cc:6005/login/')
    driver.save_screenshot('./a.png')   # 图片必须保存为 png 格式
    driver.quit()

if __name__ == '__main__':
    get_img()

截取指定区域

这一部分有两种办法来完成截取:

  1. 首先获取(可见)整个网页,然后获取指定区域的坐标点,然后算出指定区域的坐标位置(上,右上, 左下, 右下);根据坐标位置,从之前的大图中,把指定区域的图片抠出来,需要借助pillow模块。
  2. 直接使用selenium的方法论来截取。

法1:借助pillow模块抠图
使用pillow模块先下载:

pip install -i https://pypi.doubanio.com/simple  pillow
from PIL import Image   # pillow模块是这样导入的
from selenium import webdriver
class VerificationCodeHandler(object):

    def __init__(self, url, timeout=10):
        self.url = url
        self.time_out = timeout
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(time_to_wait=10)
        self.body_img_file_path = './BodyImage.png'
        self.code_img_file_path = './CodeImage.png'

    def get_pil_code(self):
        """
            获取验证码
            思路是先截取整个可视的body大图
            然后使用PIL从大图中定位到验证码所在的位置,然后再抠图
        """
        self.driver.get(self.url)
        # 截图 body 大图
        self.driver.save_screenshot(self.body_img_file_path)
        # 定位验证码所在的位置
        CodeImage = self.driver.find_element_by_id('imageCode')
        # print(CodeImage.location)  # {'x': 564, 'y': 310}
        # print(CodeImage.size)  # {'height': 30, 'width': 119}
        left = CodeImage.location['x']
        top = CodeImage.location['y']
        right = CodeImage.size['width'] + left
        height = CodeImage.size['height'] + top
        temporary_img = Image.open(self.body_img_file_path)
        temporary_img = temporary_img.crop((left, top, right, height))
        temporary_img.save(self.code_img_file_path)

    def __del__(self):
        self.driver.quit()

if __name__ == '__main__':
    VerificationCodeHandler(url='http://www.neeo.cc:6005/login/', timeout=10).get_pil_code()


上图左侧为大图,右侧为从大图中抠出来的图片。
如果扣出来的图不对,解决办法在本文的最后。

法2:使用selenium的screenshot方法直接截图

from PIL import Image
from selenium import webdriver


class VerificationCodeHandler(object):

    def __init__(self, url, timeout=10):
        self.url = url
        self.time_out = timeout
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(time_to_wait=10)

    def get_selenium_code(self):
        """ 使用 screenshot 方法直接截图 """
        self.driver.get(self.url)
        # 首先,获取验证码图片的标签对象
        CodeImage = self.driver.find_element_by_id('imageCode')
        # 通过标签的 screenshot 方法直接保存图片
        CodeImage.screenshot('./a.png')

    def __del__(self):
        self.driver.quit()

if __name__ == '__main__':
    VerificationCodeHandler(url='http://www.neeo.cc:6005/login/', timeout=10).get_selenium_code()

一步到位!

截取整个网页

这里也推荐使用Google插件来截取,非常好使:

来,看Python怎么操作吧!

from selenium import webdriver

def get_img():

    driver = webdriver.PhantomJS()
    driver.implicitly_wait(time_to_wait=10)
    driver.get('http://www.neeo.cc:6005/index/')
    # 设置视图大小
    driver.viewportSize = driver.get_window_size()
    driver.save_screenshot('a.png')
    driver.quit()

if __name__ == '__main__':
    get_img()

question

关于截图位置不对问题

在使用selenium 加 pillow 扣图的时候,遇到定位不准的情况,也就是扣的图,位置不对,经过排查问题,发现不是代码的问题,是系统的分辨率和缩放引起的问题。解决办法:

  1. 在获取坐标点的时候,乘上缩放比。
  2. 使用无头浏览器来截图。
  3. 手动的将缩放比调整为100%。

法1

from PIL import Image   # pillow模块是这样导入的
from selenium import webdriver
class VerificationCodeHandler(object):

    def __init__(self, url, timeout=10):
        self.url = url
        self.time_out = timeout
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(time_to_wait=10)
        self.body_img_file_path = './BodyImage.png'
        self.code_img_file_path = './CodeImage.png'

    def get_pil_code(self):
        """
            获取验证码
            思路是先截取整个可视的body大图
            然后使用PIL从大图中定位到验证码所在的位置,然后再抠图
        """
        self.driver.get(self.url)
        # 截图 body 大图
        self.driver.save_screenshot(self.body_img_file_path)
        # 定位验证码所在的位置
        CodeImage = self.driver.find_element_by_id('imageCode')
        # print(CodeImage.location)  # {'x': 564, 'y': 310}
        # print(CodeImage.size)  # {'height': 30, 'width': 119}
        # 就是下面两行, 我的缩放比是124%,就调整为1.24
        left = CodeImage.location['x'] * 1.24
        top = CodeImage.location['y'] * 1.24
        right = CodeImage.size['width'] + left
        height = CodeImage.size['height'] + top
        temporary_img = Image.open(self.body_img_file_path)
        temporary_img = temporary_img.crop((left, top, right, height))
        temporary_img.save(self.code_img_file_path)

    def __del__(self):
        self.driver.quit()

if __name__ == '__main__':
    VerificationCodeHandler(url='http://www.neeo.cc:6005/login/', timeout=10).get_pil_code()

这有个问题就是截的图能用,但是不是很标准,我也没时间细扣如何搞得很精确,有那时间,不如使用下面的方法了。
使用phantomjs

from PIL import Image   # pillow模块是这样导入的
from selenium import webdriver
class VerificationCodeHandler(object):

    def __init__(self, url, timeout=10):
        self.url = url
        self.time_out = timeout
        # 直接实例化一个phantomjs对象即可
        self.driver = webdriver.PhantomJS()
        self.driver.implicitly_wait(time_to_wait=10)
        self.body_img_file_path = './BodyImage.png'
        self.code_img_file_path = './CodeImage.png'

    def get_pil_code(self):
        """
            获取验证码
            思路是先截取整个可视的body大图
            然后使用PIL从大图中定位到验证码所在的位置,然后再抠图
        """
        self.driver.get(self.url)
        # 截图 body 大图
        self.driver.save_screenshot(self.body_img_file_path)
        # 定位验证码所在的位置
        CodeImage = self.driver.find_element_by_id('imageCode')
        # print(CodeImage.location)  # {'x': 564, 'y': 310}
        # print(CodeImage.size)  # {'height': 30, 'width': 119}
        left = CodeImage.location['x']
        top = CodeImage.location['y']
        right = CodeImage.size['width'] + left
        height = CodeImage.size['height'] + top
        temporary_img = Image.open(self.body_img_file_path)
        temporary_img = temporary_img.crop((left, top, right, height))
        temporary_img.save(self.code_img_file_path)

    def __del__(self):
        self.driver.quit()

if __name__ == '__main__':
    VerificationCodeHandler(url='http://www.neeo.cc:6005/login/', timeout=10).get_pil_code()

好用虽好用,但是如果你运行了会发现有有一个waring提示,意思是selenium现在不支持phantomjs了.......
当然,你可以使用Google无头浏览器来完成.....
Google无头,你值得拥有

from PIL import Image   # pillow模块是这样导入的
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

class VerificationCodeHandler(object):

    def __init__(self, url, timeout=10):
        self.url = url
        self.time_out = timeout
        # 配置Google无头,其他代码不变
        chrome_options = Options()
        chrome_options.add_argument('--headless')
        chrome_options.add_argument('--disable-gpu')
        self.driver = webdriver.Chrome(chrome_options=chrome_options)

        self.driver.implicitly_wait(time_to_wait=10)
        self.body_img_file_path = './BodyImage.png'
        self.code_img_file_path = './CodeImage.png'

    def get_pil_code(self):
        """
            获取验证码
            思路是先截取整个可视的body大图
            然后使用PIL从大图中定位到验证码所在的位置,然后再抠图
        """
        self.driver.get(self.url)
        # 截图 body 大图
        self.driver.save_screenshot(self.body_img_file_path)
        # 定位验证码所在的位置
        CodeImage = self.driver.find_element_by_id('imageCode')
        # print(CodeImage.location)  # {'x': 564, 'y': 310}
        # print(CodeImage.size)  # {'height': 30, 'width': 119}
        left = CodeImage.location['x']
        top = CodeImage.location['y']
        right = CodeImage.size['width'] + left
        height = CodeImage.size['height'] + top
        temporary_img = Image.open(self.body_img_file_path)
        temporary_img = temporary_img.crop((left, top, right, height))
        temporary_img.save(self.code_img_file_path)

    def __del__(self):
        self.driver.quit()

if __name__ == '__main__':
    VerificationCodeHandler(url='http://www.neeo.cc:6005/login/', timeout=10).get_pil_code()

实战:截取验证码图片和百度文字识别

这里我们以http://www.neeo.cc:6005/login/页面的验证码为例,我们需要使用selenium和百度AI的文字识别来获取验证码。

import base64
import requests
from PIL import Image
from selenium import webdriver
from selenium.webdriver.chrome.options import Options

class VerificationCodeHandler(object):

    def __init__(self, url, timeout=10):
        self.url = url
        self.time_out = timeout
        chrome_options = Options()
        chrome_options.add_argument('--headless')
        chrome_options.add_argument('--disable-gpu')
        self.driver = webdriver.Chrome(chrome_options=chrome_options)
        self.driver.implicitly_wait(time_to_wait=10)
        self.body_img_file_path = './BodyImage.png'
        self.code_img_file_path = './CodeImage.png'

    def get_pil_code(self):
        """
            获取验证码
            思路是先截取整个可视的body大图
            然后使用PIL从大图中定位到验证码所在的位置,然后再抠图
        """
        self.driver.get(self.url)
        # 截图 body 大图
        # self.driver.maximize_window()
        self.driver.save_screenshot(self.body_img_file_path)

        # 定位验证码所在的位置
        CodeImage = self.driver.find_element_by_id('imageCode')
        # print(CodeImage.location)  # {'x': 564, 'y': 310}
        # print(CodeImage.size)  # {'height': 30, 'width': 119}
        left = CodeImage.location['x']
        top = CodeImage.location['y']
        right = CodeImage.size['width'] + left
        height = CodeImage.size['height'] + top
        temporary_img = Image.open(self.body_img_file_path)
        temporary_img = temporary_img.crop((left, top, right, height))
        temporary_img.save(self.code_img_file_path)



    def get_selenium_code(self):
        self.driver.get(self.url)
        CodeImage = self.driver.find_element_by_id('imageCode')
        CodeImage.screenshot(self.code_img_file_path)
        self.send_baidu_msg()

    def send_baidu_msg(self):
        """ 调用百度文字识别接口来提取图片中的验证码 """

        request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic"
        # 二进制方式打开图片文件
        f = open(self.code_img_file_path, 'rb')
        img = base64.b64encode(f.read())

        params = {"image": img}
        access_token = '24.16db7b39b86ebcda566bedec25b86103.2592000.1589356853.282335-16611607'
        request_url = request_url + "?access_token=" + access_token
        headers = {'content-type': 'application/x-www-form-urlencoded'}
        response = requests.post(request_url, data=params, headers=headers)
        if response:
            print(response.json())

    def __del__(self):
        self.driver.quit()


if __name__ == '__main__':
    # VerificationCodeHandler(url='http://www.neeo.cc:6005/login/', timeout=10).get_pil_code()
    VerificationCodeHandler(url='http://www.neeo.cc:6005/login/', timeout=10).get_selenium_code()

欢迎斧正,tha'ts all

see also:

利用PIL和Selenium实现页面元素截图

posted @ 2019-04-08 18:35  听雨危楼  阅读(1781)  评论(0编辑  收藏  举报