一、 selenium 下载高清图片

1、版本介绍

python 3.7.4 
selenium = 3.141.0
chromedriver=84.0.4147.30

2、保存 base64 图片格式代码

src="data:image/gif;base64,R0lGODlhMwAxAIAAAAAAAPyH5BAAAAAAALAAAAAAzADEAAAK8jI+pBr0PowytzotTtbm/DTqQ6C3hGX
ElcraA9jIr66ozVpM3nseUvYP1UEHF0FUUHkNJxhLZfEJNvol06tzwrgd
LbXsFZYmSMPnHLB+zNJFbq15+SOf50+6rG7lKOjwV1ibGdhHYRVYVJ9Wn
k2HWtLdIWMSH9lfyODZoZTb4xdnpxQSEF9oyOWIqp6gaI9pI1Qo7BijbF
ZkoaAtEeiiLeKn72xM7vMZofJy8zJys2UxsCT3kO229LH1tXAAAOw=="

     提取出其中的base64地址(即 base64, 后的内容)然后base64解码,然后保存为图片

url='''R0lGODlhMwAxAIAAAAAAAPyH5BAAAAAAALAAAAAAzADEAAAK8jI+pBr0PowytzotTtbm/DTqQ6C3hGX
ElcraA9jIr66ozVpM3nseUvYP1UEHF0FUUHkNJxhLZfEJNvol06tzwrgd
LbXsFZYmSMPnHLB+zNJFbq15+SOf50+6rG7lKOjwV1ibGdhHYRVYVJ9Wn
k2HWtLdIWMSH9lfyODZoZTb4xdnpxQSEF9oyOWIqp6gaI9pI1Qo7BijbF
ZkoaAtEeiiLeKn72xM7vMZofJy8zJys2UxsCT3kO229LH1tXAAAOw=='''
import base64 
img=base64.urlsafe_b64decode(url + '=' * (4 - len(url) % 4))
fh = open("imageToSave.png", "wb")
fh.write(img)
fh.close()

3、selenium 对某个元素截图保存 .screenshot()方法

由于Google网络的原因,一些外网的图片高清图加载失败,导致下载的是缩减图,这一部分数据通过截取详情图片的元素来解决。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
import os
import re
import requests
import urllib3
urllib3.disable_warnings() # 去除警告

options = webdriver.ChromeOptions()
# 增加无头
options.add_argument('--disable-gpu')
# 防止被网站识别,开发者模式
options.add_experimental_option('excludeSwitches', ['enable-automation'])

browser = webdriver.Chrome(options=options)
browser.maximize_window()

browser.implicitly_wait(10)
browser.get('https://www.google.com/search?q=%E6%BF%80%E5%87%B8&tbm=isch&hl=zh-CN&hl=zh-CN#imgrc=1lpdzdDLl6rN9M')
ele = browser.find_element_by_xpath('//*[@id="Sva75c"]/div/div/div[3]/div[2]/c-wiz/div[1]/div[1]/div/div[2]/a/img')
print(ele.get_attribute('src'))

# 截图保存
ele.screenshot('1.png')

4 、selenium 常常遇见的反爬虫几个策略

         主要参考:

                         Selenium反反爬-滑块验证

                         Selenium 系列篇(六):反反爬篇

                         使用 mitmproxy + python 做拦截代理

                         如何突破网站对selenium的屏蔽

                         Selenium-webdriver绕开反爬虫机制的4种方法

                         网站对Selenium的屏蔽

                         

5、爬高清图片的代码

缺点:慢,效果受网络的影响,现在没有更好的方案...
2个代码都未解决的问题:

    ① 使用 无头 浏览器在 ‘点击更多’ 的点击事件可能不能触发
    ② 使用 无头 浏览器在 缩减图片截图时有的图片截的图可能有点问题

希望有知道怎么回事或者怎么解决的老铁请留个言,感谢!

    (1)高清、缩减、base64 格式图片

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import ElementNotInteractableException
from selenium.webdriver.common.keys import Keys
from requests.adapters import HTTPAdapter
import argparse

import time
import os
import re
import requests
import urllib3
urllib3.disable_warnings()  # 去除警告


