selenium从本地上传文件到网页

背景:
如下图,在用selenium 自动写博客的时候,需要上传本地图片到网页,问题产生了,selenium 可以控制网页,但是无法控制文件资源浏览器,怎么实现呢?

selenium从本地上传文件到网页_第1张图片

主要依赖库

  • pyperclip:复制文本到剪切板
  • pyautogui:鼠标键盘操控
  • win32con/win32gui : window底层库
import pyautogui
import pyperclip
import win32con
import win32gui

上传单个文件

    def main(self):
       '''
       前面不相关代码就屏蔽掉了
		'''
        #CSDN 文章编辑界面的上传图片按钮处理
        add_photo = self.driver.find_element(By.XPATH, ".//div//button[@data-title='图片 – Ctrl+Shift+G']")
        add_photo.click()
        time.sleep(1)
        choose_photo = self.driver.find_element(By.XPATH, ".//div[@class='uploadPicture']/input")
        # 因为按钮不是button空间,所以不能直接用click(),要借助ActionChains
        action = ActionChains(self.driver)
        action.move_to_element(choose_photo).click().perform()
        action.release()
        
        time.sleep(1)  # 等待一秒
        file = r"D:\Document\scrapy\image_all\out_image_used\长信怨\3-1404231F932_长信怨_赏析_6.JPEG"
        self.upload_file(file)


    def upload_file(self, file_path):
        try:
            pyperclip.copy(file_path)  # 把指定的路径拷贝到焦点
            pyautogui.hotkey('ctrl', 'v')
            time.sleep(1)  # 等待一秒
            pyautogui.press('enter') #进入到目标文件夹
        except:
            print(traceback.print_exc())

上传任意个指定文件(有限制,文件名总字节无法大于260)

  • 比如 ,如果我想上传 文件夹下的所有文件 self.upload_files(file_dir,os.listdir(file_dir)),那么如果这个文件夹下的所有文件名称的总字节超过260,那么就无不行了
  • 我这里做了个简单处理,就是只上传第一个文件,因为selenium 正处于打开文件界面,我希望selenium关闭文件选择对话框,正常走下去
  • 文件名最长可达多少个字符?
    def main(self):
       '''
       前面不相关代码就屏蔽掉了
		'''
        #CSDN 文章编辑界面的上传图片按钮处理
        add_photo = self.driver.find_element(By.XPATH, ".//div//button[@data-title='图片 – Ctrl+Shift+G']")
        add_photo.click()
        time.sleep(1)
        choose_photo = self.driver.find_element(By.XPATH, ".//div[@class='uploadPicture']/input")
        # 因为按钮不是button空间,所以不能直接用click(),要借助ActionChains
        action = ActionChains(self.driver)
        action.move_to_element(choose_photo).click().perform()
        action.release()
        
        time.sleep(1)  # 等待一秒
        file_dir = r"D:\Document\scrapy\image_all\out_image_used\长信怨" #这是文件夹
        self.upload_files(file_dir,["3-1404231F932_长信怨_赏析_6.JPEG","3-14041Q62234_长信怨_赏析_4.JPEG"])
        # self.upload_files(file_dir,os.listdir(file_dir))


    def upload_files(self, file_dir, file_list):
        '''        
        :param file_dir: 待上传的文件夹路径
        :param file_list: 待上传的文件列表(在 file_dir路径下)
        有个硬伤:输入的文件列表转换字符串之后总字节无法超过260
        :return:
        '''

        file_upload = ' '.join('"{0}"'.format(x) for x in file_list)
        if len(file_upload) >= 260:
            print("输入文件列表总字节{}大于260,无法上传!".format(len(file_upload)))
            file_upload = os.path.join(file_dir, file_list[0])
        try:
            pyperclip.copy(file_dir)  # 把指定的路径拷贝到焦点
            pyautogui.hotkey('ctrl', 'v')
            time.sleep(1)  # 等待一秒
            pyautogui.press('enter')  # 进入到目标文件夹
            '''将文件列表转为字符串 ,上传文件'''
            pyperclip.copy(file_upload)  # 把指定的路径拷贝到焦点
            pyautogui.hotkey('ctrl', 'v')
            time.sleep(1)  # 等待一秒
            pyautogui.press('enter') #进入到目标文件夹
        except:
            print(traceback.print_exc())

上传全部文件(需要win32gui库)

  • 上传指定文件夹下的所有文件
  • 这里用到了win32gui这个库,目的是根据文件对话框的名称找到这个对话框,并且获取到这个对话框的位置,然后pyautogui库模拟鼠标移动到对话框的文件中,再模拟Ctrl+A全选,
  • 但是这里又有个弊端,无法过滤不想传的文件,真是头疼
    def main(self):
       '''
       前面不相关代码就屏蔽掉了
		'''
        #CSDN 文章编辑界面的上传图片按钮处理
        add_photo = self.driver.find_element(By.XPATH, ".//div//button[@data-title='图片 – Ctrl+Shift+G']")
        add_photo.click()
        time.sleep(1)
        choose_photo = self.driver.find_element(By.XPATH, ".//div[@class='uploadPicture']/input")
        # 因为按钮不是button空间,所以不能直接用click(),要借助ActionChains
        action = ActionChains(self.driver)
        action.move_to_element(choose_photo).click().perform()
        action.release()
        
        time.sleep(1)  # 等待一秒
        file_dir = r"D:\Document\scrapy\image_all\out_image_used\长信怨" #这是文件夹
        self.upload_file_all(file_dir)


    def upload_file_all(self, dir):
        try:
            pyperclip.copy(dir) # 把指定的路径拷贝到焦点
            pyautogui.hotkey('ctrl', 'v')
            time.sleep(1)  # 等待一秒
            pyautogui.press('enter') # 进入到目标文件夹
            '''根据文件资源管理器的名字定位'''
            handle = win32gui.FindWindow("#32770", "打开")
            '''文件资源管理器的位置'''
            left, top, right, bottom = win32gui.GetWindowRect(handle)
            '''将鼠标移动到文件资源管理器内部'''
            pyautogui.moveTo(left+(right-left)/2, top+(bottom-top)/2, duration=0.25)
            pyautogui.click()
            pyautogui.hotkey('ctrl', 'a')#全选
            button = win32gui.FindWindowEx(handle, 0, 'Button', "打开(&O)")
            win32gui.SendMessage(handle, win32con.WM_COMMAND, 1, button)  # 点击打开按钮
        except:
            print(traceback.print_exc())

参考资料:
win32gui
Python win32gui 模块,FindWindowEx() 实例源码
详解Python中pyautogui库的最全使用方法

你可能感兴趣的:(python,selenium,测试工具)