class GoogleSpider():

    def __init__(self, url, keyword, time_sleep, target_dir):
        self.url = url
        self.keyword = keyword
        self.time_sleep = time_sleep  # 等待高清图片加载的时间
        self.target_dir = target_dir
        self.img_tmp_dir = os.path.join(self.target_dir,
                                        self.add_timestamp(self.keyword))
        if not os.path.exists(self.img_tmp_dir):
            os.makedirs(self.img_tmp_dir)

        self.head = None  # 浏览器是否存在头
        self.implicitly_wait_time = 5  # 隐形等待时间
        self.js_slide_wait = 30  # js 滑动窗口等待时间

    def clean_str(self, str_):
        """
        清除字符串为图片命名时不合规的字符
        :return:
        """
        str_ = re.sub('[^\u4e00-\u9fa5A-Za-z\d]', '', str_)
        return str_

    def add_timestamp(self, str_):
        """
        为字符串添加时间搓,保证字符串唯一不重复性
        :param str_: str
        :return:
        """
        assert isinstance(str_, str)
        time_str = str(time.time()).replace('.', '')
        str_ = str_ + time_str
        return str_

    def create_browser(self,head):
        """
        创建一个浏览器的对象
        :param headless: 是否使用无头浏览器
        :return:
        """
        self.head = head
 
        options = webdriver.ChromeOptions()
        # 增加无头
        if not self.head:
            options.add_argument('--headless')
            # 无头浏览器设置窗口大小,主要是为了解决截屏时,如果窗口比较小,截屏时会获得较小的图片
            options.add_argument("--window-size=4000,1600")
 
        options.add_argument('--disable-gpu')

        # 关闭自动测试状态显示 // 会导致浏览器报:请停用开发者模式
        # window.navigator.webdriver还是返回True,当返回undefined时应该才可行。
        options.add_experimental_option("excludeSwitches", ['enable-automation'])
        # 关闭开发者模式
        options.add_experimental_option("useAutomationExtension", False)
        # 设置中文
        options.add_argument('lang=zh_CN.UTF-8')
        # 更换头部
        options.add_argument(
            'user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"')
        # 部署项目在linux时,其驱动会要求这个参数
        options.add_argument('--no-sandbox')

        browser = webdriver.Chrome(options=options)
        if self.head:
            browser.maximize_window()

        # 设置执行js代码转换模式,反反爬虫检测 window.navigator.webdriver 属性换为 undefined
        browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
        })
 
        return browser

    def get_main_page_info(self, browser):
        """
        获取主页面且拉至最底部,且获取所有图片详情页的链接地址
        :return:
        """
        browser.get(self.url)
        browser.implicitly_wait(self.implicitly_wait_time)

        # TODO 滑动到底的js代码
        js = """ 
                   (function () { 
                       var y = document.documentElement.scrollTop; 
                       var step = 100; 
                       window.scroll(0, y); 
                       function f() { 
                           if (y < document.body.scrollHeight) { 
                               y += step; 
                               window.scroll(0, y); 
                               setTimeout(f, 100); //每两次间隔滑动的时间 100ms

                           }
                           else { 
                               window.scroll(0, y); 
                               document.title += "scroll-done"; 
                           } 
                       } 
                       setTimeout(f, 1000); // 执行函数等待时间 1000ms
                   })(); 
            """

        # TODO 执行滑动到底的操作
        browser.execute_script(js)
        # 等待窗口滑动结束
        for i in range(self.js_slide_wait):
            print('\rJS窗口滑动中,请等待 {}s,现在是第 {}s,网络好可下调 '.format(self.js_slide_wait, i + 1), end='', flush=True)
            time.sleep(1)
        print()

        # TODO 点击 ‘ 加载更多的选项 ’
        try:
            browser.find_element_by_xpath(
                '//div[@id="islmp"]/.//div[@jsname="i3y3Ic"]/.//input[@class="mye4qd"]').send_keys(Keys.ENTER)

            print('缓冲中...')
            time.sleep(8)  # ‘加载更多’ 缓冲

            # TODO 执行点击加载更多继续滚动
            browser.execute_script(js)
            # 等待窗口滑动结束
            for i in range(self.js_slide_wait):
                print('\rJS加载更多图片窗口滑动中,请等待 {}s,现在是第 {}s,网络好可下调 '.format(self.js_slide_wait, i + 1), end='', flush=True)
                time.sleep(1)
            print()
        except Exception as e:
            print(e, '网络不畅 或 该网页没有更多内容选项 .... ')

        # 获取图片详情页链接地址
        div_infos = browser.find_elements_by_xpath(
            "//div[@id='islmp']/.//div[contains(@class,'isv-r PNCib MSM1fd')]")  # 结果是一个列表

        self.reduceImg_num = len(div_infos)
        if self.reduceImg_num == 0:
            assert Exception('网络链接 {} 错误\n 获取主页面class属性已更改'.format(self.url))
        print('一共获取到 {} 张缩减图'.format(self.reduceImg_num))

        # 定义重复请求的链接列表,保存 【{url,img_name},...】二元组列表
        self.repeat_urls = []
        # TODO 通过缩减图 DIV 获取高清图片的地址
        for idx, i in enumerate(div_infos):

            try:
                data_id = i.get_attribute('data-id')
            except Exception as e:
                logger.error(e)
                logger.error('"data_id" 的属性值获取失败,可能网站已更改属性')
                continue

            # 图片详情页的 url 地址
            img_url = self.url + '#imgrc=' + data_id
            try:
                browser.get(img_url)

                self.target_img_url = browser.find_element_by_xpath(
                    "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
                    'src')
                self.target_img_name = browser.find_element_by_xpath(
                    "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
                    'alt')

                # 如果获取的url不以 data: 或者 http 开头,视为获取失败
                if not (self.target_img_url.startswith('data:') or self.target_img_url.startswith('http')):
                    logger.info("第 {} 高清图片url: {} 格式错误,跳过".format(idx + 1, self.target_img_url))
                    continue

                # 对是否详情页加载为高清图的url进行判断: https://encrypted-tbn0.gstatic.com/images? 开头属于缩减图
                # 因此对详情页进行最长为 time_sleep 时间的等待,每次判断的时间step为250ms
                if self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?'):
                    for step in range(time_sleep * 4):
                        if not self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?'):
                            break
                        time.sleep(0.25)
                        self.target_img_url = browser.find_element_by_xpath(
                            "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
                            'src')

                elif self.target_img_url.startswith('data:'):
                    for step in range(int(max(1.5, time_sleep - 3) * 4)):  # data: 类型的图片,最少等待 1.5s 去加载图片
                        if not self.target_img_url.startswith('data:'):
                            break
                        time.sleep(0.25)
                        self.target_img_url = browser.find_element_by_xpath(
                            "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
                            'src')

            except Exception as e:
                logger.error(e)
                logger.error('当前第 {} 张缩减图片详情信息url获取信息失败,跳过处理'.format(idx + 1))
                continue

            # TODO 图片高清地址获取完毕,现在构建图片保存所需要的路径
            self.target_img_name = self.add_timestamp(self.clean_str(self.target_img_name)) + '.jpg'

            img_file_path = os.path.join(self.img_tmp_dir,
                                         self.target_img_name)

            # TODO 图片保存
            if self.target_img_url.startswith(
                    'https://encrypted-tbn0.gstatic.com/images?') or self.target_img_url.startswith('data:'):
                print(
                    '总量:{}, 图片序号为:{},正在保存【缩减图】至 {},图片名: {} url:{}'.format(self.reduceImg_num, idx, img_file_path,
                                                                          self.target_img_name,
                                                                          self.target_img_url[:150])
                    # data: 链接太长,这里做一个截取
                )
            else:
                print(
                    '总量:{}, 图片序号为:{},正在保存【高清图】至 {},图片名: {} url:{}'.format(self.reduceImg_num, idx, img_file_path,
                                                                          self.target_img_name,
                                                                          self.target_img_url)
                )

            if self.target_img_url.startswith('http'):
                self.save_url_img(img_file_path)
            elif self.target_img_url.startswith('data:'):
                self.save_base64_img(self.target_img_url, img_file_path)

        # 重新爬取请求失败的高清图片的链接
        repeat_urls = self.repeat_urls
        self.repeat_spider(repeat_urls)

        browser.quit()  # 浏览器退出

    def save_url_img(self, img_files_path):
        """
        通过 url 请求保存图片
        :param img_files_path: 给定要保存的文件名的路径
        :return:
        """
        try:
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
            }
            # TODO 增加连接重试次数(一共2次请求链接)
            # requests.adapters.DEFAULT_RETRIES = 1 
            sess = requests.Session()
            sess.keep_alive = False # 关闭多余连接
            text = sess.get(self.target_img_url, headers=headers, stream=True, verify=False, timeout=5)
            
            with open(img_files_path, 'wb') as file:
                for i in text.iter_content(1024 * 10):
                    file.write(i)
        except Exception as e:
            self.repeat_urls.append((self.target_img_url, img_files_path))
            logger.error(e, self.target_img_url)

    def save_base64_img(self, url, img_files_path):
        """
        保存 base64 格式的图片
        :param url:
        :param img_files_path:
        :return:
        """
        import base64
        url = re.sub('.+base64,', '', url)
        img = base64.urlsafe_b64decode(url + '=' * (4 - len(url) % 4))
        fh = open(img_files_path, "wb")
        fh.write(img)
        fh.close()

    def screen_img(self, ele, img_files_path):
        """
        给定需要截图的 element元素,进行截图
        :param ele: 需要截图的元素
        :param img_files_path: 图片的路径
        :return:
        """
        try:
            ele.screenshot(img_files_path)
        except Exception as e:
            logger.error('一些原因导致截图失败,跳过处理', e)

    def repeat_spider(self, urls, repeat_num=3):
        """
            用于重复请求高清图片 get 失败的链接,下载图片 
            urls: 请求失败的 图片链接及其图片名称组成的二元组的列表
            repeat_num: 重复循环最多 repeat_nume 次,裆列表为零时终止循环
        """
        urls_num = len(urls)
        logger.info('\n存在{}个链接请求失败,正在重新请求爬取,使用requests的方式请求:\n'.format(urls_num))
        
        sucess_idx = []  # 保存成功的url 的索引列表
        for num in range(repeat_num):
            urls_num = len(urls)
            if urls_num == 0:
                break
                
            for idx,url_info in enumerate(urls):
                
                if idx not in sucess_idx:
                    url = url_info[0]
                    img_name = url_info[1]
                    
                    try:
                        headers = {
                            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
                        }
                        # TODO 增加连接重试次数(一共4次链接)
                        sess = requests.Session()
                        sess.mount('http://', HTTPAdapter(max_retries=3)) 
                        sess.mount('https://', HTTPAdapter(max_retries=3))     
                        sess.keep_alive = False # 关闭多余连接
                        
                        text = requests.get(url, headers=headers, stream=True, verify=False, timeout=(4,5)) # connect 和 read 二者的 timeout
                        
                        with open(img_name, 'wb') as file:
                            for i in text.iter_content(1024 * 10):
                                file.write(i)
                                
                        text.close() # 关闭,很重要,确保不要过多的链接
                        
                        logger.info('使用requests的方式请求,重复爬取阶段 保存成功 ,现在是第{}次循环,第{}张图片name-url:{}-{}'.format(num+1,idx+1,img_name,url))
                        # 保存成功的图片将成功的idx保存,确保下一次循环不会重新使用已成功的url
                        sucess_idx.append(idx)
                        
                    except Exception as e:
                        logger.error(e)
                        logger.error('使用requests的方式请求,重复爬取请求失败:{}'.format(url))
                    time.sleep(0.5)


if __name__ == '__main__':

    # TODO 参数
    head = False
    target_dir = r'target_dir'
    time_sleep = 3  # 网速好的时间可以下调,加载高清最长等待时间
    # logger.info(urls,head,keyword,target_dir)
    urls = [
        'https://www.google.com/search?q=风景&newwindow=1&sxsrf=ALeKk002XUAM8lwptPWsSjuox8SjA1B7_A:1600079585015&source=lnms&tbm=isch&sa=X&ved=2ahUKEwimsZv6uOjrAhUNkJQKHW5HBD4Q_AUoAXoECAwQAw&biw=1920&bih=937']
    keyword = '风景'

    for url in urls:
        url = url.strip()

        # TODO 运行
        spider_obj = GoogleSpider(url, keyword, time_sleep, target_dir)

        # 创建一个浏览器
        browser = spider_obj.create_browser(head=head)

        # 下载图片
        spider_obj.get_main_page_info(browser=browser)

    (2)使用截图代替下载 缩减图

tip:
    1、删除:
    from utils import utils
    logger = utils.Logger_Hanlder.setup_logging(report_path='./log')
    2、将所有的 logger语句转化为 print
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import ElementNotInteractableException
from selenium.webdriver.common.keys import Keys
from requests.adapters import HTTPAdapter
import argparse

import time
import os
import re
import requests
import urllib3
urllib3.disable_warnings() # 去除警告
from utils import utils
logger = utils.Logger_Hanlder.setup_logging(report_path='./log')


class GoogleSpider():

    def __init__(self,url,keyword,time_sleep,target_dir,repeat_num,max_imgNum = None):
        self.url = url
        self.keyword = keyword
        self.repeat_num = repeat_num # 高清图片链接请求失败后重新爬取的次数
        self.time_sleep = time_sleep    # 等待高清图片加载的时间
        self.max_imgNum = max_imgNum # 设置最大图片的下载量
        self.target_dir = target_dir
        self.img_tmp_dir = os.path.join(self.target_dir,
                                   self.add_timestamp(self.keyword))
        if not os.path.exists(self.img_tmp_dir):
            os.makedirs(self.img_tmp_dir)

        self.head = None            # 浏览器是否存在头
        self.implicitly_wait_time = 5 # 隐形等待时间
        self.js_slide_wait = 30 # js 滑动窗口等待时间

    def clean_str(self,str_):
        """
        清除字符串为图片命名时不合规的字符
        :return:
        """
        str_ = re.sub('[^\u4e00-\u9fa5A-Za-z\d]','',str_)
        return str_

    def add_timestamp(self,str_):
        """
        为字符串添加时间搓,保证字符串唯一不重复性
        :param str_: str
        :return:
        """
        assert isinstance(str_,str)
        time_str = str(time.time()).replace('.','')
        str_ = str_ + time_str
        return str_

    def create_browser(self,head):
        """
        创建一个浏览器的对象
        :param headless: 是否使用无头浏览器
        :return:
        """
        self.head = head
 
        options = webdriver.ChromeOptions()
        # 增加无头
        if not self.head:
            options.add_argument('--headless')
            # 无头浏览器设置窗口大小,主要是为了解决截屏时,如果窗口比较小,截屏时会获得较小的图片
            options.add_argument("--window-size=4000,1600")
 
        options.add_argument('--disable-gpu')
 
        # 关闭自动测试状态显示 // 会导致浏览器报:请停用开发者模式
        # window.navigator.webdriver还是返回True,当返回undefined时应该才可行。
        options.add_experimental_option("excludeSwitches", ['enable-automation'])
        # 关闭开发者模式
        options.add_experimental_option("useAutomationExtension", False)
        # 设置中文
        options.add_argument('lang=zh_CN.UTF-8')
        # 更换头部
        options.add_argument(
            'user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"')
        # 部署项目在linux时,其驱动会要求这个参数
        options.add_argument('--no-sandbox')
 
        browser = webdriver.Chrome(options=options)
        if self.head:
            browser.maximize_window()
 
        # 设置执行js代码转换模式,反反爬虫检测 window.navigator.webdriver 属性换为 undefined
        browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
        })
 
        return browser

    def get_main_page_info(self,browser):
        """
        获取主页面且拉至最底部,且获取所有图片详情页的链接地址
        :return:
        """
        browser.get(self.url)
        browser.implicitly_wait(self.implicitly_wait_time)

        # TODO 滑动到底的js代码
        js = """ 
                   (function () { 
                       var y = document.documentElement.scrollTop; 
                       var step = 100; 
                       window.scroll(0, y); 
                       function f() { 
                           if (y < document.body.scrollHeight) { 
                               y += step; 
                               window.scroll(0, y); 
                               setTimeout(f, 100); //每两次间隔滑动的时间 100ms
                               
                           }
                           else { 
                               window.scroll(0, y); 
                               document.title += "scroll-done"; 
                           } 
                       } 
                       setTimeout(f, 1000); // 执行函数等待时间 1000ms
                   })(); 
            """

        # TODO 执行滑动到底的操作
        browser.execute_script(js)
        # 等待窗口滑动结束
        for i in range(self.js_slide_wait):
            print('\rJS窗口滑动中,请等待 {}s,现在是第 {}s,网络好可下调 '.format(self.js_slide_wait,i+1),end='',flush=True)
            time.sleep(1)
        print()

        # TODO 点击 ‘ 加载更多的选项 ’
        try:
            browser.find_element_by_xpath('//div[@id="islmp"]/.//div[@jsname="i3y3Ic"]/.//input[@class="mye4qd"]').send_keys(Keys.ENTER)

            print('缓冲中...')
            time.sleep(8)  # ‘加载更多’ 缓冲

            # TODO 执行点击加载更多继续滚动
            browser.execute_script(js)
            # 等待窗口滑动结束
            for i in range(self.js_slide_wait):
                print('\rJS加载更多图片窗口滑动中,请等待 {}s,现在是第 {}s,网络好可下调 '.format(self.js_slide_wait, i + 1), end='', flush=True)
                time.sleep(1)
            print()
        except Exception as e:
            print(e, '网络不畅 或 该网页没有更多内容选项 .... ')

        # 获取图片详情页链接地址
        div_infos = browser.find_elements_by_xpath(
                "//div[@id='islmp']/.//div[contains(@class,'isv-r PNCib MSM1fd')]")    # 结果是一个列表

        self.reduceImg_num = len(div_infos)
        if self.reduceImg_num == 0:
            assert Exception('网络链接 {} 错误\n 获取主页面class属性已更改'.format(self.url))
        logger.info('一共获取到 {} 张缩减图,且图片下载给定的最大的数量为{}张'.format(self.reduceImg_num,self.max_imgNum))

        # 定义重复请求的链接列表,保存 【{url,img_name},...】二元组列表
        self.repeat_urls = []
        # TODO 通过缩减图 DIV 获取高清图片的地址
        for idx,i in enumerate(div_infos):
            # 当图片下载超过给定的最大的数量时,停止爬取
            if self.max_imgNum is not None:
                if idx >= self.max_imgNum:
                    logger.info("当图片下载超过给定的最大的数量时,强制停止")
                    break
                    
            try:
                data_id = i.get_attribute('data-id')
            except Exception as e:
                logger.error(e)
                logger.error('"data_id" 的属性值获取失败,可能网站已更改属性')
                continue

            # 图片详情页的 url 地址
            img_url = self.url + '#imgrc=' + data_id
            try:
                browser.get(img_url)

                self.target_img_url = browser.find_element_by_xpath(
                    "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
                    'src')
                self.target_img_name = browser.find_element_by_xpath(
                    "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
                    'alt')

                # 如果获取的url不以 data: 或者 http 开头,视为获取失败
                if not (self.target_img_url.startswith('data:') or self.target_img_url.startswith('http')):
                    logger.info("第 {} 高清图片url: {} 格式错误,跳过".format(idx+1 , self.target_img_url))
                    continue

                # 对是否详情页加载为高清图的url进行判断: https://encrypted-tbn0.gstatic.com/images? 开头属于缩减图
                # 因此对详情页进行最长为 time_sleep 时间的等待,每次判断的时间step为250ms
                if self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?'):
                    for step in range(time_sleep * 4):
                        if not self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?'):
                            break
                        time.sleep(0.25)
                        self.target_img_url = browser.find_element_by_xpath(
                            "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
                            'src')

                elif self.target_img_url.startswith('data:'):
                    for step in range(    int(max(1.5,time_sleep - 3) * 4)   ):  # data: 类型的图片,最少等待 1.5s 去加载图片
                        if not self.target_img_url.startswith('data:'):
                            break
                        time.sleep(0.25)
                        self.target_img_url = browser.find_element_by_xpath(
                            "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img").get_attribute(
                            'src')

            except Exception as e:
                logger.error(e)
                logger.error('当前第 {} 张缩减图片详情信息url获取信息失败,跳过处理'.format(idx+1))
                continue

            # TODO 图片高清地址获取完毕,现在构建图片保存所需要的路径
            self.target_img_name = self.add_timestamp(self.clean_str(self.target_img_name)) + '.jpg'

            img_file_path = os.path.join(self.img_tmp_dir,
                                         self.target_img_name)

            # TODO 图片保存
            if self.target_img_url.startswith('https://encrypted-tbn0.gstatic.com/images?') or self.target_img_url.startswith('data:'):
                logger.info(
                    '总量:{}, 图片序号为:{},正在保存【截图】至 {},图片名: {} url:{}'.format(self.reduceImg_num, idx, img_file_path,
                                                                  self.target_img_name,
                                                                  self.target_img_url[:150])  # data: 链接太长,这里做一个截取
                                                                                )
                # 保存截图
                ele_img = browser.find_element_by_xpath(
                            "//div[@id='Sva75c']/.//div[@class='tvh9oe BIB1wf']/.//div[@class='zjoqD']/.//img")
                self.screen_img(ele_img,img_file_path)
            else:
                logger.info(
                    '总量:{}, 图片序号为:{},正在保存【高清图】至 {},图片名: {} url:{}'.format(self.reduceImg_num, idx, img_file_path,
                                                                  self.target_img_name,
                                                                  self.target_img_url)
                                                                                )
                # 保存高清图
                self.save_url_img(img_file_path)
                time.sleep(0.5)
           
           
        # 重新爬取请求失败的高清图片的链接
        repeat_urls = self.repeat_urls
        repeat_num = self.repeat_num
        
        # self.repeat_spider_get(repeat_urls,repeat_num)
        self.repeat_spider_screen(repeat_urls,repeat_num)
            
        browser.quit()  # 浏览器退出

    def save_url_img(self,img_files_path):
        """
        通过 url 请求保存图片
        :param img_files_path: 给定要保存的文件名的路径
        :return:
        """
        try:
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
            }
            # TODO 增加连接重试次数(一共2次请求链接)
            # requests.adapters.DEFAULT_RETRIES = 1 
            sess = requests.Session()
            sess.keep_alive = False # 关闭多余连接
            text = sess.get(self.target_img_url, headers=headers, stream=True, verify=False, timeout=5)
            
            with open(img_files_path, 'wb') as file:
                for i in text.iter_content(1024 * 10):
                    file.write(i)
        except Exception as e:
            self.repeat_urls.append((self.target_img_url,img_files_path))
            logger.error(e)
            logger.error("爬取请求失败:{}".format(self.target_img_url))

    def save_base64_img(self,url,img_files_path):
        """
        保存 base64 格式的图片
        :param url:
        :param img_files_path:
        :return:
        """
        import base64
        url = re.sub('.+base64,','',url)
        img = base64.urlsafe_b64decode(url + '=' * (4 - len(url) % 4))
        fh = open(img_files_path, "wb")
        fh.write(img)
        fh.close()

    def screen_img(self,ele,img_files_path):
        """
        给定需要截图的 element元素,进行截图
        :param ele: 需要截图的元素
        :param img_files_path: 图片的路径
        :return:
        """
        try:
            ele.screenshot(img_files_path)
        except Exception as e:
            logger.error('一些原因导致截图失败,跳过处理',e)
            
    def repeat_spider_get(self,urls,repeat_num):
        """
            用于重复请求高清图片 get 失败的链接,下载图片 
            urls: 请求失败的 图片链接及其图片名称组成的二元组的列表
            repeat_num: 重复循环最多 repeat_nume 次,裆列表为零时终止循环
        """
        urls_num = len(urls)
        logger.info('\n存在{}个链接请求失败,正在重新请求爬取,使用requests的方式请求:\n'.format(urls_num))
        
        sucess_idx = []  # 保存成功的url 的索引列表
        for num in range(repeat_num):
            urls_num = len(urls)
            if urls_num == 0:
                break
            
            fail_num = 0 # 判断连续失败的个数超过一定个数以后(本次设为6),终止重复爬取阶段,
            for idx,url_info in enumerate(urls):
                
                if idx not in sucess_idx:
                    url = url_info[0]
                    img_name = url_info[1]
                    
                    try:
                        headers = {
                            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36',
                        }
                        # TODO 增加连接重试次数(一共4次链接)
                        sess = requests.Session()
                        sess.mount('http://', HTTPAdapter(max_retries=3)) 
                        sess.mount('https://', HTTPAdapter(max_retries=3))     
                        sess.keep_alive = False # 关闭多余连接
                        
                        text = requests.get(url, headers=headers, stream=True, verify=False, timeout=(4,5)) # connect 和 read 二者的 timeout
                        
                        with open(img_name, 'wb') as file:
                            for i in text.iter_content(1024 * 10):
                                file.write(i)
                                
                        text.close() # 关闭,很重要,确保不要过多的链接
                        
                        logger.info('使用requests的方式请求,重复爬取阶段 保存成功 ,现在是第{}次循环,第{}张图片name-url:{}-{}'.format(num+1,idx+1,img_name,url))
                        # 保存成功的图片将成功的idx保存,确保下一次循环不会重新使用已成功的url
                        sucess_idx.append(idx)
                        
                        fail_num = 0 # 将该数字归 0 
                    except Exception as e:
                        logger.error(e)
                        logger.error('使用requests的方式请求,重复爬取请求失败:{}'.format(url))
                        
                        # 判断连续失败的个数超过一定个数以后(本次设为6),终止重复爬取阶段,
                        fail_num += 1
                        if fail_num >= 6:
                            break
                        
                    time.sleep(0.5)
                
    def repeat_spider_screen(self,urls,repeat_num):
        """
            用于重复请求高清图片 去 截图图片 
            urls: 请求失败的 图片链接及其图片名称组成的二元组的列表
            repeat_num: 重复循环最多 repeat_nume 次,裆列表为零时终止循环
        """
        urls_num = len(urls)
        logger.info('\n存在{}个链接请求失败,正在重新请求爬取,使用浏览器截屏的方式来代替requests:\n'.format(urls_num))
        
        head = self.head
        browser = self.create_browser(head)
        browser.implicitly_wait(5)
        
        sucess_idx = []  # 保存成功的url 的索引列表
        for num in range(repeat_num):
            urls_num = len(urls)
            if urls_num == 0:
                break
        
            fail_num = 0 # 判断连续失败的个数超过一定个数以后(本次设为6),终止重复爬取阶段,
            for idx,url_info in enumerate(urls):
            
                if idx not in sucess_idx:
                    
                    url = url_info[0]
                    img_name = url_info[1]
                    
                    try:
                        browser.get(url)
                        ele = browser.find_element_by_xpath('//img')
                        self.screen_img(ele = ele,img_files_path = img_name)
                        
                        logger.info('使用浏览器截屏的方式,重复爬取阶段 保存成功 ,现在是第{}次循环,第{}张图片name-url:{}-{}'.format(num+1,idx+1,img_name,url))
                        
                        # 保存成功的图片将成功的idx保存,确保下一次循环不会重新使用已成功的url
                        sucess_idx.append(idx)
                        
                        fail_num = 0 # 将该数字归 0 
                    except Exception as e:
                        logger.error(e)
                        logger.error('使用浏览器截屏的方式,重复爬取请求失败:{}'.format(url))
                        
                        # 判断连续失败的个数超过一定个数以后(本次设为6),终止重复爬取阶段,
                        fail_num += 1
                        if fail_num >= 6:
                            break
                            
                    time.sleep(0.5)

if __name__ == '__main__':

    # argparse 回调函数
    def str2bool(v):
        if isinstance(v, bool):
            return v
        if v.lower() in ('yes', 'true', 't', 'y', '1'):
            return True
        elif v.lower() in ('no', 'false', 'f', 'n', '0'):
            return False
        else:
            raise argparse.ArgumentTypeError('Boolean value expected.')
 
    # TODO 参数
    # 创建对象
    parser = argparse.ArgumentParser()

    # 添加参数
    parser.add_argument('urls', help='main_page url',type=str,nargs='+')                # url 地址,可以给多个
    parser.add_argument('--keywords', help='keywords',nargs='+',type=str)                          # 关键字
    parser.add_argument('--repeat_num', help='repeat spider num',type=int,default=1)  # 高清图片url请求失败 重复获取的次数
    parser.add_argument('--max_imgNums', help='each url max imgs num',nargs='+',type=int,default=400)     # 保存图片的最大数量
    parser.add_argument('--head', help='headless YES or NO',type=str2bool,default=True) # 是否开启无头浏览器

    # 使用parse_args解析参数
    args = parser.parse_args()
    urls = args.urls
    keywords = args.keywords
    repeat_num = args.repeat_num
    max_imgNums = args.max_imgNums
    head = args.head

    target_dir = r'C:\Users\liukang17\Desktop'
    time_sleep = 3 # 网速好的时间可以下调,加载高清最长等待时间
    logger.info("\n\n urls:{}-head:{}-keywords:{}-target_dir:{}-repeat_num:{}-max_imgNums:{} \n\n".format(urls,head,keywords,target_dir,repeat_num,max_imgNums))
    logger.error("\n\n urls:{}-head:{}-keywords:{}-target_dir:{}-repeat_num:{}-max_imgNums:{} \n\n".format(urls,head,keywords,target_dir,repeat_num,max_imgNums))

    
    tmp1_num = len(max_imgNums)
    tmp2_num = len(keywords)
    for idx,url in enumerate(urls):
        url = url.strip()
        
        # 判断 max_imgNums 与 keywords 列表索引是否越界
        if idx >= tmp1_num:
            max_imgNum = max_imgNums[-1]
        else:
            max_imgNum = max_imgNums[idx]
        if idx >= tmp2_num:
            keyword = keywords[-1]
        else:
            keyword = keywords[idx]
        
        # TODO 运行
        spider_obj = GoogleSpider(url,keyword,time_sleep,target_dir,repeat_num,max_imgNum)

        # 创建一个浏览器
        browser = spider_obj.create_browser(head=head)

        # 下载图片
        spider_obj.get_main_page_info(browser=browser)
执行脚本:
cd C:\Users\****\Desktop\LanJunTools
python google_image_main.py "https://www.google.com.tw/search?q=风景&source=lnms&tbm=isch&sa=X&ved=2ahUKEwijoaW6o7bsAhUEIIgKHUQPBeAQ_AUoAXoECBcQAw&biw=1366&bih=625" "https://www.google.com.tw/search?q=壁纸&tbm=isch&ved=2ahUKEwiRwNG7o7bsAhXENKYKHaUzBCcQ2-cCegQIABAA&oq=%E5%A3%81%E7%BA%B8&gs_lcp=CgNpbWcQAzICCAAyAggAMgIIADICCAAyBAgAEB4yBAgAEB4yBAgAEB4yBAgAEB4yBAgAEB4yBAgAEB46BAgAEAQ6BggAEAUQHlCqd1iGogFg16MBaABwAHgAgAGoA4gBiAqSAQkwLjMuMi4wLjGYAQCgAQGqAQtnd3Mtd2l6LWltZ7ABAMABAQ&sclient=img&ei=VBWIX5HGDcTpmAWl55C4Ag&bih=625&biw=1366" --max_imgNums 900 200 --head 0 --keywords 风景 壁纸

 

二、利用 selenium 自动上传文件(图片/文本)

  1、利用 .send_keys( file_path ) 的方式上传 图片

        selenium处理文件或图片上传弹窗的三种方式(input框,robot类,autoIT3工具)

selenium 对文本框的输入操作一般有两种形式,传统的是直接通过定位元素通过sendKeys()方法直接在文本框中输入信息。
但有时候我们可以通过xpath的方式将其进行定位,但却不能通过sendKeys()向文本框中输入文本信息。
这种情况下,也需要借助JavaScript 代码完成输入。

       HTML 文本域 

<textarea id="id" style="width: 98%" cols="50" rows="5" class="txtarea">
</textarea>
...
...

        第一种:

driver.find_element_by_id('id').sendKeys("需要输入的内容");

       第二种:

text = '文本域上传的内容'
js = "var kw = document.getElementById('kw') ;kw.value='{}';".format(text)
driver.execute_script(js)

三、自动上传大众点评头像、评论

Directory_Hanlder 自定义库代码地址:
失败,已放弃
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
from selenium import webdriver
from utils.utils import Directory_Hanlder
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import ElementNotInteractableException
import os    #
import numpy as np
import pandas as pd
import time
import argparse
 
class DumpMassage():
    def __init__(self,choice,head_img_dir = None, comments_signs_file = None):
        # 选择哪种方式执行 'img' 上传头像 'text' 上传文本 'all' 同时上传
        assert choice in ['img','text','all']
        self.choice = choice
 
        # 登录浏览器的参数
        self.log_in_url = "https://account.dianping.com/login?"  # 登录点评网页的链接地址
        self.log_in_sleep = 15  # 登录页面扫码等待时间
        self.main_page = 'https://www.dianping.com/'
 
        # 上传头像图片的参数
        self.head_img_url = 'http://www.dianping.com/member/myinfo/setup/userface'  # 头像上传的链接地址
        self.head_img_sleep = 2.5  # 上传图片等待时间提交,最小为 time_sleep,最大为 time_sleep + 1.5 的随机数
        self.head_img_dir = head_img_dir # 上传头像图片的目录路径
 
        # 评论与签名相关参数
        self.comments_signs_file = comments_signs_file # 上传文本数据的文件路径
 
        # 浏览器对象参数
        self.head = True
        self.implicitly_wait = 15
 
            # 浏览器初始化
        self.browser = self.create_browser(head=self.head)
        self.browser.implicitly_wait(self.implicitly_wait)
        self.browser = self.log_in_dianping(self.browser,self.log_in_url,time_sleep=self.log_in_sleep)
            # 浏览器打开主页面 且 再打开一个窗口
        # self.browser.get(self.main_page)
        # self.browser.find_element_by_xpath("//a[@class= 'item left-split username J-user-trigger']").send_keys(Keys.ENTER)

        self.browser.get(self.head_img_url)   # 此时,浏览器其实已经有了两个窗口了{ 目前位于第一个窗口,即主窗口 },第一个窗口用来上传头像,第二个窗口用来上传文本数据
        self.windows = self.browser.window_handles
 
    def create_browser(self,head):
        """
        创建一个浏览器的对象
        :param headless: 是否使用无头浏览器
        :return:
        """
        self.head = head
 
        options = webdriver.ChromeOptions()

        # 增加无头
        if not self.head:
            options.add_argument('--headless')
            # 无头浏览器设置窗口大小,主要是为了解决截屏时,如果窗口比较小,截屏时会获得较小的图片
            options.add_argument("--window-size=4000,1600")
 
        options.add_argument('--disable-gpu')

        # 关闭自动测试状态显示 // 会导致浏览器报:请停用开发者模式
        # window.navigator.webdriver还是返回True,当返回undefined时应该才可行。
        options.add_experimental_option("excludeSwitches", ['enable-automation'])
        # 关闭开发者模式
        options.add_experimental_option("useAutomationExtension", False)
        # 设置中文
        options.add_argument('lang=zh_CN.UTF-8')
        # 更换头部
        options.add_argument(
            'user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"')
        # 部署项目在linux时,其驱动会要求这个参数
        options.add_argument('--no-sandbox')

        browser = webdriver.Chrome(options=options)
        if self.head:
            browser.maximize_window()

        # 设置执行js代码转换模式,反反爬虫检测 window.navigator.webdriver 属性换为 undefined
        browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
        })
        return browser
 
    def log_in_dianping(self,browser,url,time_sleep = 15):
        """
        浏览器登录点评
        :param browser:
        :param url: 登录点评的链接
        :param time_sleep: 登录扫码等待的时间
        :return:
        """
        # 浏览器登录
        browser.get(url)  # 获取路径

        time.sleep(0.3)
        browser.switch_to.frame((browser.find_element_by_xpath('//iframe')))
        browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
        })
        browser.find_element_by_xpath('//span[@class="bottom-password-login"]').click()
        time.sleep(0.3)
        browser.find_element_by_id('tab-account').click()

        # 登录
        browser.find_element_by_id('account-textbox').clear()
        browser.find_element_by_id('account-textbox').send_keys('***********')
        time.sleep(2)
        browser.find_element_by_id('password-textbox').clear()
        browser.find_element_by_id('password-textbox').send_keys('***********')  # password
        time.sleep(1)
        browser.find_element_by_id('login-button-account').click()

        # 登录等待
        time.sleep(3)

        return browser
 
    def load_head_img_paths(self,img_dir):
        """
        给定头像图片目录路径,加载所有图片的路径
        :param img_dir:
        :return:
        """
        assert img_dir is not None
        img_paths,_ = Directory_Hanlder.list_dir_all_files(img_dir)
        img_nums = len(img_paths)
 
        self.img_paths = img_paths
        self.img_nums = img_nums
        return img_paths,img_nums
 
    def load_comments_sign(self,comments_path):
        """
        加载文件【①去除空行数据 ②去除首尾空格】至Series中,保存每段文本所对应的行号
        :param comments_path: 文件的路径
        :return: Series
        """
        assert comments_path is not None

        # 将数据保存至 Series 中
        comments_ser = pd.Series()
        try:
            with open(comments_path,'r',encoding='utf-8-sig') as w:
                for row,line in enumerate(w.readlines()):
                    # 对每一行的数据前后去除空格
                    line = line.strip()
                    # 判断去除空格后的数据是否有内容,只要有数据的内容【去除空行数据】
                    if line:

                        # 添加行号
                        row_index = row + 1
                        comments_ser.loc[row_index] = line

        except Exception as e:
            with open(comments_path, 'r', encoding='gbk') as w:
                for row, line in enumerate(w.readlines()):
                    # 对每一行的数据前后去除空格
                    line = line.strip()
                    # 判断去除空格后的数据是否有内容,只要有数据的内容【去除空行数据】
                    if line:

                        # 添加行号
                        row_index = row + 1
                        comments_ser.loc[row_index] = line

        return comments_ser,len(comments_ser)

    def dump_head_img(self,url,browser,img_path,time_sleep=1.5):
        """
        上传头像图片的函数,给定 一张头像图片地址进行上传,
        :param url:
        :param time_sleep: 上传图片等待时间提交, 最小为 time_sleep
        :return:
        """
        try:
            browser.find_element_by_xpath("//input[@capture='camera']").send_keys(img_path)
        except:
            # 当找不到元素的时候,重新请求一下页面
            browser.get(url)
            # 获取上传头像 ele 元素
            browser.find_element_by_xpath("//input[@capture='camera']").send_keys(img_path)
 
        # 上传图片等待时间提交,最小为 time_sleep
        tmp1_num = np.random.uniform(time_sleep, time_sleep + 1.5)
        time.sleep(tmp1_num)
 
        # 点击提交 ---- 使用 js 大法
        flag = True
        try:
            js = 'document.getElementById("J_usave").click();'
            browser.execute_script(js)
            # 判断url并非最初的美团图片,才进行打印
            dump_url = browser.find_element_by_xpath("//img[@id='J_bface']").get_attribute('src')

            if not dump_url.startswith('https://p0.meituan.net/userheadpic/chicken.png%40120w'):
                print('随机数等待上传图片时间为: {:.1f} , 上传的图片url为:{}'.format(tmp1_num,dump_url))

            if len(self.browser.find_elements_by_class_name('medi-btn-ashdisb')) == 0:
                print('找不到button的类属性 medi-btn-ashdisb ,判断图片点击失败')
                flag = False

        except Exception as e:
            flag = False
            print('\nERROR: \n',e)
            print('当前图片点击事件触发失败,上传失败,已跳过\n')

        # 上传后等待 1.6  -  2.5 s
        time.sleep(np.random.uniform(1.6,2.5))
        time.sleep(100)
        return browser,flag

    def dump_text(self,line,browser):
        """
        上传文本
        :return:
        """
        url = "http://www.dianping.com/member/myinfo/setup/basic"
        browser.get(url)

        # TODO 给文本域上传文本
        js = "var kw = document.getElementById('J_sign') ;kw.value='{}';".format(line)
        browser.execute_script(js)

        time.sleep(1)
        # js = 'document.getElementsByClassName("btn-txt J_submit")[0].click();'
        browser.execute_script(js)
        return browser

    def run_img(self,browser):
        """
        仅仅自动上传头像
        :param browser: 浏览器对象
        :return:
        """
        self.browser = browser
 
        # 获取 给定的头像目录路径 所有图片的路径
        img_paths,img_num = self.load_head_img_paths(self.head_img_dir)
        print('一共有 {} 张头像需要上传, 现在正在上传中....'.format(img_num))
 
        # 浏览器请求头像页面链接
        self.browser.get(self.head_img_url)
        for idx,head_img in enumerate(img_paths):
 
            # 每 10 张 图片重新请求下头像上传页面,防止假死状态
            if (idx+1) % 10 == 0:
                self.browser.get(self.head_img_url)
                time.sleep(np.random.uniform(0.8,1.4))
 
            # 防止后台检测,每上传25 张图片, 睡眠 60s 的时间
            if (idx + 1) % 25 == 0:
                for i in range(60):
                    time.sleep(1)
                    print('\r等待 60s 继续上传头像,现在是第{}s '.format(i+1),end='',flush=True)
                print()
 
                # 重新请求头像上传的网址
                self.browser.get(self.head_img_url)
                time.sleep(np.random.uniform(0.8, 1.4))
 
            # 上传头像
            self.browser,flag = self.dump_head_img(self.head_img_url,self.browser,head_img,time_sleep=self.head_img_sleep)
            if not flag:
                continue
            elif flag:
                print('第 {} 张头像图片-{} 上传成功!'.format(idx+1,head_img))

        print('头像 {} 张图片已全部上传完毕!'.format(img_num))
        return self.browser
 
    def run_comments(self):
        """"""
        # 更换第二个窗口
        self.browser.switch_to.window(self.windows[-1])
        # 执行 js 更换 window.navigator.webdriver 属性
        self.browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
            "source": """Object.defineProperty(navigator, 'webdriver', {get: () => undefined})""",
        })
        # 获取需要所有的文本数据
        comments,num = self.load_comments_sign(self.comments_signs_file)
        print(comments,num)

        for idx,line in enumerate(comments):

            # 上传文本数据
            self.browser = self.dump_text(line,self.browser)
            print('共 {} 条文本,第 {} 条内容:  {} '.format(num,idx+1,line))
            time.sleep(2)
        return self.browser

    def run_all(self):
        pass
 
    def run(self):
        """
        主函数,运行
        :return:
        """
        if self.choice is 'img':
            self.run_img(self.browser)
 
        elif self.choice is 'text':
            self.run_comments()
        elif self.choice is 'all':
            self.run_all()
        else:
            raise Exception("choice 参数输入有误! 从 ['img','text','all'] 选择一个 ")
 
if __name__ == '__main__':
 
    head_img_dir = r'C:\Users\Hasee\Desktop\touxiang'
    comments_sign = r'C:\Users\Hasee\Desktop\作文.txt'

    choice = 'text'
 
    obj = DumpMassage(choice = choice,head_img_dir = head_img_dir,comments_signs_file=comments_sign)
    browser = obj.run()

    #退出浏览器
    browser.quit()